Picolibc 是一种适用于小型微控制器嵌入式系统的 C 标准库,该库的 API 甚至允许在低内存 ( RAM ) 设备中运行。picolibc 是「newlib-nano」的升级版本,它没有成熟的 stdio lib,使用的是 avrlibc 的轻量级 stdio lib,更适合低内存嵌入式设备。 Zephyr 在 v3.3.0 引入 Picolibc,从 v3.5.0 开始将 Picolibc 做为默认的标准 C 库。
Picolibc 是为嵌入式系统编写的完整 C 库实现,面向 C17 ( ISO/IEC 9899:2018 ) 和 POSIX 2018 ( IEEE Std 1003.1-2017 ) 标准。Picolibc 是一个外部开源项目,Zephyr 通过下面两种方式导入 Picolibc:
- 作为模块
- 作为 Zephyr SDK 的一部分以预编译形式包含在每个支持的架构工具链中 ( libc.a )
Picolibc 模块 链接到标题
作为模块 Picolibc 默认会放在 modules/lib/picolibc
下,当配置 CONFIG_PICOLIBC_USE_MODULE=y
时将直接编译 Picolibc 模块代码。要更新 Picolibc 模块为较新版本时,还必须同步更新 Zephyr SDK 中捆绑的工具链的 Picolibc 版本。
Zephyr 通过下面几个配置调整 Picolibc 库中的功能集,来平衡库的支持范围与生成函数的代码大小。
CONFIG_PICOLIBC_FAST_STRCMP
CONFIG_PICOLIBC_IO_C99_FORMATS
CONFIG_PICOLIBC_IO_LONG_LONG
CONFIG_PICOLIBC_IO_PERCENT_B
CONFIG_PICOLIBC_IO_FLOAT
CONFIG_PICOLIBC_IO_FLOAT_EXACT
CONFIG_PICOLIBC_LOCALE_INFO
CONFIG_PICOLIBC_LOCALE_EXTENDED_INFO
CONFIG_PICOLIBC_MULTIBYTE
CONFIG_PICOLIBC_MULTITHREAD
CONFIG_THREAD_LOCAL_STORAGE
CONFIG_PICOLIBC_GLOBAL_ERRNO
CONFIG_SIZE_OPTIMIZATIONS
使用 Picolibc 模块的注意点:
- 由于标准 C++库必须针对目标 C 库进行编译,因此无法在使用标准 C++库的应用程序中使用 Picolibc 模块。
- 构建 Picolibc 模块会增加编译应用程序所需的时间。
- 在将 Picolibc 模块更新为较新版本时,还必须更新 Zephyr SDK 中捆绑的工具链版本与之相同的 Picolibc。
工具链中的 Picolibc 链接到标题
从 Zephyr SDK 0.16 开始就包含了针对每个目标架构的预编译版本的 Picolibc,以及预编译版本的 libstdc++。默认情况下 CONFIG_PICOLIBC_USE_MODULE=n
会直接使用工具链内的 Picolibc。应当按照 Zephyr 的发布版本使用对应推荐的 Zephyr SDK 版本,已包装 Picolibc 模块和工具链内预编译 Picolibc 版本的一致。
C 库格式化输出 链接到标题
Picolibc 支持所有标准 C 格式化输入和输出函数,包括 printf ( )
、fprintf ( )
、sprintf ( )
和 sscanf ( )
。
Picolibc 的格式化输入和输出函数实现支持 C17 和 POSIX 2018 标准中定义的所有格式说明符,例外:
- 浮点数格式说明符 ( 例如%f ) 需要启用
CONFIG_PICOLIBC_IO_FLOAT
。 - 长长整型格式说明符 ( 例如%lld ) 需要启用
CONFIG_PICOLIBC_IO_LONG_LONG
。这个选项在启用CONFIG_PICOLIBC_IO_FLOAT
时会自动启用。
Zephyr 格式化输出 链接到标题
在使用 Picolibc 时,Zephyr 的格式化输出函数是基于 stdio 调用实现的,这些函数有:
printk
、snprintk
和vsnprintk
cbprintf
和cbvprintf
fprintfcb
、vfprintfcb
、printfcb
、vprintfcb
、snprintfcb
和vsnprintfcb
启用 CONFIG_CBPRINTF_PACKAGE_SUPPORT_TAGGED_ARGUMENTS
和 CBPRINTF_PACKAGE_ARGS_ARE_TAGGED
时, cbpprintf
的不会使用 Picolibc的 stdio 。
数学函数 链接到标题
除了贝塞尔 ( Bessel ) 函数的 long double
版本之外,Picolibc 为 float
、double
和 long double
的数学运算提供了完整的 C17/IEEE STD 754-2019 支持。
线程本地存储 ( TLS ) 链接到标题
Picolibc 支持 TLS,当开启 TLS 后,由于 TLS 变量的加入对线程堆栈需求量会变大。
Picolibc 内部全局变量 链接到标题
Picolibc 在一些内部全局变量被收集在一个专用的内存分区 z_libc_partition
内,在 zephyr/lib/libc/picolibc/libc-hooks.c
中可以看到这些变量。使用 CONFIG_USERSPACE
和内存域的应用程序必须确保在进行 Picolibc 调用期间的活动域中包含了这个分区。
动态内存管理 链接到标题
Picolibc 使用通用 C 库提供的 malloc API 族的实现,通用 C 库本身是基于内核堆管理构建的。
参考 链接到标题
https://docs.zephyrproject.org/3.5.0/develop/languages/c/picolibc.html