使用 CMake 解决编译出来的so文件过大的问题

CMake加入的一些设置,简化编译结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
set(SIMPLIFY "ON")

if(SIMPLIFY STREQUAL "ON")
MESSAGE("catkin_make small libfile.so")
SET(CMAKE_BUILD_TYPE "Release")
# 删除调试符号
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 ()
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")
endif()

  1. 编译选项使用-Os,表示以最小化大小为优化方向,假如链接失败,则修改为-O2

在 CMakeLists.txt 文件中加入以下两行:

1
2
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s -O4 -Wall")

  1. 去除-g选项,进而去除调试信息

  2. 通过strip裁剪符号及调试信息

  3. 只导出必要符号

Linux默认导出所有符号,并不仅仅导出你开放的接口。

定义如下宏:

#define SYMBOL_EXPORT __attribute__ ((visibility("default")))

在你想导出的符号前加上SYMBOL_EXPORT就好。

同时,需要在脚本中增加如下编译选项: -fvisibility = hidden

譬如:导出符号是int add(int a, int b); 那么添加的结果就是SYMBOL_EXPORT int add(int a, int b);

通过这种方式只导出想导出的符号,也可以减小库大小。

default: 用它定义的符号将被导出,动态库中的函数默认是可见的。

hidden: 用它定义的符号将不被导出,并且不能从其它对象进行使用,动态库中的函数是被隐藏的。

default意味着该方法对其它模块是可见的。而hidden表示该方法符号不会被放到动态符号表里,所以其它模块(可执行文件或者动态库)不可以通过符号表访问该方法。这个选项可能导致编译失败,出现undef reference

还有一个选项 -fvisibility = inlines-hidden

  • 控制C++特性的使用,如无必要,则不使用C++的高级特性。

  • 屏蔽RTTI特性,增加编译选项-fno-rtti。

  • 对性能影响不大时,避免使用C++的inline特性,也就是增加编译选项 -fno-inline

  • 在不影响使用时,控制对STL的组件的使用。尤其iostream的相关模板类。

示例:

1
2
3
4
5
6
7
8
9
10
11
12
# 关闭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 = 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")
# 开启空间优化
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os")