Почему CMake сконструирован так, что он удаляет путь выполнения во время установки

Я сам построил свою общую библиотеку (например, я использую lib, вычисляю число фибоначчи), и хочу использовать его в другом проекте c++, созданном CMake

Скажем, общая библиотека и заголовки, расположенные в /path/to/my/lib, разделяемая библиотека libfib.so находится в /path/to/my/lib/lib а заголовок fib.h находится в /path/to/my/lib/include и мой собственный проект, расположенный в /path/to/my/project

Вот мой оригинальный CMakeLists.txt:

cmake_minimum_required(VERSION 3.2)
project(learn-lib)
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
set(FIB_INCLUDE "${FIB_PREFIX}/include")
set(FIB_LIB "${FIB_PREFIX}/lib")
set(EXE mybin)
include_directories(${FIB_INCLUDE})
link_directories(${FIB_LIB})
add_executable(${EXE} main.cpp)
target_link_libraries(${EXE} fib)
install(TARGETS ${EXE} RUNTIME DESTINATION bin)

И я использую этот скрипт для создания и установки моего проекта:

mkdir -p build_dir
cd build_dir
cmake -DFIB_PREFIX=/path/to/my/lib \
      -DCMAKE_INSTALL_PREFIX=/path/to/my/project \
      ..
make
make install
cd ..

Теперь, после запуска скрипта установки, я получил два исполняемых файла: один в build_dir, один в пути установки path/to/my/project/bin, при запуске программы в build_dir, все в порядке, но при запуске установленной программы, Я получил:

./bin/mybin: ошибка при загрузке разделяемых библиотек: libfib.so: невозможно открыть файл общих объектов: нет такого файла или каталога

После некоторого поиска в google и stackoverflow я понял, что CMake удалил путь поиска во время выполнения, который привязан к исполняемому файлу при его создании. Теперь я знаю два способа добиться этого:

  1. Добавить путь библиотеки, где libfib.so находит переменную окружения LD_LIBRARY_PATH
  2. Добавьте set_target_properties(${EXE} PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) в мой CMakeLists.txt

Итак, мои вопросы:

  1. Почему CMake спроектирован так? При установке, почему он удаляет путь выполнения из исполняемых файлов вместо того, чтобы просто копировать созданные исполняемые файлы в место установки или что-либо, поддерживающее путь ссылки для установленной программы?
  2. Каким образом наилучшая практика (или есть лучшая практика) для устранения этой проблемы? Чтобы установить среду или добавить set_target_properties(...) в CMakeLists.txt?

Ответы

Ответ 1

Вы можете посмотреть настройки обработки CMake RPATH

Эта цитата, в частности, имеет отношение к вашему затруднительному положению:

По умолчанию, если вы не изменяете какие-либо связанные с RPATH настройки, CMake свяжет исполняемые файлы и общие библиотеки с полным RPATH ко всем используемым библиотекам в дереве сборки. При установке он очистит RPATH этих целей, чтобы они были установлены с пустым RPATH.

Вы можете установить RPATH, установленный для установленных двоичных файлов, используя переменную CMAKE_INSTALL_RPATH, например:

SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")

и вы также можете отключить вскрытие RPATH во время установки:

SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

Ответ 2

Я просто хочу ответить на вопрос 1. Почему это сделано. Алекс уже опубликовал решение, как изменить это поведение.

Причина в том, что когда вы собираете его, вы действительно хотите использовать библиотеки, которые скрипт сборки видел на вашем компьютере. Если вы создаете целый стек библиотек для своего приложения, вы не должны заблуждаться, что они не выбраны библиотекой. Поэтому имеет смысл использовать полный путь к библиотеке. Кроме того, вы никогда не перемещаете свое приложение между компиляцией и когда она отлажена и запущена.

Но при установке обычным случаем в мире Unix было использование каталогов shared/usr/lib и /usr/local/lib. Они обычно выбираются (если не используется LD_LIBRARY_PATH), и это обычно то, что вы хотите.

Как вы видите из моей формулировки, все это беспорядок, потому что он включает в себя очень много неявных решений о том, как организовать сборку и развертывание. Это одна из причин того, что термин "ад DLL", когда-то популярный только в Windows, перешел на Unix, когда он стал более широко использоваться. Технического решения не существует, потому что это не техническая проблема (эта часть решена). Это организационная проблема, и CMake должен решить, какой из вариантов он поддерживает на платформе по умолчанию. И ИМХО они выбрали мудро.