19.2 Picolibc Library

The picolibc library implements the standard C and C++ library functions, types, and macros; however, it provides additional thread safety and re-entrancy functionality not available in the default library. It can be linked to a project using the -mchp-stdlibc option, see Mchp-stdlibc Option.

The picolibc library is available for C and C++ projects and supports all ARM devices. Use of the picolibc library disables the smart IO features associated with functions like printf(). Math functions will also be linked from the picolibc library with this selection. You may select between speed- and space-orientated library alternatives of the picolibc library using the -mlibc-variant option.

The picolibc library defines thread-safe instances of the errno global variable, which is used by many standard library functions to indicate that an error was detected during execution. These variables are defined to use Thread-Local Storage (TLS), see Thread-local Storage. Using TLS ensures that each thread has its own instance of errno, preventing conflicts between threads.

The picolibc library also uses a global lock for APIs sharing global data. This includes the malloc() family of functions, onexit() and atexit(), and functions using timezones. This lock protects relevant functions from race conditions and provides data integrity, ensuring that your application is safe for use in a multithreaded environment. This prevents multiple threads from accessing and modifying memory simultaneously, which could lead to corruption or crashes.

Your application code must provide several functions to fully implement the retargetable locking API. The picolibc library provides stubs for all of these functions, which can be completed to suit your application. The stubs as provided do not perform locking, so a single-threaded application can still use the library, despite locking being enabled. See the document at github.com/picolibc/picolibc/blob/1.8.6/doc/locking.md for information. If you are using an RTOS, you might need to map these functions to the RTOS's mutex functions. Ensure that your application initializes and uses these locks correctly. Acquire the global lock before calling functions such as malloc(), which uses locking to share global data. Release the lock after the operation is complete.

Note that, like most standard C library implementations for bare-metal embedded systems, low-level system functions must be provided by the operating environment or application code. This includes functions such as gettimeofday(), read(), write(), _exit(), etc. The semihosting library does provide implementations of these functions, but these functions would typically need to be customised to work with your specific hardware. You may see an "undefined reference" error from the linker when linking.