summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke T. Shumaker <lukeshu@lukeshu.com>2024-12-26 20:09:17 -0700
committerLuke T. Shumaker <lukeshu@lukeshu.com>2024-12-26 20:09:17 -0700
commite7e0cff1960fca598e0ba01be2bb56b65cbb9e2b (patch)
tree1e2c607ae9980b47917effe4203b4448a1dd4c5f
parentd0e9e9c4a178fe396f3ba255bc440a15b107a097 (diff)
parent1aecc70750ee6ce9c96ebf3e6b4a7fb322ff8ca3 (diff)
Merge branch 'lukeshu/check-build'
-rw-r--r--CMakeLists.txt7
-rw-r--r--GNUmakefile17
-rwxr-xr-xbuild-aux/stack.c.gen12
-rw-r--r--libcr/coroutine.c38
-rw-r--r--libcr/tests/test_matrix/config.h2
-rw-r--r--libmisc/CMakeLists.txt2
-rw-r--r--libmisc/assert.c4
-rw-r--r--libmisc/include/libmisc/_intercept.h21
-rw-r--r--libmisc/include/libmisc/assert.h2
-rw-r--r--libmisc/include/libmisc/log.h9
-rw-r--r--libmisc/intercept.c25
-rw-r--r--libmisc/log.c10
-rw-r--r--libmisc/tests/test_assert.c20
-rw-r--r--libmisc/tests/test_assert_min.c17
-rw-r--r--libmisc/tests/test_log.c49
-rw-r--r--libmisc/tests/test_rand.c25
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++)