Относительное связывание CMake, исполняемый файл не может найти общие библиотеки - PullRequest
0 голосов
/ 01 февраля 2020

Я пытаюсь изучить CMake, и для этого я работаю с примером проекта структуры, показанной ниже. Я пытаюсь настроить все файлы CMakeLists.txt так, чтобы после make install я мог скопировать результирующий каталог build и свободно копировать и вставлять его так, чтобы другие люди могли запускать исполняемый файл.

Проблема: после запуска make install (maxOS 10.14.6 (Дарвин 18.7.0)) все работает, если я запускаю исполняемый файл внутри build НО, если я перемещаю каталог сборки из Исходное местоположение - например, для рабочего стола - исполняемый файл не может найти общие библиотеки. Кажется, причина этого в том, что пути к разделяемым библиотекам определяются как абсолютные пути, а не относительные пути по отношению к каталогу сборки.

Вопрос: Как я могу собрать проект такой, что исполняемый файл находит разделяемые библиотеки?

Структура проекта:

myapp
  |
  CMakeLists.txt (top-level)
  - build
  - app 
  |   CMakeLists.txt (app)
  |   - inc
  |       - app
  |          app.h  
  |   - src
  |      app.cpp
  |      main.cpp
  |    
  - external
      | 
      - mylib
          CMakeLists.txt (mylib)
          - inc
             - mylib
                mylib.h
          - src
             mylib.cpp

CMakeLists:

CMakeLists.txt (верхнего уровня)

cmake_minimum_required(VERSION 3.0)

project(myapp)

add_subdirectory(external/mylib)
add_subdirectory(app)

CMakeLists.txt (приложение)

# myapp program

cmake_minimum_required(VERSION 3.0)

project(myapp_prog)

set(SOURCES ./src/)
set(HEADERS ./inc/app/)

set(SOURCE_FILES
        ${SOURCES}/app.cpp)

set(HEADER_FILES
        ${HEADERS}/app.h)


# All sources that need to be tested in unit test go into a static library
add_library(myapp_lib SHARED ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories(myapp_lib PUBLIC ${HEADERS})

# The main program
add_executable(prog ./src/main.cpp)
target_include_directories(prog PUBLIC ./inc/)

# Link the libraries
target_link_libraries(prog PRIVATE myapp_lib mylib)

install(TARGETS myapp_lib DESTINATION ${CMAKE_BINARY_DIR}/lib)

CMakeLists.txt (mylib)

# mylib

cmake_minimum_required(VERSION 3.0)

project(mylib)

set(SOURCES src/)

set(HEADERS inc/mylib/)

set(SOURCE_FILES
     ${SOURCES}/mylib.cpp)

set(HEADER_FILES
    ${HEADERS}/mylib.h)

add_library(mylib SHARED ${HEADER_FILES} ${SOURCE_FILES})

target_include_directories(mylib PUBLIC inc/)

install(TARGETS mylib DESTINATION ${CMAKE_BINARY_DIR}/lib)


C ++ код:

mylib.h

void mylib_print_hello();

mylib. cpp

#include "library.h"

#include <iostream>

void mylib_print_hello() {
    std::cout << "Hello from mylib!" << std::endl;
}

app.h

void myapp_hello();

app. cpp

#include <iostream>
#include "app.h"

void myapp_hello()
{
    std::cout << "Hello from myapp!" << std::endl;
}

main. cpp


#include <iostream>
#include "app/app.h"
#include "mylib/mylib.h"

int main()
{
    myapp_hello();
    mylib_print_hello();

}

Ответы [ 2 ]

0 голосов
/ 02 февраля 2020

Пожалуйста, добавьте тег macos к этому вопросу.

Я думаю, что вы ищете относительную RPATH . CMake создает исполняемый файл с абсолютным значением RPATH, поэтому, если вы переместите или переименуете каталог сборки, программа перестанет работать. В вашем примере вам нужно всего лишь изменить основную программу CMakeLists.txt, чтобы изменить значения RPATH, которые CMake вставляет в ваш исполняемый файл.

# The main program
add_executable(prog ./src/main.cpp)
target_include_directories(prog PUBLIC ./inc/)
set_target_properties(prog PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH "@executable_path/;@executable_path/../external/mylib")

Вы можете проверить значения LC_RPATH s с помощью этой команды из вашего каталога сборки:

$ otool -l app/prog

Для зависимостей между библиотеками может быть также полезно "@loader_path" вместо @executable_path. А для других Unix операционных систем используйте «$ ORIGIN». Больше информации здесь .

0 голосов
/ 01 февраля 2020

Я думаю, проблема в том, что вы, возможно, путаете этап сборки с этапом установки. Используя $ {CMAKE_BINARY_DIR}, вы передаете абсолютный путь к вашему двоичному каталогу (сборка), который впоследствии может помешать перемещению сборки. Если вы хотите вывести свои библиотеки в папку после сборки, вы можете установить цель библиотеки с помощью:

set_target_property(<library-name> PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"

Это повлияет только на этап сборки вашего проекта. Что касается установки go, вам лучше использовать только относительные пути в директивах установки. Эти пути будут относиться к вашей переменной $ {CMAKE_INSTALL_PREFIX}. Например, вы должны использовать:

install(TARGETS mylib DESTINATION lib)

Для установки библиотеки в папку $ {CMAKE_INSTALL_PREFIX} / lib. Наилучшая практика гласит, что вы должны НИКОГДА манипулировать этой переменной непосредственно в ваших файлах CMakeLists.txt, так как это может нарушить компоновку где-нибудь в будущем. Начиная с CMake 3.15, можно использовать cmake --install для установки проекта. Эта команда позволяет установить префикс установки, например:

cmake --install . --prefix desired/install/path

При этом весь путь ссылки должен оставаться действительным.

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