gcc 链接LLVM导致gcov失败

6rqinv9w  于 2023-02-19  发布在  其他
关注(0)|答案(1)|浏览(268)

--coverage传递给gcc同时链接LLVM会导致链接器出现undefined reference to__gcov_exit'`错误。我已经建立了一个新的项目来尝试隔离这个问题。您可以使用view the source on githubinspect 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'
nwlqm0z1

nwlqm0z11#

一开始我认为这是一个微不足道的修复(与 -fprofile-arcs -ftest-coverage -lgcov * 标记相关的东西),正如[Man7]: GCC(1)--coverage * 选项)中所指出的那样,但事实并非如此。
我无法在我的 * Ubuntu 16 pc064**VM * 上重现这个问题(虽然 * Travis * 非常好,但对于调试目的来说有点慢(特别是由于匆忙,编辑时可能会忘记或添加额外的字符:)),而且它也不提供与本地计算机相同的访问级别,)因为环境:

    • CMake 3.5.1版本 *
    • 通用条款第5.4.0条 *
    • 低层虚拟机3.8.0 *

与 * Travis**Docker * 映像上的内容相差甚远。我必须指出,我既没有尝试从源代码构建软件包(这可能会引起很多麻烦),也没有尝试从 * CI * 构建期间下载软件包的存储库下载它们(甚至没有检查这些存储库是否是公共的)。

这是吃我活着,所以我结束了建设***48***该死的时间(对 * 特拉维斯 *),以获得它的工作,这只是因为我没有注意到显而易见的。

问题

对于3种配置中的每一种,我将粘贴生成的编译和链接(* G ++)命令(从您的构建版本:[Travis CI]: Kerndog73/gcov_error - Build #24
1.
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

1.* 覆盖范围 *:

/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

1.* 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

在大量的幽灵追逐之后,我注意到当包含 * LLVM * 时,-L/usr/lib/gcc/x86_64-linux-gnu/4.8被传递到链接器。 GCC 4.8安装在 * Docker * 上的,所以很明显 * GCC7.4用于编译, GCC4.8用于链接,这是*UndefinedB行为
我还粘贴了 * Collect * 命令(更靠近链接器),它来自
**#3的一个小变体(带有 -v )。(所有带有 *-l但没有完整路径的库(例如,-lgcov -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 )在2个相关版本之间的某处进行了修改(添加了**__gcov_exit符号), G ++* 知道它有一个,但 * Ld * 没有提供(因为错误的 * lib ),因此出现错误。
现在,**为什么
LLVM * 要添加这个库搜索路径,我不知道(可能是因为它是用 * GCC 4.8 * 构建的--或者是用与之相近的 * smth * 构建的),但我可以想到的是:
1.
LLVM * 不适用于 * GCC 7 (尽管我在快速浏览[LLVM]: Getting Started with the LLVM System时没有发现任何此类限制)
1.
LLVM * 中的一个bug(考虑到我遇到的另一个问题,我倾向于认为这是赢家)
我为他们找到了方法:

  • 使用旧版 * G ++ v4.8 *-默认安装在 * Docker * 上)
  • export CXX=g++(甚至可能不需要)
    • G (这次不是CMake *)不知道 * cxx_std_17 *,所以最简单的方法是移除传入的 * target_compile_features *(缺点是代码将不符合 * C17 *)
  • 由于我不知道如何"撤消"传递(错误的)库搜索路径,所以我想到的解决方法是在之前指定正确的路径。
  • 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 * 和其他一些)。

相关问题