Linux编译时如何减⼩so库⽂件的⼤⼩
Linux编译时如何减⼩so库⽂件的⼤⼩
今天问了我这个问题,我就顺便记录⼀下。客户问为什么libc.so⽂件再编译前和编译后的size不⼀样啊,staging 和 compile 两个dir下的 libc.so⼤⼩不⼀样,具体有什么区别吗?
这是是因为编译的时候还会⽤strip⼯具来处理库⽂件,把⼆进制⽂件中的包含的符号表和调试信息删除掉,所以库⽂件编译打包后会变⼩。
Strip⼯具是什么?
在linux下有个⼯具叫做strip,这是⼀个可以将linux下的可执⾏⽂件的符号表去除,减少每个可执⾏⽂件的⼤⼩,这对于嵌⼊式⽅⾯很有必要。但是没有了符号表也就意味着没有办法采⽤gdb进⾏调试,因为gdb调试是读取ELF⽂件头来获取符号表,⽅便调试,但strip之后,可执⾏⽂件的ELF⽂件头就没有.symtab这个符号表,有的仅是动态符号表。在strip之后nm libxxx.so是看不到符号表的,nm -D
libxxx.so可以看到动态符号表,但⽤处不⼤,但strip有个参数选项叫做--only-keep-debug,这个选项可以在strip的时候保留debug调试信息。
strip命令如何使⽤,可以⾃⾏搜索⼀下。
那我们再把问题拓展下:Linux编译时如何减⼩so动态库⽂件的⼤⼩
在⼀些嵌⼊式系统开发中,由于成本和资源的限制需要对动态库的⼤⼩进⾏限制,主要通过以下⼏种⽅法:
1. 编译选项使⽤-Os,编译优化;
2. 去掉-g选项,去除调试信息;
3. 通过strip⼯具裁剪符号及调试信息;
4. 只导出必要符号;Linux会默认导出所有符号,并不仅仅导出你开放的接⼝!
C++的还可以参照这⾥:
在Linux环境下编译如何减⼩可执⾏⽂件或者动态库的⼤⼩(C++)
操作步骤如下:
选型时,在同等功能时,尽量选择代码量少、占⽤空间⼩的开源的软件。
控制C++特性的使⽤,如⽆必要,则不使⽤C++的⾼级特性。
屏蔽RTTI特性,增加编译选项-fno-rtti。
屏蔽异常我,增加编译选项-fno-exceptions。
对性能影响不⼤时,避免使⽤C++的inline特性。
增加编译选项-fno-inline。
在不影响使⽤时,控制对STL的组件的使⽤。
避免使⽤STL的iostream的相关模板类。
构建⽬标动态库时,控制符号的可见性。
增加编译选项-fvisibility=hidden。
增加编译选项-fvisibility-inlines-hidden。
定义符号导出宏,如下代码。
#ifndef __has_attribute
#define __has_attribute(x) 0
#endif
#if (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4) && (__GNUC_MINOR__ > 2))) || __has_attribute(visibility) #define MY_EXPORT __attribute__((visibility("default")))
#define MY_IMPORT __attribute__((visibility("default")))
#else
#define MY_EXPORT
#define MY_IMPORT
#endif
// 在外部可见的符号上,使⽤上述宏修饰。
MY_EXPORT int foo(int a, int b);
对⽬标以及全部依赖,使⽤gc-sections特性。即:
编译源码时,增加选项-ffunction-sections -fdata-sections。
链接⽬标时,增加选项-Wl,--gc-sections。
链接⽬标时,增加选项-Wl,--icf=safe。
对⽬标以及全部依赖,使⽤特性。
编译源码时,增加选项-flto=full。
链接⽬标时,增加选项-flto=full。
构建⽬标时的外部依赖,均使⽤静态链接。⽐如:
静态链接STL库。
静态链接使⽤前述要求编译的依赖库。
构建⽬标时,要求编译器对⽬标占⽤的空间进⾏优化。
增加选项-Os。
假如链接失败,则修改为-O2。
链接时,对于Release版本,删除不必要的调试符号。
增加选项-s。
如下使⽤CMake的请求,描述选项。
# 关闭C++特性
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-inline")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
# 控制符号的可见性
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fvisibility=hidden")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility=hidden")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -fvisibility-inlines-hidden")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fvisibility-inlines-hidden")
# 删除调试符号
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
# 开启空间优化
if (APPLE)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Oz")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Oz")
else ()
cmake如何使用set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os")
endif ()
# 使⽤gc-section优化
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -ffunction-sections -fdata-sections")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -ffunction-sections -fdata-sections") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--gc-sections")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections")
# 使⽤icf优化
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--icf=safe")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--icf=safe")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--icf=safe")
# 使⽤LTO
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -flto=full")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto=full")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto=full")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -flto=full")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto=full")
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论