链接LLVM导致gcov失败 [英] Linking LLVM causes gcov to fail

查看:280
本文介绍了链接LLVM导致gcov失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在同时链接LLVM的同时将--coverage传递给gcc会导致链接器出现undefined reference to `__gcov_exit'错误.我建立了一个新项目来尝试解决此问题.您可以在github上查看源代码

Passing --coverage to gcc while also linking LLVM causes an undefined reference to `__gcov_exit' error from the linker. I've set up a fresh project to try to isolate this problem. You can view the source on github and inspect the compiler output on Travis-CI.

这是coverage版本和非coverage版本之间的区别

This is the difference between a coverage and a non-coverage build

-DCMAKE_CXX_FLAGS="--coverage"

这是LLVM和非LLVM内部版本之间的区别

This is the difference between an LLVM and a non-LLVM build

target_link_libraries(Test
        PUBLIC
        LLVMCore
)

LLVM作业成功. Coverage作业成功. LLVM + Coverage作业失败,并显示此错误

The LLVM job succeeds. The Coverage job succeeds. The LLVM + Coverage job fails with this error

undefined reference to `__gcov_exit'

推荐答案

注释:

  • Check [cmake 3.13]: CMAKE_<LANG>_FLAGS for details regarding which env var affects which cmake var - as you figured out in your (deleted) answer
  • Only noticed cxx_std_17 from cmake 3.8, so you might want to update your cmake_minimum_required
  • Forked your repo to [GitHub]: CristiFati/gcov_error - An attempt to reproduce the gcov/llvm linker error and did some debugging on it - beware, I might delete it someday
  • Was able to get my head around Travis CI, it's a real gold-mine

在一开始,我认为这将是一个简单的修复程序(与 -fprofile-arcs -ftest-coverage -lgcov相关的标志),如 [man7]:GCC(1)(-coverage 选项),但不是.
我无法在我的 Ubtu 16 x64 VM 上重现该问题(尽管 travis 很好,但调试时有点慢(尤其是由于匆忙而造成的,在编辑时可能会忘记或添加一个额外的字符:)),并且它没有提供与本地计算机相同的访问级别,),因为环境:

At the beginning I thought that it would be a trivial fix (something related to -fprofile-arcs, -ftest-coverage, -lgcov flags) as noted in [man7]: GCC(1) (--coverage option), but it wasn't.
I wasn't able to reproduce the problem on my Ubtu 16 x64 VM (although travis is very nice, it's kind of slow for debugging purposes (especially when due to rushing one might forget or add an extra character when editing :) ) and also it doesn't offer the same access level that a local machine does,) because the environment:

  • cmake 3.5.1
  • gcc 5.4.0
  • llvm 3.8.0
  • cmake 3.5.1
  • gcc 5.4.0
  • llvm 3.8.0

travis docker 映像上的图像相去甚远.我必须提到,我既没有尝试从源代码构建软件包(这可能会引起很多麻烦),也没有尝试从在 CI 构建期间下载它们的存储库中下载它们.甚至检查这些回购是否公开).无论如何, VM 几乎无法使用,因为:

is pretty far away from what's on the travis docker image. I must mention that neither I tried building the packages from sources (that would probably have caused lots of headaches), nor did I try downloading them from the repositories where they are downloaded during CI builds (didn't even check if those repos are public). Anyway the VM was pretty much unusable because:

  • I couldn't reproduce the issue (after some minor changes to adapt to older tools,) everything worked
  • More: I ran into [SO]: Error when using CMake with LLVM - (@CristiFati's answer)

它正在吞噬着我,所以我最终建立了 48 怪胎时间(在 travis 上),以使其正常运行,并且那只是因为我没注意到明显的事.

It was eating me alive, so I ended up building 48 freaking times (on travis) in order to get it working, and that is only because I failed to notice the obvious.

问题

对于这3种配置,我将分别粘贴生成的 compile link ( g ++ )命令(来自您的版本: [Travis CI]:Kerndog73/gcov_error -版本#24 )

For each of the 3 configurations I'm going to paste the compile and link (g++) commands generated (from your build: [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

  • 覆盖率:

    /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 + 覆盖率:

  • LLVM + Coverage:

    /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 进行链接,这是未定义行为.
    我还将 命令(更接近 linker )粘贴了轻微变化(带有 -v ) > #3. (所有用 -l * 指定的库,但没有完整路径(例如 -lgcov -lgcc_s -lgcc )的版本为错误,因为将从错误的目录中提取该版本):

    After lots of ghosts chasing, I noticed -L/usr/lib/gcc/x86_64-linux-gnu/4.8 being passed to the linker when llvm is included. gcc 4.8 is installed on the docker, so apparently gcc 7.4 was used for compilation, and gcc 4.8 for linking, which is Undefined Behavior.
    I'm also pasting the collect command (closer to the linker) from a slight variation (with -v) of #3. (all the libraries specified with -l* and without the full path (e.g. -lgcov, -lgcc_s, -lgcc) have the wrong version because will be picked up from the wrong directory):

    /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 部分中的一些测试命令产生了以下输出:

    Some test commands placed in .travis.yml's after_script section, yielded the following output:

    $ _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),因此出现了错误.

    So, libgcc (libgcov.a) was modified somewhere between the 2 involved versions (__gcov_exit symbol was added), and g++ knew it has one but ld didn't provide it (because of the wrong lib) hence the error.

    现在,为什么会添加 llvm 这个库搜索路径,我不知道(可能是因为它是使用 gcc 4.8 构建的-或接近),但这是我能想到的:

    Now, why does llvm add this library search path, I don't know (probably because it was built with gcc 4.8 - or smth close to it), but here's what I can think of:

    1. llvm 不能与 gcc 7 一起使用(尽管在快速浏览
    1. llvm is not meant to be used with gcc 7 (although I didn't find any such restriction while quickly browsing [LLVM]: Getting Started with the LLVM System)
    2. A bug in llvm (considering the other issue that I ran into, I tend to think this is the winner)

    我找到了两种方法:

    1. 使用较旧的 g ++ ( 4.8 -默认安装在 docker 上)

    • export CXX=g++(甚至可能没有必要)
    • g ++ (这次不是不是 cmake )不知道 cxx_std_17 ,所以最简单的方法是删除传入的 target_compile_features (缺点是代码不会与 C ++ 17 兼容")
    • export CXX=g++ (might even not be necessary)
    • g++ (not cmake this time) doesn't know about cxx_std_17, so the easiest way is to remove the afferent target_compile_features (the drawback is that code won't be C++17 "compliant")

    由于我不知道如何撤消"通过(错误的)库搜索路径,因此我想到的解决方法是在之前指定正确的路径.

    Since I don't know how to "undo" passing the (faulty) library search path, the workaround that I came up with is to specify the correct one before it.

    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 等).

    Note: I tried to come up with something more elegant (I'm sure that it is), but I couldn't (tried using CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES, target_link_libraries, link_directories and a few more) at this point.

    这篇关于链接LLVM导致gcov失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆