diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-12-26 20:09:17 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-12-26 20:09:17 -0700 |
commit | e7e0cff1960fca598e0ba01be2bb56b65cbb9e2b (patch) | |
tree | 1e2c607ae9980b47917effe4203b4448a1dd4c5f | |
parent | d0e9e9c4a178fe396f3ba255bc440a15b107a097 (diff) | |
parent | 1aecc70750ee6ce9c96ebf3e6b4a7fb322ff8ca3 (diff) |
Merge branch 'lukeshu/check-build'
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | GNUmakefile | 17 | ||||
-rwxr-xr-x | build-aux/stack.c.gen | 12 | ||||
-rw-r--r-- | libcr/coroutine.c | 38 | ||||
-rw-r--r-- | libcr/tests/test_matrix/config.h | 2 | ||||
-rw-r--r-- | libmisc/CMakeLists.txt | 2 | ||||
-rw-r--r-- | libmisc/assert.c | 4 | ||||
-rw-r--r-- | libmisc/include/libmisc/_intercept.h | 21 | ||||
-rw-r--r-- | libmisc/include/libmisc/assert.h | 2 | ||||
-rw-r--r-- | libmisc/include/libmisc/log.h | 9 | ||||
-rw-r--r-- | libmisc/intercept.c | 25 | ||||
-rw-r--r-- | libmisc/log.c | 10 | ||||
-rw-r--r-- | libmisc/tests/test_assert.c | 20 | ||||
-rw-r--r-- | libmisc/tests/test_assert_min.c | 17 | ||||
-rw-r--r-- | libmisc/tests/test_log.c | 49 | ||||
-rw-r--r-- | libmisc/tests/test_rand.c | 25 |
16 files changed, 172 insertions, 88 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e7b4682..e4f4d91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,13 @@ pico_sdk_init() add_compile_options(-Wall -Wextra -Wswitch-enum -Werror) +string(TOUPPER "${CMAKE_BUILD_TYPE}" _upper_cmake_build_type) +string(REPLACE " " ";" _build_type_flags "${CMAKE_C_FLAGS_${_upper_cmake_build_type}}") +if ("-DNDEBUG" IN_LIST _build_type_flags) + add_compile_options(-Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable) + target_compile_definitions(pico_printf INTERFACE PICO_PRINTF_ALWAYS_INCLUDED=1) +endif() + function(_suppress_tinyusb_warnings) __suppress_tinyusb_warnings() set_source_files_properties( diff --git a/GNUmakefile b/GNUmakefile index 9f5ad61..098f076 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -61,24 +61,25 @@ generate-clean: # `build` and `check` ########################################################## platforms := $(shell sed -nE 's/if *\(PICO_PLATFORM STREQUAL "(.*)"\)/\1/p' cmd/*/CMakeLists.txt) +build_types = Debug Release RelWithDebInfo MinSizeRel -build: $(foreach p,$(platforms),build/$p/build) +build: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)) .PHONY: build -$(foreach p,$(platforms),build/$p/Makefile): build/%/Makefile: - mkdir -p $(@D) && cd $(@D) && cmake -DCMAKE_BUILD_TYPE=Debug -DPICO_PLATFORM=$* ../.. +$(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/Makefile)): build/%/Makefile: + mkdir -p $(@D) && cd $(@D) && cmake -DPICO_PLATFORM=$(firstword $(subst -, ,$*)) -DCMAKE_BUILD_TYPE=$(lastword $(subst -, ,$*)) ../.. -$(foreach p,$(platforms),build/$p/build): build/%/build: build/%/Makefile generate +$(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)): build/%/build: build/%/Makefile generate $(MAKE) -C $(<D) -.PHONY: $(foreach p,$(platforms),build/$p/build) +.PHONY: $(foreach t,$(build_types),$(foreach p,$(platforms),build/$p-$t/build)) check: build - $(MAKE) -j1 -k $(foreach p,$(platforms),build/$p/check) + $(MAKE) -j1 -k $(foreach t,$(build-types),$(foreach p,$(platforms),build/$p-$t/check)) .PHONY: check -$(foreach p,$(platforms),build/$p/check): build/%/check: build/%/Makefile +$(foreach t,$(build-types),$(foreach p,$(platforms),build/$p-$t/check)): build/%/check: build/%/Makefile CTEST_OUTPUT_ON_FAILURE=1 $(MAKE) -C $(<D) test -.PHONY: $(foreach p,$(platforms),build/$p/check) +.PHONY: $(foreach t,$(build-types),$(foreach p,$(platforms),build/$p-$t/check)) # `lint` and `format` ########################################################## diff --git a/build-aux/stack.c.gen b/build-aux/stack.c.gen index 92bd8c2..61d7bce 100755 --- a/build-aux/stack.c.gen +++ b/build-aux/stack.c.gen @@ -456,17 +456,15 @@ def main( def sbc_skip_call(chain: list[str], call: str) -> bool: if ( len(chain) > 1 - and chain[-1].endswith(":__assert_msg_fail") - and call == "_log_printf" - and any(c.endswith(":__assert_msg_fail") for c in chain[:-1]) + and chain[-1] == "__assert_msg_fail" + and call.endswith(":__lm_printf") + and "__assert_msg_fail" in chain[:-1] ): return True if ( len(chain) >= sbc_9p_max_depth - and call.endswith("/srv.c:util_release") - and all( - c.endswith("/srv.c:util_release") for c in chain[-sbc_9p_max_depth:] - ) + and "/srv.c:util_release" in call + and all(("/srv.c:util_release" in c) for c in chain[-sbc_9p_max_depth:]) ): return True return False diff --git a/libcr/coroutine.c b/libcr/coroutine.c index 7278225..129f4da 100644 --- a/libcr/coroutine.c +++ b/libcr/coroutine.c @@ -46,6 +46,10 @@ #error config.h must define CONFIG_COROUTINE_GDB (bool) #endif +/* Enforce that CONFIG_COROUTINE_NUM is greater than 1, to work around + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118212 */ +static_assert(CONFIG_COROUTINE_NUM > 1); + /* Implementation *************************************************************/ #if CONFIG_COROUTINE_VALGRIND @@ -386,7 +390,7 @@ struct coroutine { #if CONFIG_COROUTINE_VALGRIND unsigned stack_id; #endif - char name[CONFIG_COROUTINE_NAME_LEN]; + [[gnu::nonstring]] char name[CONFIG_COROUTINE_NAME_LEN]; }; /* constants ******************************************************************/ @@ -522,10 +526,24 @@ static inline void assert_cid(cid_t cid) { /* coroutine_add() ************************************************************/ +LM_NEVER_INLINE +cid_t coroutine_allocate_cid(void) { + static cid_t last_created = 0; + + size_t base = last_created; + for (size_t shift = 0; shift < CONFIG_COROUTINE_NUM; shift++) { + cid_t child = ((base + shift) % CONFIG_COROUTINE_NUM) + 1; + if (coroutine_table[child-1].state == CR_NONE) { + last_created = child; + return child; + } + } + return 0; +} + cid_t coroutine_add_with_stack_size(size_t stack_size, const char *name, cr_fn_t fn, void *args) { - static cid_t last_created = 0; cid_t parent = coroutine_running; if (parent) @@ -540,21 +558,11 @@ cid_t coroutine_add_with_stack_size(size_t stack_size, coroutine_initialized = true; } - cid_t child; - { - size_t base = last_created; - for (size_t shift = 0; shift < CONFIG_COROUTINE_NUM; shift++) { - child = ((base + shift) % CONFIG_COROUTINE_NUM) + 1; - if (coroutine_table[child-1].state == CR_NONE) - goto found; - } + cid_t child = coroutine_allocate_cid(); + if (!child) return 0; - found: - } debugf("...child=%zu", child); - last_created = child; - if (name) strncpy(coroutine_table[child-1].name, name, sizeof(coroutine_table[child-1].name)); else @@ -753,6 +761,7 @@ cid_t cr_getcid(void) { return coroutine_running; } +#ifndef NDEBUG void cr_assert_in_coroutine(void) { assert(!cr_plat_is_in_intrhandler()); assert_cid_state(coroutine_running, state == CR_RUNNING); @@ -761,6 +770,7 @@ void cr_assert_in_coroutine(void) { void cr_assert_in_intrhandler(void) { assert(cr_plat_is_in_intrhandler()); } +#endif /* cr_cid_info() **************************************************************/ diff --git a/libcr/tests/test_matrix/config.h b/libcr/tests/test_matrix/config.h index 9802f08..becfce0 100644 --- a/libcr/tests/test_matrix/config.h +++ b/libcr/tests/test_matrix/config.h @@ -9,6 +9,6 @@ #define CONFIG_COROUTINE_DEFAULT_STACK_SIZE (4*1024) #define CONFIG_COROUTINE_NAME_LEN 16 -#define CONFIG_COROUTINE_NUM 1 +#define CONFIG_COROUTINE_NUM 2 #endif /* _CONFIG_H_ */ diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt index 83e91fe..8d842c3 100644 --- a/libmisc/CMakeLists.txt +++ b/libmisc/CMakeLists.txt @@ -7,11 +7,13 @@ add_library(libmisc INTERFACE) target_include_directories(libmisc SYSTEM INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) target_sources(libmisc INTERFACE assert.c + intercept.c log.c ) target_compile_options(libmisc INTERFACE "$<$<COMPILE_LANGUAGE:C>:-fplan9-extensions>") add_lib_test(libmisc test_assert) +add_lib_test(libmisc test_assert_min) add_lib_test(libmisc test_endian) add_lib_test(libmisc test_hash) add_lib_test(libmisc test_log) diff --git a/libmisc/assert.c b/libmisc/assert.c index 8231c85..69c0530 100644 --- a/libmisc/assert.c +++ b/libmisc/assert.c @@ -5,7 +5,6 @@ */ #include <stdbool.h> /* for bool, true, false */ -#include <stdlib.h> /* for abort() */ #define LOG_NAME ASSERT #include <libmisc/log.h> /* for errorf() */ @@ -13,7 +12,6 @@ #include <libmisc/assert.h> #ifndef NDEBUG -[[noreturn, gnu::weak]] void __assert_msg_fail(const char *expr, const char *file, unsigned int line, const char *func, const char *msg) { @@ -26,6 +24,6 @@ void __assert_msg_fail(const char *expr, msg ? ": " : "", msg ?: ""); in_fail = false; } - abort(); + __lm_abort(); } #endif diff --git a/libmisc/include/libmisc/_intercept.h b/libmisc/include/libmisc/_intercept.h new file mode 100644 index 0000000..47e4620 --- /dev/null +++ b/libmisc/include/libmisc/_intercept.h @@ -0,0 +1,21 @@ +/* libmisc/_intercept.h - Interceptable ("weak") functions + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#ifndef _LIBMISC__INTERCEPT_H_ +#define _LIBMISC__INTERCEPT_H_ + +/* pico-sdk/newlib define these to be [[gnu:weak]] already, but + * depending on optimization options glibc might not, and GCC might + * assume it knows what they do and optimize them out. So define our + * own `__lm_` wrappers that GCC/glibc won't interfere with. + */ + +[[format(printf, 1, 2)]] +int __lm_printf(const char *format, ...); + +[[noreturn]] void __lm_abort(void); + +#endif /* _LIBMISC__INTERCEPT_H_ */ diff --git a/libmisc/include/libmisc/assert.h b/libmisc/include/libmisc/assert.h index da2ba2b..8cf0735 100644 --- a/libmisc/include/libmisc/assert.h +++ b/libmisc/include/libmisc/assert.h @@ -17,7 +17,7 @@ #endif #define assert_msg(expr, msg) __assert_msg(expr, #expr, msg) /* libmisc */ -#define assert(expr) __assert_msg(expr, #expr, NULL) /* C89, POSIX-2001 */ +#define assert(expr) __assert_msg(expr, #expr, 0) /* C89, POSIX-2001 */ #define assert_notreached(msg) do { __assert_msg(0, "notreached", msg); __builtin_unreachable(); } while (0) /* libmisc */ #define static_assert _Static_assert /* C11 */ diff --git a/libmisc/include/libmisc/log.h b/libmisc/include/libmisc/log.h index 8c6d6be..121b0e1 100644 --- a/libmisc/include/libmisc/log.h +++ b/libmisc/include/libmisc/log.h @@ -10,6 +10,7 @@ #include <stdint.h> /* for uint8_t */ #include <libmisc/macro.h> +#include <libmisc/_intercept.h> #ifndef LOG_NAME #error "each compilation unit that includes <libmisc/log.h> must define LOG_NAME" @@ -21,12 +22,10 @@ #define _LOG_NDEBUG 0 #endif -[[format(printf, 1, 2)]] int _log_printf(const char *format, ...); - -#define n_errorf(nam, fmt, ...) do { _log_printf("error: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0) -#define n_infof(nam, fmt, ...) do { _log_printf("info : " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0) +#define n_errorf(nam, fmt, ...) do { __lm_printf("error: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0) +#define n_infof(nam, fmt, ...) do { __lm_printf("info : " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0) #define n_debugf(nam, fmt, ...) do { if (LM_CAT3_(CONFIG_, nam, _DEBUG) && !_LOG_NDEBUG) \ - _log_printf("debug: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0) + __lm_printf("debug: " LM_STR_(nam) ": " fmt "\n" __VA_OPT__(,) __VA_ARGS__); } while (0) #define errorf(fmt, ...) n_errorf(LOG_NAME, fmt, __VA_ARGS__) #define infof(fmt, ...) n_infof(LOG_NAME, fmt, __VA_ARGS__) diff --git a/libmisc/intercept.c b/libmisc/intercept.c new file mode 100644 index 0000000..dda8c09 --- /dev/null +++ b/libmisc/intercept.c @@ -0,0 +1,25 @@ +/* libmisc/intercept.c - Interceptable ("weak") functions + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <stdarg.h> /* for va_list, va_start(), va_end() */ +#include <stdio.h> /* for vprintf() */ +#include <stdlib.h> /* for abort() */ + +#include <libmisc/_intercept.h> + +[[gnu::weak]] +int __lm_printf(const char *format, ...) { + va_list va; + va_start(va, format); + int ret = vprintf(format, va); + va_end(va); + return ret; +} + +[[gnu::weak]] +void __lm_abort(void) { + abort(); +} diff --git a/libmisc/log.c b/libmisc/log.c index 9bf5366..ff4dac6 100644 --- a/libmisc/log.c +++ b/libmisc/log.c @@ -7,19 +7,11 @@ #include <stdio.h> /* for vprintf() */ #include <stdarg.h> /* for va_list, va_start(), va_end() */ -#include <libmisc/assert.h> +#include <libmisc/assert.h> /* for static_assert() */ #define LOG_NAME #include <libmisc/log.h> -int _log_printf(const char *format, ...) { - va_list va; - va_start(va, format); - int ret = vprintf(format, va); - va_end(va); - return ret; -} - static const char *byte_strs[] = { "0x00", "0x01", diff --git a/libmisc/tests/test_assert.c b/libmisc/tests/test_assert.c index 189f6de..3c2d6b6 100644 --- a/libmisc/tests/test_assert.c +++ b/libmisc/tests/test_assert.c @@ -5,12 +5,14 @@ */ #include <setjmp.h> +#include <stdarg.h> /* for va_list, va_start(), va_end() */ #include <stdbool.h> -#include <string.h> #include <stdlib.h> +#include <string.h> #include <libmisc/macro.h> #include <libmisc/assert.h> +#include <libmisc/_intercept.h> #include "test.h" @@ -28,17 +30,21 @@ jmp_buf global_env; setjmp(global_env) == 0; \ }) -[[noreturn]] void abort(void) { +void __lm_abort(void) { global_failed = true; longjmp(global_env, 1); } -#define __builtin_unreachable() test_assert(0) - -int vprintf(const char *format, va_list ap) { - return vasprintf(&global_log, format, ap); +int __lm_printf(const char *format, ...) { + va_list va; + va_start(va, format); + int ret = vasprintf(&global_log, format, va); + va_end(va); + return ret; } +#define __builtin_unreachable() test_assert(0) + /* Utilities ******************************************************************/ #define test_should_succeed(test) do { \ @@ -68,6 +74,7 @@ int vprintf(const char *format, va_list ap) { static_assert(sizeof(char) == 1); int main() { +#ifndef NDEBUG test_should_succeed(assert(true)); test_should_fail(assert(false), "error: ASSERT: "__FILE__":"LM_STR_(__LINE__)":main(): assertion \"false\" failed\n"); @@ -82,5 +89,6 @@ int main() { free(global_log); global_log = NULL; } +#endif return 0; } diff --git a/libmisc/tests/test_assert_min.c b/libmisc/tests/test_assert_min.c new file mode 100644 index 0000000..9c0394b --- /dev/null +++ b/libmisc/tests/test_assert_min.c @@ -0,0 +1,17 @@ +/* libmisc/tests/test_assert_min.c - Tests for minimal <libmisc/assert.h> + * + * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +/* Don't include *anything* else. */ +#include <libmisc/assert.h> + +static_assert(1 == 1); + +int main() { + assert_msg(1, "foo"); + assert(1); + return 0; + assert_notreached("ret"); +} diff --git a/libmisc/tests/test_log.c b/libmisc/tests/test_log.c index 286738d..49a76ca 100644 --- a/libmisc/tests/test_log.c +++ b/libmisc/tests/test_log.c @@ -13,36 +13,43 @@ #define LOG_NAME FROBNICATE #include <libmisc/log.h> +#include <libmisc/_intercept.h> + #include "test.h" /* Intercept output ***********************************************************/ static char *log_output = NULL; -int vprintf(const char *format, va_list ap) { - return vasprintf(&log_output, format, ap); +int __lm_printf(const char *format, ...) { + va_list va; + va_start(va, format); + int ret = vasprintf(&log_output, format, va); + va_end(va); + return ret; } /* Actual tests ***************************************************************/ -#define should_print(_exp, cmd) do { \ - char *exp = _exp; \ - test_assert(!log_output); \ - cmd; \ - if (!exp) \ - test_assert(!log_output); \ - else \ - if (!(log_output != NULL && \ - strcmp(log_output, exp) == 0)) { \ - printf("exp = \"%s\"\n" \ - "act = \"%s\"\n", \ - exp, log_output); \ - test_assert(0); \ - } \ - if (log_output) { \ - free(log_output); \ - log_output = NULL; \ - } \ +#define should_print(_exp, cmd) do { \ + char *exp = _exp; \ + test_assert(!log_output); \ + cmd; \ + if (!exp) \ + test_assert(!log_output); \ + else { \ + test_assert(log_output); \ + if (strcmp(log_output, exp)) { \ + printf("exp = \"%s\"\n" \ + "act = \"%s\"\n", \ + exp, log_output); \ + test_assert(0); \ + } \ + } \ + if (log_output) { \ + free(log_output); \ + log_output = NULL; \ + } \ } while (0) int main() { @@ -50,6 +57,7 @@ int main() { errorf("val=%d", 42)); should_print("info : FROBNICATE: val=0\n", infof("val=%d", 0)); +#ifndef NDEBUG #define CONFIG_FROBNICATE_DEBUG 1 should_print("debug: FROBNICATE: val=-2\n", debugf("val=%d", -2)); @@ -57,5 +65,6 @@ int main() { #define CONFIG_FROBNICATE_DEBUG 0 should_print(NULL, debugf("val=%d", -2)); +#endif return 0; } diff --git a/libmisc/tests/test_rand.c b/libmisc/tests/test_rand.c index fff1b27..8076155 100644 --- a/libmisc/tests/test_rand.c +++ b/libmisc/tests/test_rand.c @@ -8,26 +8,18 @@ #include <setjmp.h> #include <libmisc/rand.h> +#include <libmisc/_intercept.h> #include "test.h" /* Intercept failures *********************************************************/ +#ifndef NDEBUG jmp_buf *__catch; -void __assert_msg_fail(const char *expr, - const char *file, unsigned int line, const char *func, - const char *msg) { - static bool in_fail = false; +void __lm_abort(void) { if (__catch) longjmp(*__catch, 1); - if (!in_fail) { - in_fail = true; - printf("error: %s:%u:%s(): assertion \"%s\" failed%s%s\n", - file, line, func, - expr, - msg ? ": " : "", msg); - } abort(); } @@ -43,6 +35,7 @@ void __assert_msg_fail(const char *expr, __catch = old_catch; \ } \ } while (0); +#endif /* Actual tests ***************************************************************/ @@ -51,20 +44,24 @@ void __assert_msg_fail(const char *expr, static void test_n(uint64_t cnt) { if (cnt == 0 || cnt > UINT64_C(1)<<63) { +#ifndef NDEBUG should_abort(rand_uint63n(cnt)); +#else + return; +#endif } else { double sum = 0; bool seen[MAX_SEE_ALL] = {0}; for (int i = 0; i < ROUNDS; i++) { uint64_t val = rand_uint63n(cnt); - sum += ((double)val)/(cnt-1); + sum += val; test_assert(val < cnt); if (cnt < MAX_SEE_ALL) seen[val] = true; } if (cnt > 1) { - test_assert(sum/ROUNDS > 0.45); - test_assert(sum/ROUNDS < 0.55); + test_assert(sum/ROUNDS > 0.45*(cnt-1)); + test_assert(sum/ROUNDS < 0.55*(cnt-1)); } if (cnt < MAX_SEE_ALL) { for (uint64_t i = 0; i < cnt; i++) |