CMake: две библиотеки, одинаковое расположение общих объектов, одна не найдена во время выполнения

Я пытаюсь создать библиотеку 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)

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


person Ginswich    schedule 14.07.2020    source источник


Ответы (1)


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

Оказывается, 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 (я хочу использовать в этом проекте сценарии по умолчанию), все, что я могу сделать (на самом деле), это передать дополнительные аргументы команде 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 во время выполнения.

person Ginswich    schedule 15.07.2020