将--coverage
传递给gcc并同时链接LLVM会导致链接器发生undefined reference to `__gcov_exit'
错误。我建立了一个新项目来尝试解决此问题。您可以view the source on github和inspect the compiler output on Travis-CI。
这是coverage和非coverage版本之间的区别
-DCMAKE_CXX_FLAGS="--coverage"
这是LLVM和非LLVM内部版本之间的区别
target_link_libraries(Test
PUBLIC
LLVMCore
)
LLVM
工作成功。 Coverage
工作成功。 LLVM + Coverage
作业因此错误而失败
undefined reference to `__gcov_exit'
对此将提供任何帮助。
答案 0 :(得分:2)
注释:
在一开始,我认为这将是一个简单的修复(与 -fprofile-arcs , -ftest-coverage , -lgcov有关的标志)(如[man7]: GCC(1)(-coverage 选项)所述,但不是。
我无法在我的 Ubtu 16 x64 VM 上重现该问题(尽管 travis 很好,但调试时有点慢(尤其是由于匆忙而造成的,在编辑时可能会忘记或添加一个额外的字符:)),并且它没有提供与本地计算机相同的访问级别,),因为环境:
与 travis docker 映像上的图像相去甚远。我必须提到,我既没有尝试从源代码构建软件包(这可能会引起很多麻烦),也没有尝试从在 CI 构建期间下载它们的存储库中下载它们。甚至检查这些回购是否公开)。无论如何, VM 几乎无法使用,因为:
它正在吞噬着我,所以我最终建立了 48 怪胎时间(在 travis 上),以使其正常运行,并且那只是因为我没注意到明显的事。
问题
对于这3种配置,我将分别粘贴生成的 compile 和 link ( g ++ )命令(来自您的版本:[Travis CI]: Kerndog73 / gcov_error - Build #24)
LLVM :
/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
覆盖率:
/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 + 覆盖率:
/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
在追逐大量鬼影之后,我注意到 -L / usr / lib / gcc / x86_64-linux-gnu / 4.8 被传递给链接器包括llvm 。在 docker 上安装了 gcc 4.8 ,因此显然 gcc 7.4 用于编译和 gcc 4.8 进行链接,这是未定义行为。
我还粘贴了 collect 命令(更靠近 linker ),该命令的细微变化(带有 -v ) strong> #3。 (所有用 -l * 指定且没有完整路径的库(例如 -lgcov ,< em> -lgcc_s , -lgcc )的版本为错误,因为将从错误的目录中提取该版本):
/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 部分中的一些测试命令产生以下输出:
$ _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 )在两个涉及的版本( __ gcov_exit 符号)之间进行了修改。被添加),并且 g ++ 知道它有一个,但是 ld 没有提供它(由于错误的lib),因此出现了错误。
现在,为什么会添加 llvm 这个库搜索路径,我不知道(可能是因为它是使用 gcc 4.8 构建的-或接近),但这是我能想到的:
我找到了两种方法:
使用较旧的 g ++ ( 4.8 -默认安装在 docker 上)
export CXX=g++
(可能没有必要)由于我不知道如何“撤消”通过(错误的)库搜索路径,因此我想到的解决方法是在之前指定正确的路径。 / p>
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()
注意:我试图提出更优雅的方法(我敢肯定是这样),但我做不到(使用 CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES 尝试过, > target_link_libraries , link_directories 等)。