所以我对GitLab CI有这种奇怪的行为。我得到了它的工作,但现在我想知道为什么它的工作。
首先,我开始使用GitLab CI。我在我的机器(Arch Linux)上有一个带有docker的本地跑步者,所以我可以在不推动和等待的情况下进行测试。我用googletest框架编写了一个测试(只是断言是真的)。我在本地触发了脚本,一切正常。所有测试都在本地docker镜像中传递。
现在,当一切正常时,我推到了存储库,一名跑步者接过了这份工作。这是在Ubuntu 16.04上运行的。现在它已编译,并在执行后抛出了一个分段错误。
我在Ubuntu系统上调试了一段时间后我切换了两个库的链接顺序:
来自:
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进行构建。
两台PC都运行相同版本的docker(17.12.0-ce)。
使用过的gcc码头图片是:sha256:95d81930694ca9e705b71dc141ddd13f466f4989857f74aebaf1d29ba6553775
显然这个问题是有联系的: Why does the order in which libraries are linked sometimes cause errors in GCC?
现在我的问题:当两个系统都运行一个docker容器时。为什么在这种情况下更改链接顺序可以解决问题?
答案 0 :(得分:2)
依赖关系。文件顺序很重要。
链接器一次处理一个静态库,并解析缺失的符号并将其拉入正在创建的可执行文件中。
因此,如果静态库(* .a)依赖于另一个静态库,则它必须出现在满足其缺失符号的静态库之前。
对象文件(* .o)已被消费"批发",因此对它们的订购不会太麻烦。
答案 1 :(得分:1)
在CMake中对此的正确解决方法是不手动调整顺序,而是正确地模拟不同目标之间的相互依赖关系。
这里的顺序依赖的确切性质是工具链依赖的(在gcc上,依赖必须在依赖于链接器命令行之前; MSVC不关心;其他工具链可以选择不同的顺序要求)。 CMake确保为给定工具链生成正确顺序的唯一方法是在CMake中明确建模依赖关系。
在您的示例中,您已建模了一个依赖项的平面列表:
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引入另外两个目标:
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
调用会建立从gmock
到gtest
的依赖关系。在CMake中总是模拟这样的静态库之间的直接依赖是非常重要的,否则你会遇到像你描述的那样的问题,一旦你的构建超过一定的复杂性,它就会迅速增长。
作为旁注,尽量不要在CMake文件中对库路径进行硬编码,因为这会使您的构建变得不可移植,并且可能会在不同的工具链上完全破坏。