diff --git a/Makefile.dep b/Makefile.dep index 7b73c2e2c8..1274aa3ca4 100644 --- a/Makefile.dep +++ b/Makefile.dep @@ -479,6 +479,14 @@ ifneq (,$(filter posix_select,$(USEMODULE))) USEMODULE += xtimer endif +ifneq (,$(filter picolibc,$(USEMODULE))) + # allow custom picolibc syscalls implementations by adding + # picolibc_syscalls_XXX to USEMODULE + ifeq (,$(filter picolibc_syscalls_%,$(USEMODULE))) + USEMODULE += picolibc_syscalls_default + endif +endif + ifneq (,$(filter posix_sockets,$(USEMODULE))) USEMODULE += bitfield USEMODULE += random diff --git a/core/include/thread.h b/core/include/thread.h index a2d2a1486d..78131c24c6 100644 --- a/core/include/thread.h +++ b/core/include/thread.h @@ -176,6 +176,10 @@ struct _thread { const char *name; /**< thread's name */ int stack_size; /**< thread's stack size */ #endif +/* enable TLS only when Picolibc is compiled with TLS enabled */ +#ifdef PICOLIBC_TLS + void *tls; /**< thread local storage ptr */ +#endif #ifdef HAVE_THREAD_ARCH_T thread_arch_t arch; /**< architecture dependent part */ #endif diff --git a/core/sched.c b/core/sched.c index f099c5f15b..907ddb5a23 100644 --- a/core/sched.c +++ b/core/sched.c @@ -40,6 +40,10 @@ #include #endif +#ifdef PICOLIBC_TLS +#include +#endif + /* Needed by OpenOCD to read sched_threads */ #if defined(__APPLE__) && defined(__MACH__) #define FORCE_USED_SECTION __attribute__((used)) __attribute__((section( \ @@ -148,6 +152,9 @@ int __attribute__((used)) sched_run(void) next_thread->status = STATUS_RUNNING; sched_active_pid = next_thread->pid; sched_active_thread = next_thread; +#ifdef PICOLIBC_TLS + _set_tls(next_thread->tls); +#endif #ifdef MODULE_MPU_STACK_GUARD mpu_configure( diff --git a/core/thread.c b/core/thread.c index b723bbfde1..3de9dfb23c 100644 --- a/core/thread.c +++ b/core/thread.c @@ -20,6 +20,9 @@ #include #include +#ifdef PICOLIBC_TLS +#include +#endif #include "assert.h" #include "thread.h" @@ -215,6 +218,13 @@ kernel_pid_t thread_create(char *stack, int stacksize, uint8_t priority, /* allocate our thread control block at the top of our stackspace */ thread_t *thread = (thread_t *)(stack + stacksize); +#ifdef PICOLIBC_TLS + stacksize -= _tls_size(); + + thread->tls = stack + stacksize; + _init_tls(thread->tls); +#endif + #if defined(DEVELHELP) || defined(SCHED_TEST_STACK) if (flags & THREAD_CREATE_STACKTEST) { /* assign each int of the stack the value of it's address */ diff --git a/cpu/arm7_common/arm7_init.c b/cpu/arm7_common/arm7_init.c index f9619eae9d..c5e4d903a8 100644 --- a/cpu/arm7_common/arm7_init.c +++ b/cpu/arm7_common/arm7_init.c @@ -127,7 +127,7 @@ void bootloader(void) /* cpu specific setup of clocks, peripherals */ cpu_init(); -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) extern void __libc_init_array(void); __libc_init_array(); #endif diff --git a/cpu/cortexm_common/Makefile.dep b/cpu/cortexm_common/Makefile.dep index 472b903407..edc2835da9 100644 --- a/cpu/cortexm_common/Makefile.dep +++ b/cpu/cortexm_common/Makefile.dep @@ -4,11 +4,15 @@ USEMODULE += cortexm_common # include common periph code USEMODULE += cortexm_common_periph -# all cortex MCU's use newlib as libc -USEMODULE += newlib - -# use the nano-specs of Newlib when available -USEMODULE += newlib_nano +ifeq (1,$(PICOLIBC)) + # Use Picolibc when explicitly selected + USEMODULE += picolibc +else + # all cortex MCU's use newlib as libc + USEMODULE += newlib + # use the nano-specs of Newlib when available + USEMODULE += newlib_nano +endif # Export the peripheral drivers to be linked into the final binary: USEMODULE += periph diff --git a/cpu/cortexm_common/ldscripts/cortexm_base.ld b/cpu/cortexm_common/ldscripts/cortexm_base.ld index 2ed641a0f5..de0dc81fd1 100644 --- a/cpu/cortexm_common/ldscripts/cortexm_base.ld +++ b/cpu/cortexm_common/ldscripts/cortexm_base.ld @@ -96,6 +96,42 @@ SECTIONS _efixed = .; /* End of text section */ } > rom + /* + * TLS relocations are offsets relative to the address + * of the first TLS symbol. That means we just need to + * allocate them all together so that the TLS region + * is compact when allocated for each thread. + */ + + /* + * TLS initialization data is loaded into ROM so that + * each thread can get its values initialized from there + * at startup + */ + .tdata : + { + __tdata_start = .; + *(.tdata .tdata.* .gnu.linkonce.td.*) + __tdata_end = .; + } > rom + __tdata_source = LOADADDR(.tdata); + __tdata_size = SIZEOF(.tdata); + + /* + * TLS zeroed data is relocated as if it immediately followed + * the tdata values. However, the linker 'magically' erases the + * memory allocation so that no ROM is consumed by this + * section + */ + .tbss : + { + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + __tbss_end = .; + } > rom + __tls_size = __tbss_end - __tdata_start; + __tbss_size = __tls_size - __tdata_size; + /* .ARM.exidx is sorted, so has to go in its own output section. */ PROVIDE_HIDDEN (__exidx_start = .); .ARM.exidx : diff --git a/cpu/cortexm_common/vectors_cortexm.c b/cpu/cortexm_common/vectors_cortexm.c index 4a751d4bcf..17fd205921 100644 --- a/cpu/cortexm_common/vectors_cortexm.c +++ b/cpu/cortexm_common/vectors_cortexm.c @@ -174,7 +174,7 @@ void reset_handler_default(void) /* initialize the board (which also initiates CPU initialization) */ board_init(); -#if MODULE_NEWLIB +#if MODULE_NEWLIB || MODULE_PICOLIBC /* initialize std-c library (this must be done after board_init) */ extern void __libc_init_array(void); __libc_init_array(); diff --git a/cpu/fe310/Makefile b/cpu/fe310/Makefile index 6fdbf475a4..98076f3201 100644 --- a/cpu/fe310/Makefile +++ b/cpu/fe310/Makefile @@ -2,6 +2,10 @@ MODULE = cpu # add a list of subdirectories, that should also be built -DIRS = periph nano vendor +DIRS = periph vendor + +ifneq (1,$(PICOLIBC)) + DIRS += nano +endif include $(RIOTBASE)/Makefile.base diff --git a/cpu/fe310/Makefile.dep b/cpu/fe310/Makefile.dep index 3a32bc7fd8..9d1c9bdb2a 100644 --- a/cpu/fe310/Makefile.dep +++ b/cpu/fe310/Makefile.dep @@ -1,6 +1,10 @@ -USEMODULE += newlib_nano +ifeq (1,$(PICOLIBC)) + USEMODULE += picolibc +else + USEMODULE += newlib_nano + USEMODULE += newlib_syscalls_fe310 +endif -USEMODULE += newlib_syscalls_fe310 USEMODULE += sifive_drivers_fe310 USEMODULE += periph diff --git a/cpu/fe310/cpu.c b/cpu/fe310/cpu.c index bede3f4915..81442d7da3 100644 --- a/cpu/fe310/cpu.c +++ b/cpu/fe310/cpu.c @@ -24,6 +24,8 @@ #include "vendor/encoding.h" #include "vendor/plic_driver.h" +#include "stdio_uart.h" + /* * Configure the memory mapped flash for faster throughput * to minimize interrupt latency on an I-Cache miss and refill @@ -110,8 +112,12 @@ void cpu_init(void) /* Initialize IRQs */ irq_init(); + /* Initialize stdio */ + stdio_init(); +#ifndef _PICOLIBC__ /* Initialize newlib-nano library stubs */ nanostubs_init(); +#endif /* PICOLIBC */ /* Initialize static peripheral */ periph_init(); diff --git a/cpu/fe310/ldscripts/fe310_base.ld b/cpu/fe310/ldscripts/fe310_base.ld index 845b6d1d45..3a344dd5ec 100644 --- a/cpu/fe310/ldscripts/fe310_base.ld +++ b/cpu/fe310/ldscripts/fe310_base.ld @@ -27,6 +27,7 @@ PHDRS flash PT_LOAD; ram_init PT_LOAD; ram PT_NULL; + tls PT_TLS; } SECTIONS @@ -118,6 +119,42 @@ SECTIONS KEEP (*(.dtors)) } >flash AT>flash :flash + /* + * TLS relocations are offsets relative to the address + * of the first TLS symbol. That means we just need to + * allocate them all together so that the TLS region + * is compact when allocated for each thread. + */ + + /* + * TLS initialization data is loaded into ROM so that + * each thread can get its values initialized from there + * at startup + */ + .tdata : + { + __tdata_start = .; + *(.tdata .tdata.* .gnu.linkonce.td.*) + __tdata_end = .; + } >flash AT>flash :tls + __tdata_source = LOADADDR(.tdata); + __tdata_size = SIZEOF(.tdata); + + /* + * TLS zeroed data is relocated as if it immediately followed + * the tdata values. However, the linker 'magically' erases the + * memory allocation so that no ROM is consumed by this + * section + */ + .tbss : + { + *(.tbss .tbss.* .gnu.linkonce.tb.*) + *(.tcommon) + __tbss_end = .; + } >flash : tls + __tls_size = __tbss_end - __tdata_start; + __tbss_size = __tls_size - __tdata_size; + .lalign : { . = ALIGN(4); diff --git a/cpu/fe310/nano/nanostubs.c b/cpu/fe310/nano/nanostubs.c index 80f8f6ad4b..914baff797 100644 --- a/cpu/fe310/nano/nanostubs.c +++ b/cpu/fe310/nano/nanostubs.c @@ -40,7 +40,6 @@ void nanostubs_init(void) { #if defined(MODULE_STDIO_UART) /* STDIO redirected to UART, no line buffering */ - stdio_init(); setvbuf(stdout, NULL, _IONBF, 0); #endif } diff --git a/cpu/fe310/start.S b/cpu/fe310/start.S index d3518e5344..c80485c068 100644 --- a/cpu/fe310/start.S +++ b/cpu/fe310/start.S @@ -43,8 +43,6 @@ _start: 2: /* Call global constructors */ - la a0, __libc_fini_array - call atexit call __libc_init_array diff --git a/examples/filesystem/main.c b/examples/filesystem/main.c index ba1a28a9d8..759d61c4ab 100644 --- a/examples/filesystem/main.c +++ b/examples/filesystem/main.c @@ -240,9 +240,9 @@ static int _cat(int argc, char **argv) printf("Usage: %s \n", argv[0]); return 1; } - /* With newlib, low-level syscalls are plugged to RIOT vfs + /* With newlib or picolibc, low-level syscalls are plugged to RIOT vfs * on native, open/read/write/close/... are plugged to RIOT vfs */ -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) FILE *f = fopen(argv[1], "r"); if (f == NULL) { printf("file %s does not exist\n", argv[1]); @@ -276,7 +276,7 @@ static int _tee(int argc, char **argv) return 1; } -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) FILE *f = fopen(argv[1], "w+"); if (f == NULL) { printf("error while trying to create %s\n", argv[1]); diff --git a/makefiles/docker.inc.mk b/makefiles/docker.inc.mk index 3f797fa779..587a3dfa2f 100644 --- a/makefiles/docker.inc.mk +++ b/makefiles/docker.inc.mk @@ -57,6 +57,7 @@ export DOCKER_ENV_VARS += \ PREFIX \ QUIET \ WERROR \ + PICOLIBC \ PROGRAMMER \ RIOT_CI_BUILD \ RIOT_VERSION \ diff --git a/makefiles/libc/picolibc.mk b/makefiles/libc/picolibc.mk new file mode 100644 index 0000000000..94263d082b --- /dev/null +++ b/makefiles/libc/picolibc.mk @@ -0,0 +1,25 @@ +ifneq (,$(filter picolibc,$(USEMODULE))) + # Test if picolibc.specs is available + ifeq ($(shell $(LINK) -specs=picolibc.specs -E - 2>/dev/null >/dev/null &1 | grep -q "use of wchar_t values across objects may fail" ; echo $$?),0) + CFLAGS += -fshort-wchar + LINKFLAGS += -Wl,--no-wchar-size-warning + endif + endif +endif + +ifeq (1,$(USE_PICOLIBC)) + LINKFLAGS += -specs=picolibc.specs + # RIOT uses _sheap and _eheap for heap start and end, PicoLIBC uses + # __heap_start and __heap_end. This glues these different names together. + LINKFLAGS += -Wl,--defsym=__heap_end=_eheap + LINKFLAGS += -Wl,--defsym=__heap_start=_sheap + CFLAGS += -specs=picolibc.specs + ifeq (,$(filter printf_float scanf_float,$(USEMODULE))) + CFLAGS += -DPICOLIBC_INTEGER_PRINTF_SCANF + LINKFLAGS += -DPICOLIBC_INTEGER_PRINTF_SCANF + endif +endif + +LINKFLAGS += -lc diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index 31abbf9e59..510e6fecd8 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -85,6 +85,7 @@ PSEUDOMODULES += newlib PSEUDOMODULES += newlib_gnu_source PSEUDOMODULES += newlib_nano PSEUDOMODULES += openthread +PSEUDOMODULES += picolibc PSEUDOMODULES += pktqueue PSEUDOMODULES += posix_headers PSEUDOMODULES += printf_float diff --git a/makefiles/stdio.inc.mk b/makefiles/stdio.inc.mk index 4f4959be16..4c7749d2f9 100644 --- a/makefiles/stdio.inc.mk +++ b/makefiles/stdio.inc.mk @@ -8,7 +8,7 @@ STDIO_MODULES = \ stdio_uart \ # -ifneq (,$(filter newlib,$(USEMODULE))) +ifneq (,$(filter newlib picolibc,$(USEMODULE))) ifeq (,$(filter $(STDIO_MODULES),$(USEMODULE))) USEMODULE += stdio_uart endif diff --git a/sys/Makefile.include b/sys/Makefile.include index a449b90e99..a5cb26e796 100644 --- a/sys/Makefile.include +++ b/sys/Makefile.include @@ -68,10 +68,18 @@ ifneq (,$(filter newlib,$(USEMODULE))) include $(RIOTMAKE)/libc/newlib.mk endif +ifneq (,$(filter picolibc,$(USEMODULE))) + include $(RIOTMAKE)/libc/picolibc.mk +endif + ifneq (,$(filter newlib_syscalls_default,$(USEMODULE))) include $(RIOTBASE)/sys/newlib_syscalls_default/Makefile.include endif +ifneq (,$(filter picolibc_syscalls_default,$(USEMODULE))) + include $(RIOTBASE)/sys/picolibc_syscalls_default/Makefile.include +endif + ifneq (,$(filter arduino,$(USEMODULE))) include $(RIOTBASE)/sys/arduino/Makefile.include endif diff --git a/sys/log/log_color/log_module.h b/sys/log/log_color/log_module.h index 4e0942923b..82209c4459 100644 --- a/sys/log/log_color/log_module.h +++ b/sys/log/log_color/log_module.h @@ -110,7 +110,7 @@ static inline void log_write(unsigned level, const char *format, ...) va_end(args); printf(LOG_RESET_ANSI_COLOR_CODE); -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) /* no fflush on msp430 */ fflush(stdout); #endif diff --git a/sys/picolibc_syscalls_default/Makefile b/sys/picolibc_syscalls_default/Makefile new file mode 100644 index 0000000000..48422e909a --- /dev/null +++ b/sys/picolibc_syscalls_default/Makefile @@ -0,0 +1 @@ +include $(RIOTBASE)/Makefile.base diff --git a/sys/picolibc_syscalls_default/Makefile.include b/sys/picolibc_syscalls_default/Makefile.include new file mode 100644 index 0000000000..d14f2c9f79 --- /dev/null +++ b/sys/picolibc_syscalls_default/Makefile.include @@ -0,0 +1 @@ +UNDEF += $(BINDIR)/picolibc_syscalls_default/syscalls.o diff --git a/sys/picolibc_syscalls_default/syscalls.c b/sys/picolibc_syscalls_default/syscalls.c new file mode 100644 index 0000000000..1782610d08 --- /dev/null +++ b/sys/picolibc_syscalls_default/syscalls.c @@ -0,0 +1,357 @@ +/* + * Copyright (C) 2019 Koen Zandberg + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @defgroup sys_picolibc PicoLibc system call + * @ingroup sys + * @brief PicoLibc system call + * @{ + * + * @file + * @brief PicoLibc system call implementations + * + * @author Koen Zandberg + * + * @} + */ + +#include +#include +#include + +#include "log.h" +#include "periph/pm.h" +#include "stdio_base.h" + +/** + * @brief Exit a program without cleaning up files + * + * If your system doesn't provide this, it is best to avoid linking with subroutines that + * require it (exit, system). + * + * @param n the exit code, 0 for all OK, >0 for not OK + */ +void __attribute__((__noreturn__)) +_exit(int n) +{ + LOG_INFO("#! exit %i: powering off\n", n); + pm_off(); + while(1); +} + +/** + * @brief Send a signal to a thread + * + * @param[in] pid the pid to send to + * @param[in] sig the signal to send + * + * @return always returns -1 to signal error + */ +__attribute__ ((weak)) +int kill(pid_t pid, int sig) +{ + (void) pid; + (void) sig; + errno = ESRCH; /* not implemented yet */ + return -1; +} + +#include "mutex.h" + +static mutex_t picolibc_put_mutex = MUTEX_INIT; + +#define PICOLIBC_STDOUT_BUFSIZE 64 + +static char picolibc_stdout[PICOLIBC_STDOUT_BUFSIZE]; +static int picolibc_stdout_queued; + +static void _picolibc_flush(void) +{ + if (picolibc_stdout_queued) { + stdio_write(picolibc_stdout, picolibc_stdout_queued); + picolibc_stdout_queued = 0; + } +} + +static int picolibc_put(char c, FILE *file) +{ + (void)file; + mutex_lock(&picolibc_put_mutex); + picolibc_stdout[picolibc_stdout_queued++] = c; + if (picolibc_stdout_queued == PICOLIBC_STDOUT_BUFSIZE || c == '\n') + _picolibc_flush(); + mutex_unlock(&picolibc_put_mutex); + return 1; +} + +static int picolibc_flush(FILE *file) +{ + (void)file; + mutex_lock(&picolibc_put_mutex); + _picolibc_flush(); + mutex_unlock(&picolibc_put_mutex); + return 0; +} + +static int picolibc_get(FILE *file) +{ + (void)file; + picolibc_flush(NULL); + char c = 0; + stdio_read(&c, 1); + return c; +} + +FILE picolibc_stdio = + FDEV_SETUP_STREAM(picolibc_put, picolibc_get, picolibc_flush, _FDEV_SETUP_RW); + +FILE *const __iob[] = { + &picolibc_stdio, /* stdin */ + &picolibc_stdio, /* stdout */ + &picolibc_stdio, /* stderr */ +}; + +#include +/** + * @brief Get the process-ID of the current thread + * + * @return the process ID of the current thread + */ +pid_t getpid(void) +{ + return thread_getpid(); +} + +#if MODULE_VFS +#include "vfs.h" + +/** + * @brief Open a file + * + * This is a wrapper around @c vfs_open + * + * @param name file name to open + * @param flags flags, see man 3p open + * @param mode mode, file creation mode if the file is created when opening + * + * @return fd number (>= 0) on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +int open(const char *name, int flags, int mode) +{ + int fd = vfs_open(name, flags, mode); + if (fd < 0) { + /* vfs returns negative error codes */ + errno = -fd; + return -1; + } + return fd; +} + +/** + * @brief Read bytes from an open file + * + * This is a wrapper around @c vfs_read + * + * @param[in] fd open file descriptor obtained from @c open() + * @param[out] dest destination buffer + * @param[in] count maximum number of bytes to read + * + * @return number of bytes read on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +_READ_WRITE_RETURN_TYPE read(int fd, void *dest, size_t count) +{ + int res = vfs_read(fd, dest, count); + if (res < 0) { + /* vfs returns negative error codes */ + errno = -res; + return -1; + } + return res; +} + +/** + * @brief Write bytes to an open file + * + * This is a wrapper around @c vfs_write + * + * @param[in] fd open file descriptor obtained from @c open() + * @param[in] src source data buffer + * @param[in] count maximum number of bytes to write + * + * @return number of bytes written on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +_READ_WRITE_RETURN_TYPE write(int fd, const void *src, size_t count) +{ + int res = vfs_write(fd, src, count); + if (res < 0) { + /* vfs returns negative error codes */ + errno = -res; + return -1; + } + return res; +} + +/** + * @brief Close an open file + * + * This is a wrapper around @c vfs_close + * + * If this call returns an error, the fd should still be considered invalid and + * no further attempt to use it shall be made, not even to retry @c close() + * + * @param[in] fd open file descriptor obtained from @c open() + * + * @return 0 on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +int close(int fd) +{ + int res = vfs_close(fd); + if (res < 0) { + /* vfs returns negative error codes */ + errno = -res; + return -1; + } + return res; +} + +/** + * Current process times (not implemented). + * + * @param[out] ptms Not modified. + * + * @return -1, this function always fails. errno is set to ENOSYS. + */ +clock_t times(struct tms *ptms) +{ + (void)ptms; + errno = ENOSYS; + + return (-1); +} + +/** + * @brief Query or set options on an open file + * + * This is a wrapper around @c vfs_fcntl + * + * @param[in] fd open file descriptor obtained from @c open() + * @param[in] cmd fcntl command, see man 3p fcntl + * @param[in] arg argument to fcntl command, see man 3p fcntl + * + * @return 0 on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +int fcntl (int fd, int cmd, int arg) +{ + int res = vfs_fcntl(fd, cmd, arg); + if (res < 0) { + /* vfs returns negative error codes */ + errno = -res; + return -1; + } + return res; +} + +/** + * @brief Seek to position in file + * + * This is a wrapper around @c vfs_lseek + * + * @p whence determines the function of the seek and should be set to one of + * the following values: + * + * - @c SEEK_SET: Seek to absolute offset @p off + * - @c SEEK_CUR: Seek to current location + @p off + * - @c SEEK_END: Seek to end of file + @p off + * + * @param[in] fd open file descriptor obtained from @c open() + * @param[in] off seek offset + * @param[in] whence determines the seek method, see detailed description + * + * @return the new seek location in the file on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +off_t lseek(int fd, _off_t off, int whence) +{ + int res = vfs_lseek(fd, off, whence); + if (res < 0) { + /* vfs returns negative error codes */ + errno = -res; + return -1; + } + return res; +} + +/** + * @brief Get status of an open file + * + * This is a wrapper around @c vfs_fstat + * + * @param[in] fd open file descriptor obtained from @c open() + * @param[out] buf pointer to stat struct to fill + * + * @return 0 on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +int fstat(int fd, struct stat *buf) +{ + int res = vfs_fstat(fd, buf); + if (res < 0) { + /* vfs returns negative error codes */ + errno = -res; + return -1; + } + return 0; +} + +/** + * @brief Status of a file (by name) + * + * This is a wrapper around @c vfs_fstat + * + * @param[in] name path to file + * @param[out] buf pointer to stat struct to fill + * + * @return 0 on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +int stat(const char *name, struct stat *st) +{ + int res = vfs_stat(name, st); + if (res < 0) { + /* vfs returns negative error codes */ + errno = -res; + return -1; + } + return 0; +} + +/** + * @brief Unlink (delete) a file + * + * @param[in] path path to file to be deleted + * + * @return 0 on success + * @return -1 on error, @c errno set to a constant from errno.h to indicate the error + */ +int unlink(const char *path) +{ + int res = vfs_unlink(path); + if (res < 0) { + /* vfs returns negative error codes */ + errno = -res; + return -1; + } + return 0; +} + +#endif /* MODULE_VFS */ diff --git a/sys/posix/include/fcntl.h b/sys/posix/include/fcntl.h index 3cc1a766cf..d7ff4ecae7 100644 --- a/sys/posix/include/fcntl.h +++ b/sys/posix/include/fcntl.h @@ -16,7 +16,7 @@ */ #ifndef DOXYGEN -#if defined(CPU_NATIVE) || MODULE_NEWLIB +#if defined(CPU_NATIVE) || MODULE_NEWLIB || MODULE_PICOLIBC /* If building on native or newlib we need to use the system header instead */ #pragma GCC system_header /* without the GCC pragma above #include_next will trigger a pedantic error */ diff --git a/sys/posix/include/sys/select.h b/sys/posix/include/sys/select.h index 6899e262cf..743bb3374f 100644 --- a/sys/posix/include/sys/select.h +++ b/sys/posix/include/sys/select.h @@ -30,8 +30,9 @@ #define SYS_SELECT_H #include -/* prevent cyclic dependency with newlib's `sys/types.h` */ -#if defined(MODULE_NEWLIB) && !defined(CPU_ESP32) && !defined(CPU_ESP8266) +/* prevent cyclic dependency with newlib/picolibc's `sys/types.h` */ +#if (defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC)) && \ + !defined(CPU_ESP32) && !defined(CPU_ESP8266) #include #else #include diff --git a/sys/progress_bar/progress_bar.c b/sys/progress_bar/progress_bar.c index 70ee709885..2bec1c5d8c 100644 --- a/sys/progress_bar/progress_bar.c +++ b/sys/progress_bar/progress_bar.c @@ -72,7 +72,7 @@ void progress_bar_print(char *prefix, char *suffix, uint8_t value) /* show cursor */ printf("\033[?25h"); -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) fflush(stdout); #endif } diff --git a/sys/shell/commands/sc_sntp.c b/sys/shell/commands/sc_sntp.c index d8337068fb..1cd3886cc6 100644 --- a/sys/shell/commands/sc_sntp.c +++ b/sys/shell/commands/sc_sntp.c @@ -82,7 +82,7 @@ int _ntpdate(int argc, char **argv) puts("Error in synchronization"); return 1; } -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) struct tm *tm; time_t time = (time_t)(sntp_get_unix_usec() / US_PER_SEC); diff --git a/sys/shell/shell.c b/sys/shell/shell.c index 167cdb6ee4..297344043f 100644 --- a/sys/shell/shell.c +++ b/sys/shell/shell.c @@ -42,11 +42,11 @@ #define BS '\x08' /** ASCII "Backspace" */ #define DEL '\x7f' /** ASCII "Delete" */ -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) #define flush_if_needed() fflush(stdout) #else #define flush_if_needed() -#endif /* MODULE_NEWLIB */ +#endif /* MODULE_NEWLIB || MODULE_PICOLIBC */ #ifndef SHELL_NO_ECHO #define ECHO_ON 1 diff --git a/tests/bloom_bytes/main.c b/tests/bloom_bytes/main.c index f611e6f4ba..5628cad6b2 100644 --- a/tests/bloom_bytes/main.c +++ b/tests/bloom_bytes/main.c @@ -110,7 +110,7 @@ int main(void) double false_positive_rate = (double) in / (double) lenA; /* Use 'fmt/print_float' to work on all platforms (atmega) * Stdout should be flushed before to prevent garbled output. */ -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) fflush(stdout); #endif print_float(false_positive_rate, 6); diff --git a/tests/pkg_fatfs_vfs/main.c b/tests/pkg_fatfs_vfs/main.c index 4b6059fe7c..b90b5f3636 100644 --- a/tests/pkg_fatfs_vfs/main.c +++ b/tests/pkg_fatfs_vfs/main.c @@ -325,16 +325,16 @@ static void test_fstat(void) print_test_result("test_stat__umount", vfs_umount(&_test_vfs_mount) == 0); } -#ifdef MODULE_NEWLIB -static void test_newlib(void) +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) +static void test_libc(void) { FILE* fl; char buf[sizeof(test_txt) + sizeof(test_txt2)]; - print_test_result("test_newlib__mount", vfs_mount(&_test_vfs_mount) == 0); + print_test_result("test_libc__mount", vfs_mount(&_test_vfs_mount) == 0); /* try to open file that doesn't exist */ fl = fopen(FULL_FNAME_NXIST, "r"); - print_test_result("test_newlib__fopen", fl == NULL); + print_test_result("test_libc__fopen", fl == NULL); if (fl) { fclose(fl); } @@ -342,52 +342,52 @@ static void test_newlib(void) /* create new file write and check content */ remove(FULL_FNAME2); fl = fopen(FULL_FNAME2, "w+"); - print_test_result("test_newlib__fopen_w", fl != NULL); + print_test_result("test_libc__fopen_w", fl != NULL); if (fl) { - print_test_result("test_newlib__fputs_w", fputs(test_txt, fl) >= 0); + print_test_result("test_libc__fputs_w", fputs(test_txt, fl) >= 0); rewind(fl); - print_test_result("test_newlib__fread_w", + print_test_result("test_libc__fread_w", fread(buf, sizeof(*buf), sizeof(buf), fl) > 0); - print_test_result("test_newlib__strcmp_w", strcmp(test_txt, buf) == 0); - print_test_result("test_newlib__fclose_w", fclose(fl) == 0); + print_test_result("test_libc__strcmp_w", strcmp(test_txt, buf) == 0); + print_test_result("test_libc__fclose_w", fclose(fl) == 0); } /* cppcheck-suppress resourceLeak * (reason: cppcheck <2.0 reports a false positive here) */ fl = fopen(FULL_FNAME2, "r"); /* open file RO */ - print_test_result("test_newlib__fopen_r", fl != NULL); + print_test_result("test_libc__fopen_r", fl != NULL); if (fl) { - print_test_result("test_newlib__fclose_r", fclose(fl) == 0); + print_test_result("test_libc__fclose_r", fclose(fl) == 0); } /* remove file */ - print_test_result("test_newlib__remove", remove(FULL_FNAME2) == 0); + print_test_result("test_libc__remove", remove(FULL_FNAME2) == 0); /* append to non existing file */ fl = fopen(FULL_FNAME2, "a"); - print_test_result("test_newlib__fopen_a", fl != NULL); + print_test_result("test_libc__fopen_a", fl != NULL); if (fl) { - print_test_result("test_newlib__fputs_a", fputs(test_txt, fl) >= 0); - print_test_result("test_newlib__fclose_a", fclose(fl) == 0); + print_test_result("test_libc__fputs_a", fputs(test_txt, fl) >= 0); + print_test_result("test_libc__fclose_a", fclose(fl) == 0); } /* append to existing file and check content */ fl = fopen(FULL_FNAME2, "a+"); - print_test_result("test_newlib__fopen_a2", fl != NULL); + print_test_result("test_libc__fopen_a2", fl != NULL); if (fl) { - print_test_result("test_newlib__fputs_a2", fputs(test_txt2, fl) >= 0); + print_test_result("test_libc__fputs_a2", fputs(test_txt2, fl) >= 0); rewind(fl); - print_test_result("test_newlib__fread_a2", + print_test_result("test_libc__fread_a2", fread(buf, sizeof(*buf), sizeof(buf), fl) > 0); - print_test_result("test_newlib__strcmp_a2", + print_test_result("test_libc__strcmp_a2", strncmp(test_txt, buf, strlen(test_txt)) == 0); - print_test_result("test_newlib__strcmp_a2", strncmp(test_txt2, + print_test_result("test_libc__strcmp_a2", strncmp(test_txt2, &buf[strlen(test_txt)], strlen(test_txt2)) == 0); - print_test_result("test_newlib__fclose_a2", fclose(fl) == 0); + print_test_result("test_libc__fclose_a2", fclose(fl) == 0); } - print_test_result("test_newlib__remove", remove(FULL_FNAME2) == 0); + print_test_result("test_libc__remove", remove(FULL_FNAME2) == 0); - print_test_result("test_newlib__umount", vfs_umount(&_test_vfs_mount) == 0); + print_test_result("test_libc__umount", vfs_umount(&_test_vfs_mount) == 0); } #endif @@ -421,8 +421,8 @@ int main(void) test_mkrmdir(); test_create(); test_fstat(); -#ifdef MODULE_NEWLIB - test_newlib(); +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) + test_libc(); #endif printf("Test end.\n"); diff --git a/tests/rng/test.c b/tests/rng/test.c index 08a54f32c0..18ecae457a 100644 --- a/tests/rng/test.c +++ b/tests/rng/test.c @@ -389,7 +389,7 @@ void test_entropy(uint32_t samples) /* Use 'fmt/print_float' to work on all platforms (atmega) * Stdout should be flushed before to prevent garbled output. */ printf("Calculated "); -#ifdef MODULE_NEWLIB +#if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) /* no fflush on msp430 */ fflush(stdout); #endif diff --git a/tests/unittests/tests-vfs/tests-vfs-mount-constfs.c b/tests/unittests/tests-vfs/tests-vfs-mount-constfs.c index 4f630ac2be..5cf14271de 100644 --- a/tests/unittests/tests-vfs/tests-vfs-mount-constfs.c +++ b/tests/unittests/tests-vfs/tests-vfs-mount-constfs.c @@ -171,7 +171,7 @@ static void test_vfs_constfs_read_lseek(void) TEST_ASSERT_EQUAL_INT(0, res); } -#if MODULE_NEWLIB || defined(BOARD_NATIVE) +#if MODULE_NEWLIB || MODULE_PICOLIBC || defined(BOARD_NATIVE) static void test_vfs_constfs__posix(void) { int res; @@ -210,7 +210,7 @@ Test *tests_vfs_mount_constfs_tests(void) new_TestFixture(test_vfs_umount__invalid_mount), new_TestFixture(test_vfs_constfs_open), new_TestFixture(test_vfs_constfs_read_lseek), -#if MODULE_NEWLIB || defined(BOARD_NATIVE) +#if MODULE_NEWLIB || MODULE_PICOLIBC || defined(BOARD_NATIVE) new_TestFixture(test_vfs_constfs__posix), #endif };