Differences between Newlib and Newlib-Nano include:
- Newlib-Nano is optimized for size.
- The printf and scanf family of routines have been re-implemented in Newlib-Nano to remove a direct dependency on the floating-point input/output handling code. Projects that need to handle floating-point values using these functions must now explicitly request the feature during linking, as described above.
- The printf and scanf family of routines in Newlib-Nano support only conversion specifiers defined in C89 standard. This provides a good balance between small memory footprint and full feature formatted input/output.
- Newlib-Nano removes the now redundant integer-only implementations of the printf/scanf family of routines (iprintf/iscanf, etc).These functions now alias the standard routines.
- In Newlib-Nano, only unwritten buffered data is flushed on exit. Open streams are not closed.
- In Newlib-Nano, the dynamic memory allocator has been re-implemented
翻译如下:
- Newlib-Nano针对代码大小进行了优化。
- 在Newlib-Nano中重新实现了
printf
和scanf
系列例程,以消除对浮点输入/输出处理代码的直接依赖。需要使用这些函数处理浮点值的项目现在必须在链接期间显式请求该特性,如上所述。 - Newlib-Nano中的
printf
和scanf
系列例程只支持C89
标准中定义的转换说明符。这在小内存占用和全功能格式化输入/输出之间提供了良好的平衡。 - Newlib-Nano删除了现在多余的
printf/scanf
系列例程(iprintf/iscanf
等)的纯整数实现。这些函数现在是标准例程的别名。 - 在Newlib-Nano中,只有未写入的缓冲数据会在退出时刷新。已打开的流是不会关闭的。
- 在Newlib Nano中,重新实现了动态内存分配器。
arm-none-eabi-gcc工具链中的newlib库,它实现的printf
函数非常复杂,需要大约37k
字节的FLASH和5k
字节的RAM才能运行一个简单的hello-world程序。对于MCU编程来说,这太大了,因为您可能需要用printf功能来进行调试和日志记录。好消息是,newlib库里有很多不必要的“臃肿部分”可以被裁剪掉。
库的裁剪计划就是要减少不必要的功能,用更简单的逻辑重新实现功能,并在优化大小的同时进行构建。它产生了一组名为newlib nano的新库。即基于newlib,但大小要小得多。
Newlib nano削减了C89
之后添加的一些功能,这些功能被认为很少用于MCU编程。通过将格式转换器限制为C89标准,printf
中格式字符串处理的代码大大减少了。通过移除iov缓冲,所有IO功能的大小再次显著减小。对非宽字符函数中宽字符支持的删除则进一步压缩了字符串IO逻辑。Newlib nano还广泛使用弱符号技术来排除普通MCU程序中很少使用的功能。例如,将floating point IO
和atexit
引用为弱函数可以显著减少printf()
和exit()
的大小。
Newlib nano还重新实现了内存分配函数,以取代原来的那些总体性能更好但具有大量复杂逻辑的函数(这些函数会增加代码大小)。所谓的nano分配器使用简单的本地算法来处理分配、取消分配和碎片整理。当可分配的总内存很小时,它仍能有效地工作。更重要的是,它的尺寸只有原来的六分之一左右。
Newlib nano是使用优化级别Os
构建的。这会导致更小的memcpy
和memset
,因为newlib在发现这些函数是用Os
构建时会选择它们的简单版本。它还丢弃了C++库中的一些大型优化。newlib nano的另一个构建标志是-fno-exception
,它禁用库的异常处理。一些MCU C++开发人员承认这是可以接受的。
总之,newlib nano可以将hello world
程序的大小减少80%左右。在C++程序的极端情况下,大小缩减可能超过90%。
如何启用newlib-nano
arm-none-eabi-gcc工具链发布时带有两个基于newlib的预构建C库:一个是标准的newlib,另一个是newlib-nano(代码大小优化的)。为了区分它们,我们将大小优化的库重命名为:
libc.a --> libc_nano.a
libg.a --> libg_nano.a
要使用newlib-nano,用户应该提供额外的gcc编译和链接时选项: --specs=nano.specs
在编译时,如果--specs=nano.specs
被传递给编译器,那么一个专门为newlib-nano配置的“newlib.h”
头文件会被使用。
Nano.specs
还处理另外两个gcc库:libstdc++_nano.a
和libsupc++_nano.a
,它们针对代码大小进行了优化。例如:
$ arm-none-eabi-gcc src.c --specs=nano.specs $(OTHER_OPTIONS)
此选项也可以与其他specs
选项一起使用,如--specs=rdimon.specs
请注意,--specs=nano.specs
既是编译器选项,也是链接器选项。如果编译和链接是分开进行的,请确保该选项被同时包含在编译器和链接器中。
newlib-nano额外使用案例
newlib-nano相比newlib,不仅仅是库的名字上的区别。浮点数的格式化input/output
被实现为弱符号。如果要使用%f
,则必须通过显式指定"-u"
命令选项来引入该符号。
-u _scanf_float
-u _printf_float
例如,要输出一个浮点数,命令行就像这样:
$ arm-none-eabi-gcc --specs=nano.specs -u _printf_float $(OTHER_LINK_OPTIONS)
有关差异和用法的更多信息,请参阅源程序包中的README.nano
。