编译静态库时,让编译器自动优化掉未使用的函数,减少最终程序的大小

在实际的项目里面,产品留给应用程序的空间较小,因此需要对程序用到的库进行裁剪。有些依赖的第三方开源库如openssl等占用体积较大,库中有很多实现的函数,但是应用程序并没有使用,没用的函数就应该不链接进来,占用宝贵的空间。

对此就需要修改编译选项:

(1)编译时加入:-ffunction-sections, -fdata-sections 选项,这样编译的时候,把每个函数作为一个section,每个数据(应该是指全局变量之类的吧)也作为一个section。如果不加-ffunction-sections选项,则默认似乎是每个源文件为一个section进行链接,这样子只要这个文件中用到了一个函数,那么所有的函数都会被链接进来。

(2)链接时加入:–gc-sections选项 ,这样链接的时候,–gc-sections会把没用到的section丢弃掉,最终的可执行文件就只包含用到了的函数和数据。链接的单位,是函数级别,这样就能丢弃没使用的函数。

当我们依赖静态库,编译和链接选项加如上所示后,应用程序变小,但是查看符号表等,发现一些库中的函数依然存在,于是经过一些时间的排查,发现应当添加上-fvisibility=hidden

背景 有时我们的程序会定义一些暂时使用不上的功能和函数,虽然我们不使用这些功能和函数,但它们往往会浪费我们的ROM和RAM的空间。这在使用静态库时,体现的更为严重。有时,我们只使用了静态库仅有的几个功能,但是系统默认会自动把整个静态库全部链接到可执行程序中,造成可执行程序的大小大大增加。

参数详解 为了解决前面分析的问题,我们引入了标题中的几个参数。GCC链接操作是以section作为最小的处理单元,只要一个section中的某个符号被引用,该section就会被加入到可执行程序中去。因此,GCC在编译时可以使用 -ffunction-sections 和 -fdata-sections 将每个函数或符号创建为一个sections,其中每个sections名与function或data名保持一致。而在链接阶段, -Wl,–gc-sections 指示链接器去掉不用的section(其中-wl, 表示后面的参数 -gc-sections 传递给链接器),这样就能减少最终的可执行程序的大小了。

我们常常使用下面的配置启用这个功能:

CFLAGS += -ffunction-sections -fdata-sections LDFLAGS += -Wl,–gc-sections


编译器gcc默认提供了5级优化选项的集合:

-O0:无优化(默认)。

-O和-O1:使用能减少目标文件大小以及执行时间并且不会使编译时间明显增加的优化。

在编译大型程序的时候会显著增加编译时内存的使用和时间。

-O2: 此选项将增加编译时间和目标文件的执行性能。

包含-O1的优化并增加了不需要在目标文件大小和执行速度上进行折衷的优化。

编译器不执行循环展开以及函数内联。

-Os:专门优化目标文件大小,执行所有的不增加目标文件大小的-O2优化选项,并且执行专门减小目标文件大小的优化选项。

-O3:打开所有-O2的优化选项并且增加 -finline-functions, -funswitch-loops,-fpredictive-commoning,-fgcse-after-reload and -ftree-vectorize优化选项。


为了减少运行时库的大小,我们应该使用交叉编译工具的strip工具来处理根文件系统的库文件,把二进制文件中的包含的符号表和调试信息删除掉。

例:#arm-linux-strip /home/su/rootfs/lib/*.so


CFLAGS=”-O2″,

LDFLAGS 是传递给连接器的选项。这是一个常被忽视的变量,事实上它对优化的影响也是很明显的。加入-s选项,删除可执行程序中的所有符号表和所有重定位信息。其结果与运行命令 strip 所达到的效果相同,这个选项是比较安全的。