为什么更改链接顺序可以解决一个系统上的某些链接错误? [英] Why does changing the linking order fix some linking errors on one system?

查看:107
本文介绍了为什么更改链接顺序可以解决一个系统上的某些链接错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我在GitLab CI上有这种奇怪的行为.我可以使用它,但是现在我想知道为什么它可以使用.

So I had this strange behavior with GitLab CI. I got it working but now I am wondering why it works.

首先,我从GitLab CI开始.我在机器(Arch Linux)上安装了docker本地运行程序,因此我无需等待就可以进行测试.我用googletest框架编写了一个测试(只有一个断言为true).我在本地触发了脚本,一切正常.所有测试均在本地docker映像中通过.

First of all I was starting with GitLab CI. I got a local runner with docker on my machine (Arch Linux), so that I can test without pushing and waiting. I wrote a test with the googletest framework (Just an assert true). I triggered the script locally and everything worked. All tests passed in the local docker image.

现在,当一切正常时,我推到存储库中,一个跑步者接了这份工作.它在Ubuntu 16.04上运行.现在,它进行了编译,执行后引发了分段错误.

So now, when everything was working, I pushed to the repository and a runner took the job. This ran on Ubuntu 16.04. Now it compiled and after the execution it was throwing a segmentation fault.

我要在Ubuntu系统上进行调试,过了一会儿,我切换了两个库的链接顺序:

I got to debugging at the Ubuntu system and after a while I switched the linking order of two libraries:

发件人:

target_link_libraries(${PROJECT_NAME}_test PRIVATE Threads::Threads -lglog -lpthread
    ${QT_LIBRARIES}
    ${PROJECT_BINARY_DIR}/googletest-build/googlemock/libgmock.a
    ${PROJECT_BINARY_DIR}/googletest-build/googlemock/gtest/libgtest.a
    ${OpenCV_LIBRARIES}
)

收件人:

target_link_libraries(${PROJECT_NAME}_test PRIVATE Threads::Threads -lglog -lpthread
    ${QT_LIBRARIES}
    ${OpenCV_LIBRARIES}
    ${PROJECT_BINARY_DIR}/googletest-build/googlemock/libgmock.a
    ${PROJECT_BINARY_DIR}/googletest-build/googlemock/gtest/libgtest.a
)

我正在使用CMake进行构建.

I am using CMake for the build.

两台PC都运行相同版本的docker(17.12.0-ce).

Both PCs are running the same version of docker (17.12.0-ce).

使用的gcc docker映像为:sha256:95d81930694ca9e705b71dc141ddd13f466f4989857f74aebaf1d29ba6553775

The used gcc docker image is: sha256:95d81930694ca9e705b71dc141ddd13f466f4989857f74aebaf1d29ba6553775

显然,这个问题是联系在一起的: 为什么下订单在其中链接的库有时会导致GCC错误?

Appareantly this question is linked: Why does the order in which libraries are linked sometimes cause errors in GCC?

现在我的问题是:当两个系统都运行一个docker容器时.为什么在这种情况下更改链接顺序可以解决问题?

Now my question: When both systems run a docker container. Why does changing the linking order in this case fix the problem?

推荐答案

在CMake中,对此的正确解决方案不是 手动调整顺序,而是建模不同目标之间的相互依赖性.正确.

The proper solution to this in CMake is not to adjust the order manually, but rather to model the inter-dependencies between different targets correctly.

这里的顺序依赖关系的确切性质是依赖于工具链的(在gcc上,依赖对象必须先于链接器命令行的依赖关系; MSVC不在乎;其他工具链可能会选择不同的顺序要求). CMake确保为给定工具链生成正确顺序的唯一方法是通过在CMake中显式建模依赖项.

The exact nature of the order dependency here is toolchain dependent (on gcc, dependees have to come before dependencies on the linker command line; MSVC doesn't care; other toolchains may choose different order requirements). The only way for CMake to ensure that it generates the correct order for the given toolchain is by modelling the dependencies explicitly in CMake.

在您的示例中,您对依赖关系的平面列表进行了建模:

In your example you have modeled a flat list of dependencies:

target_link_libraries(${PROJECT_NAME}_test PRIVATE Threads::Threads -lglog -lpthread
    ${QT_LIBRARIES}
    ${OpenCV_LIBRARIES}
    ${PROJECT_BINARY_DIR}/googletest-build/googlemock/libgmock.a
    ${PROJECT_BINARY_DIR}/googletest-build/googlemock/gtest/libgtest.a
)

您有一个目标${PROJECT_NAME}_test,它取决于一堆库.但这实际上是错误的!实际上,从gmock到gtest都有一个依赖性,您没有告诉过CMake.您需要显式地对此依赖关系建模,以使CMake正常工作.由于只能在目标之间指定依赖关系,因此我们需要为gtest和gmock引入两个其他目标:

You have a single target ${PROJECT_NAME}_test that depends on a bunch of libraries. But that is actually wrong! In reality, there is a dependency from gmock to gtest which you didn't tell CMake about. You need to model this dependency explicitly in order for CMake to work correctly. Since dependencies can only be specified between targets, we need to introduce two additional targets for gtest and gmock:

add_library(gtest INTERFACE)
target_link_libraries(gtest INTERFACE ${PROJECT_BINARY_DIR}/googletest-build/googlemock/gtest/libgtest.a)
add_library(gmock INTERFACE)
target_link_libraries(gmock INTERFACE ${PROJECT_BINARY_DIR}/googletest-build/googlemock/libgmock.a)
target_link_libraries(gmock INTERFACE gtest)   # now gmock depends on gtest

target_link_libraries(${PROJECT_NAME}_test PRIVATE Threads::Threads -lglog -lpthread
    ${QT_LIBRARIES}
    ${OpenCV_LIBRARIES}
    gtest
    gmock     # order doesn't matter here;
              # you can even omit gtest completely now
)

请注意此处的target_link_libraries调用建立了从gmockgtest的依赖关系.在CMake中始终对静态库之间的直接依赖关系进行建模非常重要,否则您将遇到您所描述的问题,一旦构建超出一定的复杂度,这些问题就会迅速蔓延.

Note the target_link_libraries call here that establishes the dependency from gmock to gtest. It is very important to always model direct dependencies between static libraries like this in CMake, otherwise you will get problems like the one you described, which can quickly grow over your head once your build exceeds a certain complexity.

请注意,请不要在CMake文件中对库路径进行硬编码,因为这再次使您的构建不可移植,并可能在不同的工具链上完全中断.

As a side note, try not to hard-code library paths in your CMake files, as that again makes your build non-portable and may break completely on different toolchains.

这篇关于为什么更改链接顺序可以解决一个系统上的某些链接错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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