Почему изменение порядка связывания исправляет некоторые ошибки связывания в одной системе?

Так что у меня было странное поведение с GitLab CI. Я получил это работает, но теперь мне интересно, почему это работает.

Прежде всего я начал с GitLab CI. На моей машине есть локальный бегун с докером (Arch Linux), так что я могу тестировать, не нажимая и не ожидая. Я написал тест с каркасом googletest (просто верно). Я запустил скрипт локально, и все заработало. Все тесты пройдены в локальном докере.

Так что теперь, когда все работало, я подтолкнул к хранилищу, и бегун взял работу. Это работало на 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 для сборки.

На обоих ПК установлена ​​одна и та же версия докера (17.12.0-ce).

Используемое изображение док-станции gcc: sha256: 95d81930694ca9e705b71dc141ddd13f466f4989857f74aebaf1d29ba6553775

Видимо, этот вопрос связан:
Почему порядок, в котором связаны библиотеки, иногда вызывает ошибки в GCC?

Теперь мой вопрос: когда обе системы запускают докер-контейнер. Почему изменение порядка ссылок в этом случае решает проблему?

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, так как это снова делает вашу сборку непереносимой и может полностью сломаться на разных наборах инструментов.

1

Другие решения

Зависимости. Порядок файлов имеет значение.

Компоновщик обрабатывает статические библиотеки по одной, обрабатывает недостающие символы и помещает их в создаваемый исполняемый файл.

Поэтому, если статическая библиотека (* .a) имеет зависимости от другой статической библиотеки, она должна появиться перед статической библиотекой, которая выполняет свои отсутствующие символы.

Объектные файлы (* .o) потребляются «оптом», поэтому заказ на них не составляет особого труда.

2

По вопросам рекламы [email protected]