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:

  1. 作为模块
  2. 作为 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 调用实现的,这些函数有:

  • printksnprintkvsnprintk
  • cbprintfcbvprintf
  • fprintfcbvfprintfcbprintfcbvprintfcbsnprintfcbvsnprintfcb

启用 CONFIG_CBPRINTF_PACKAGE_SUPPORT_TAGGED_ARGUMENTSCBPRINTF_PACKAGE_ARGS_ARE_TAGGED 时, cbpprintf 的不会使用 Picolibc的 stdio 。

数学函数 链接到标题

除了贝塞尔 ( Bessel ) 函数的 long double 版本之外,Picolibc 为 floatdouble 和 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