为什么相同编译命令下CMake生成的.o目标文件大小与手动编译不同
问题1:相同编译命令生成的目标文件大小存在差异的原因
核心原因是GCC生成的调试信息中携带了编译时的工作目录路径:
- 你使用
RelWithDebInfo编译模式时会携带-g参数,生成的DWARF格式调试信息中会记录DW_AT_comp_dir字段存储当前工作目录的绝对路径 - 两次编译的工作目录分别为
build和mybuild,两个路径的长度存在差异,存储到目标文件的调试信息段后自然会产生大小差,你遇到的8字节差值刚好对应两个路径的长度差。
你可以执行以下命令验证差异:
# 分别查看两个目标文件的调试字符串段,对比工作目录记录 readelf -p .debug_str build/main.cpp.o | grep comp_dir readelf -p .debug_str mybuild/main.cpp.o | grep comp_dir
问题2:调整CMake配置实现一致编译结果的方案
根据是否需要保留调试信息,有两种可行方案:
- 不需要调试信息的场景:将
CMAKE_BUILD_TYPE改为Release,去掉-g编译参数,自然不会携带路径相关的调试信息,编译结果大小会完全一致。 - 需要保留调试信息的场景:给GCC添加路径映射编译参数,将CMake构建目录的路径统一映射为手动编译的工作目录路径,示例配置如下:
# 放在CMakeLists.txt的project指令之后即可 set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fdebug-prefix-map=${CMAKE_BINARY_DIR}=/home/CMakeExample/mybuild")
如果还存在源文件路径差异导致的__FILE__宏不一致问题,可以额外添加-ffile-prefix-map参数统一源文件路径:
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -ffile-prefix-map=${CMAKE_SOURCE_DIR}=/home/CMakeExample/source")
配置完成后重新编译,即可得到和手动编译大小完全一致的目标文件。
内容的提问来源于stack exchange,提问作者W. Stalin R.
相关产品推荐
相关产品推荐

