CMake: две библиотеки, одно и то же расположение общих объектов, одна не найдена во время выполнения - PullRequest
0 голосов
/ 14 июля 2020

Я пытаюсь создать C библиотеку libmy, которая зависит от внешней библиотеки libext. И libmy, и libext используют CMake. Кроме того, libext фактически создает два общих объекта, libext1.so и libext2.so, оба из которых необходимы libmy.

Сначала я устанавливаю libext с настраиваемым модулем CMake в разделе ${CMAKE_BINARY_DIR}/ext. Процесс проходит успешно, и я получаю следующее дерево:

${CMAKE_BINARY_DIR}
└── ext
    └── lib
        ├── libext1.so
        └── libext2.so

Чтобы протестировать libmy, я создаю несколько тестовых примеров для цели mytest, которые связаны с общими объектами libmy.so, libext1.so и libext2.so.

Процесс сборки всех целей завершается успешно. Но когда я пытаюсь запустить mytest, я получаю знаменитый не могу открыть файл общих объектов: такого файла или каталога нет, но только для libext1.so, а libext2.so правильно найден. Однако что очень любопытно, так это то, что и libext1.so, и libext2.so расположены по одному и тому же пути, а libext2.so действительно успешно связан во время выполнения. Вот что выводит LD_DEBUG=libs mytest:

10703:  find library=libext2.so [0]; searching
10703:   search path=/usr/local/lib:/home/user/mylib/build/ext/lib:x86_64:      (RUNPATH from file src/test/mytest)
10703:    trying file=/usr/local/lib/libext2.so
10703:    trying file=/home/user/mylib/build/ext/lib/libext2.so
10703:      
10703:  find library=libext1.so [0]; searching
10703:   search cache=/etc/ld.so.cache
10703:    trying file=/usr/local/lib/libext1.so
10703:   search path=/lib/x86_64-linux-gnu/tls/haswell/x86_64:[...truncated long search path (/home/user/mylib/build/ext/lib is not here)...]:/usr/lib      (system search path)
10703:    trying file=/lib/x86_64-linux-gnu/tls/haswell/x86_64/libext1.so
          ...
10703:    trying file=/usr/lib/haswell/libext1.so
10703:    trying file=/usr/lib/x86_64/libext1.so
10703:    trying file=/usr/lib/libext1.so
10703:  
src/test/myest: error while loading shared libraries: libext1.so: cannot open shared object file: No such file or directory

Итак, по какой-то причине для поиска libext1.so используется системный путь поиска (который не включает путь к внешней библиотеке), а для libext2.so используется RUNPATH (у которого есть правильный путь).

Модуль CMake, в котором я создаю внешнюю библиотеку, в основном делает следующее:

include(ExternalProject)
set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/ext)

ExternalProject_Add(extproject
  GIT_REPOSITORY https://github.com/ext/ext.git
  CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION})

include_directories(${EXTERNAL_INSTALL_LOCATION}/include)
link_directories(${EXTERNAL_INSTALL_LOCATION}/lib)

set(EXT_INCLUDE_DIR ${EXTERNAL_INSTALL_LOCATION}/include)
set(EXT1_LIBRARY ext1)
set(EXT2_LIBRARY ext2)

И CMakeLists.txt файл, в котором создается mytest, содержит:

add_executable(mytest mytest.cpp)
target_include_directories (mytest
  PUBLIC
  ${EXT_INCLUDE_DIR})
target_link_libraries(mytest
  my
  ${EXT1_LIBRARY}  
  ${EXT2_LIBRARY})
add_test(NAME mytest COMMAND mytest)

Заявление об ограничении ответственности : Я дал упрощение сценария, так как библиотека довольно большая, а процесс сборки содержит несколько других компонентов. Но, надеюсь, этого достаточно.

1 Ответ

0 голосов
/ 15 июля 2020

Проблема была немного незаметной.

Оказывается, libext2.so внутренне также зависит от libext1.so. Эта информация не отображается в LD_LEBUG=libs mytest, поэтому я подумал, что зависимость от libext1.so пришла непосредственно из libmy.so, которому она действительно нужна. Однако запуск LD_DEBUG=all mytest выводит:

11540:  file=libext1.so [0];  needed by /home/user/mylib/build/external/lib/libext2.so [0]

Вот почему установка RPATH или RUNPATH для всех целей libmy не дала никакого эффекта, я думаю, потому что RPATH / RUNPATH для libext является устанавливается внутри CMake этого проекта и, следовательно, не зависит от способа сборки libmy.

Поскольку я не хочу изменять сценарии CMake для libext (я хочу использовать сценарии по умолчанию этим проектом), все, что я могу сделать (afaik), - это передать дополнительные аргументы команде ExternalProject_Add. Следующее работает:

include(ExternalProject)
set(EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/ext)

ExternalProject_Add(extproject
  GIT_REPOSITORY https://github.com/ext/ext.git
  CMAKE_ARGS 
  -DCMAKE_INSTALL_PREFIX=${EXTERNAL_INSTALL_LOCATION}
  -DCMAKE_INSTALL_RPATH=${EXTERNAL_INSTALL_LOCATION}/lib)

include_directories(${EXTERNAL_INSTALL_LOCATION}/include)
link_directories(${EXTERNAL_INSTALL_RPATH}/lib)

set(EXT_INCLUDE_DIR ${EXTERNAL_INSTALL_LOCATION}/include)
set(EXT1_LIBRARY ext1)
set(EXT2_LIBRARY ext2)

(обратите внимание на дополнительный аргумент -DCMAKE_INSTALL_RPATH=${EXTERNAL_INSTALL_LOCATION}/lib в инструкции ExternalProject_Add.)

Это устанавливает RPATH так, что libext2.so можно найти libext1.so во время выполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...