From f4d9526802ba7001bdf43e8b0e0671d22b2171a0 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 3 Apr 2026 09:38:57 -0700 Subject: [PATCH] cbortojson: adapt to work with picolibc's variant of `funopen` Instead of matching the API first introduced by 4.4BSD, picolibc decided to be different. ``` tinycbor/src/open_memstream.c:103:29: error: passing argument 3 of 'funopen' from incompatible pointer type [-Wincompatible-pointer-types] 103 | return funopen(b, NULL, write_to_buffer, NULL, close_buffer); | ^~~~~~~~~~~~~~~ | | | RetType (*)(void *, const char *, LenType) {aka int (*)(void *, const char *, int)} In file included from tinycbor/src/open_memstream.c:31: picolibc/include/stdio.h:429:28: note: expected '_ssize_t (*)(void *, const void *, size_t)' {aka 'int (*)(void *, const void *, unsigned int)'} but argument is of type 'RetType (*)(void *, const char *, LenType)' {aka 'int (*)(void *, const char *, int)'} 429 | _ssize_t (*writefn)(void *cookie, const void *buf, size_t n), | ``` Signed-off-by: Thiago Macieira --- CMakeLists.txt | 35 ++++++++++++++++++++++++++++++++--- src/open_memstream.c | 12 ++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e1854746..21b27c34 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,6 +44,7 @@ include(GNUInstallDirs) include(GenerateExportHeader) include(CheckLinkerFlag) include(CheckSymbolExists) +include(CheckCSourceCompiles) add_library(tinycbor src/cborencoder.c @@ -131,13 +132,41 @@ configure_file(tinycbor.pc.in tinycbor.pc @ONLY) # Check for open_memstream and store the result in HAVE_OPEN_MEMSTREAM check_symbol_exists(open_memstream stdio.h HAVE_OPEN_MEMSTREAM) -check_symbol_exists(funopen stdio.h HAVE_OPEN_FUNOPEN) +# Check for funopen - try traditional BSD signature first (int/const char*/int), +# then the POSIX-like variant used by picolibc (ssize_t/const void*/size_t). +set(_saved_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") +if(MSVC) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /we4028 /we4113") +else() + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror=incompatible-pointer-types") +endif() +check_c_source_compiles(" +#include +static int write_fn(void *c, const char *b, int n) { (void)c; (void)b; return n; } +static int close_fn(void *c) { (void)c; return 0; } +int main(void) { funopen(NULL, NULL, write_fn, NULL, close_fn); return 0; } +" HAVE_OPEN_FUNOPEN) +if(NOT HAVE_OPEN_FUNOPEN) + check_c_source_compiles(" +#include +#include +static ssize_t write_fn(void *c, const void *b, size_t n) { (void)c; (void)b; return (ssize_t)n; } +static int close_fn(void *c) { (void)c; return 0; } +int main(void) { funopen(NULL, NULL, write_fn, NULL, close_fn); return 0; } +" HAVE_OPEN_FUNOPEN_SSIZE) +endif() +set(CMAKE_REQUIRED_FLAGS "${_saved_CMAKE_REQUIRED_FLAGS}") +unset(_saved_CMAKE_REQUIRED_FLAGS) check_symbol_exists(fopencookie stdio.h HAVE_OPEN_FOPENCOOKIE) if(NOT HAVE_OPEN_MEMSTREAM) - if (HAVE_OPEN_FUNOPEN) + if (HAVE_OPEN_FUNOPEN OR HAVE_OPEN_FUNOPEN_SSIZE) message(STATUS "implementing open_memstream using funopen()") - target_compile_definitions(tinycbor PRIVATE HAVE_OPEN_FUNOPEN) + if(HAVE_OPEN_FUNOPEN_SSIZE) + target_compile_definitions(tinycbor PRIVATE HAVE_OPEN_FUNOPEN_SSIZE) + else() + target_compile_definitions(tinycbor PRIVATE HAVE_OPEN_FUNOPEN) + endif() target_sources(tinycbor PRIVATE src/open_memstream.c) elseif (HAVE_OPEN_FOPENCOOKIE) message(STATUS "implementing open_memstream using fopencookie()") diff --git a/src/open_memstream.c b/src/open_memstream.c index ed94e898..d74eee61 100644 --- a/src/open_memstream.c +++ b/src/open_memstream.c @@ -35,12 +35,20 @@ #if defined(__unix__) || defined(__APPLE__) # include #endif -#if defined(HAVE_OPEN_FUNOPEN) +#if defined(HAVE_OPEN_FUNOPEN) || defined(HAVE_OPEN_FUNOPEN_SSIZE) +# if defined(HAVE_OPEN_FUNOPEN_SSIZE) +typedef ssize_t RetType; +typedef size_t LenType; +typedef const void *WriteBufType; +# else typedef int RetType; typedef int LenType; +typedef const char *WriteBufType; +# endif #elif defined(HAVE_OPEN_FOPENCOOKIE) typedef ssize_t RetType; typedef size_t LenType; +typedef const char *WriteBufType; #else # error "Cannot implement open_memstream!" #endif @@ -54,7 +62,7 @@ struct Buffer size_t alloc; }; -static RetType write_to_buffer(void *cookie, const char *data, LenType len) +static RetType write_to_buffer(void *cookie, WriteBufType data, LenType len) { struct Buffer *b = (struct Buffer *)cookie; char *ptr = *b->ptr;