Ker*_*g73 4 c++ gcc cmake llvm gcov
--coverage在链接 LLVM 的同时传递给 gcc 会导致undefined reference to `__gcov_exit'链接器出错。我已经建立了一个新项目来尝试隔离这个问题。您可以在 github 上查看源代码并在 Travis-CI 上检查编译器输出。
这是覆盖和非覆盖构建之间的区别
-DCMAKE_CXX_FLAGS="--coverage"
Run Code Online (Sandbox Code Playgroud)
这是 LLVM 和非 LLVM 构建之间的区别
target_link_libraries(Test
PUBLIC
LLVMCore
)
Run Code Online (Sandbox Code Playgroud)
该LLVM作业成功。该Coverage作业成功。该LLVM + Coverage作业失败,出现此错误
undefined reference to `__gcov_exit'
Run Code Online (Sandbox Code Playgroud)
注意事项:
一开始我认为这将是一个微不足道的修复(与-fprofile-arcs、-ftest-coverage、-lgcov标志相关),如[man7]: GCC(1)(--coverage选项)中所述,但它不是。
我无法在我的Ubtu 16 x64 VM上重现该问题(尽管travis非常好,但出于调试目的它有点慢(尤其是当编辑时匆忙可能忘记或添加额外字符时:))以及它不提供与本地机器相同的访问级别,)因为环境:
与travis docker图像上的内容相去甚远。我必须提到,我既没有尝试从源代码构建包(这可能会引起很多麻烦),也没有尝试从在CI构建期间下载它们的存储库下载它们(甚至没有检查这些存储库是否是公开的) )。无论如何,VM几乎无法使用,因为:
它让我活着,所以我最终构建了48次(在travis 上)以使其正常工作,这只是因为我没有注意到明显的情况。
问题
对于 3 个配置中的每一个,我将粘贴生成的编译和链接( g++ ) 命令(来自您的构建:[Travis CI]: Kerndog73 / gcov_error - Build #24)
LLVM:
Run Code Online (Sandbox Code Playgroud)/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp /usr/bin/g++-7 -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread -lm /usr/lib/llvm-7/lib/libLLVMDemangle.a
覆盖范围:
Run Code Online (Sandbox Code Playgroud)/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include --coverage -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp /usr/bin/g++-7 --coverage -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test
LLVM +覆盖范围:
Run Code Online (Sandbox Code Playgroud)/usr/bin/g++-7 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/usr/lib/llvm-7/include --coverage -std=gnu++1z -o CMakeFiles/Test.dir/main.cpp.o -c /home/travis/build/Kerndog73/gcov_error/main.cpp /usr/bin/g++-7 --coverage -rdynamic CMakeFiles/Test.dir/main.cpp.o -o Test -L/usr/lib/gcc/x86_64-linux-gnu/4.8 /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread -lm /usr/lib/llvm-7/lib/libLLVMDemangle.a
在追了很多鬼之后,我注意到当包含llvm时,-L/usr/lib/gcc/x86_64-linux-gnu/4.8被传递给链接器。GCC 4.8被安装在码头工人,因此显然GCC 7.4被用于汇编,和GCC 4.8用于链接,这是未定义行为。我还从#3的轻微变化(使用-v)粘贴了collect命令(更接近链接器)。(所有用-l*指定但没有完整路径的库(例如-lgcov,
-lgcc_s , -lgcc ) 有错误的版本,因为将从错误的目录中提取):
Run Code Online (Sandbox Code Playgroud)/usr/lib/gcc/x86_64-linux-gnu/7/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/7/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper -plugin-opt=-fresolution=/tmp/ccyDh97q.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --sysroot=/ --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -export-dynamic -dynamic-linker /lib64/ld-linux-x86-64.so.2 -z relro -o Test /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/7/crtbegin.o -L/usr/lib/gcc/x86_64-linux-gnu/4.8 -L/usr/lib/gcc/x86_64-linux-gnu/7 -L/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/7/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/7/../../.. CMakeFiles/Test.dir/main.cpp.o /usr/lib/llvm-7/lib/libLLVMCore.a /usr/lib/llvm-7/lib/libLLVMBinaryFormat.a /usr/lib/llvm-7/lib/libLLVMSupport.a -lz -lrt -ldl -ltinfo -lpthread /usr/lib/llvm-7/lib/libLLVMDemangle.a -lstdc++ -lm -lgcov -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-linux-gnu/7/crtend.o /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.0
.travis.yml的after_script部分中的一些测试命令产生了以下输出:
Run Code Online (Sandbox Code Playgroud)$ _GCOV_LIB7=/usr/lib/gcc/x86_64-linux-gnu/7/libgcov.a $ (nm -S ${_GCOV_LIB7} 2>/dev/null | grep __gcov_exit) || echo ${_GCOV_LIB7} 0000000000001e40 000000000000008b T __gcov_exit $ _GCOV_LIB48=/usr/lib/gcc/x86_64-linux-gnu/4.8/libgcov.a $ (nm -S ${_GCOV_LIB48} 2>/dev/null | grep __gcov_exit) || echo ${_GCOV_LIB48} /usr/lib/gcc/x86_64-linux-gnu/4.8/libgcov.a
因此,libgcc ( libgcov.a ) 在 2 个相关版本之间的某个地方进行了修改(添加了__gcov_exit符号),并且g++知道它有一个,但ld没有提供它(因为错误的 lib)因此出现错误。
现在,为什么不LLVM添加此库搜索路径,我不知道(可能是因为它与内置GCC 4.8 -水木清华或接近),但这里是我能想到的:
我为他们找到了方法:
使用较旧的g++(4.8 - 默认安装在docker 上)
export CXX=g++ (甚至可能没有必要)由于我不知道如何“撤消”传递(错误的)库搜索路径,因此我想出的解决方法是在它之前指定正确的路径。
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(gcov_test)
find_package(LLVM 7.0.0 REQUIRED CONFIG)
message(STATUS "Found LLVM: ${LLVM_DIR} ${LLVM_PACKAGE_VERSION}")
add_executable(Test
"main.cpp"
)
target_compile_features(Test
PUBLIC cxx_std_17
)
target_include_directories(Test
PUBLIC ${LLVM_INCLUDE_DIRS}
)
target_compile_definitions(Test
PUBLIC ${LLVM_DEFINITIONS}
)
if(LINK_WITH_LLVM)
# @TODO - cfati: Everything in this block is to avoid hardcoding default libgcc path (/usr/lib/gcc/x86_64-linux-gnu/7)
set(_COLLECT_LTO_WRAPPER_TEXT "COLLECT_LTO_WRAPPER=")
execute_process(
COMMAND bash -c "$0 -v 2>&1 | grep ${_COLLECT_LTO_WRAPPER_TEXT} | sed s/${_COLLECT_LTO_WRAPPER_TEXT}//" "${CMAKE_CXX_COMPILER}"
OUTPUT_VARIABLE _GAINARIE_COLLECT_TMP_VAR
)
get_filename_component(_GAINARIE_GCC_DEFAULT_PATH ${_GAINARIE_COLLECT_TMP_VAR} DIRECTORY)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${_GAINARIE_GCC_DEFAULT_PATH}")
#set (GCCOPT "${GCCOPT} -L${_GAINARIE_GCC_DEFAULT_PATH}")
# @TODO END
target_link_libraries(Test
PUBLIC LLVMCore
)
endif()
Run Code Online (Sandbox Code Playgroud)
注:我想拿出一些更优雅(我敢肯定,这是),但我不能(尝试使用CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES,target_link_libraries,link_directories在这一点上多了一些)。
| 归档时间: |
|
| 查看次数: |
769 次 |
| 最近记录: |