Подтвердить что ты не робот

Каков правильный способ использования `pkg-config` из` cmake`?

Оглядываясь в сети, я видел много такого кода:

include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)

target_include_directories(app SYSTEM PUBLIC ${SDL2_INCLUDE_DIRS}
target_link_libraries(app ${SDL2_LIBRARIES})

Однако это кажется неправильным способом, поскольку он использует только каталоги и библиотеки include, но игнорирует определения, пути к библиотекам и другие флаги, которые могут быть возвращены pkg-config.

Как правильно сделать это и убедиться, что все флаги компиляции и ссылки, возвращаемые pkg-config, используются скомпилированным app? И есть ли одна команда для этого, то есть что-то вроде target_use(app SDL2)?

ссылка:

4b9b3361

Ответ 1

Другие методы, показанные ниже, не могут настроить пути компоновщика для тех общих библиотек, которые не находятся в типичных установленных местах (например,/usr/lib). В результате возникла ошибка компоновщика /usr/bin/ld: cannot find -llibrary-1.0. В моем случае файлы pkg-config также не были установлены, а пути pkg-config для проекта были добавлены с помощью переменной среды PKG_CONFIG_PATH. Это развернутая версия рабочего CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project(ya-project C)

find_package(PkgConfig REQUIRED)

pkg_check_modules(MY_PKG REQUIRED IMPORTED_TARGET any-package)
pkg_check_modules(YOUR_PKG REQUIRED IMPORTED_TARGET ya-package)

add_executable(program-name file.c ya.c)

target_link_libraries(program-name
        PkgConfig::MY_PKG
        PkgConfig::YOUR_PKG)

Ответ 2

Во-первых, звонок:

include(FindPkgConfig)

следует заменить на:

find_package(PkgConfig)

Вызов find_package() является более гибким и позволяет использовать такие опции, как REQUIRED, которые автоматически выполняют действия, которые нужно было бы делать вручную с include().

Во-вторых, следует избегать ручного вызова pkg-config, когда это возможно. CMake поставляется с богатым набором определений пакетов, которые можно найти в Linux под /usr/share/cmake-3.0/Modules/Find*cmake. Они предоставляют больше возможностей и выбора для пользователя, чем необработанный вызов pkg_search_module().

Что касается упомянутой гипотетической команды target_use(), CMake уже имеет такую встроенную функцию с помощью PUBLIC | PRIVATE | INTERFACE. Такой вызов, как target_include_directories(mytarget PUBLIC ...), приведет к тому, что включаемые каталоги будут автоматически использоваться в каждой цели, которая использует mytarget, например, target_link_libraries(myapp mytarget). Однако этот механизм, по-видимому, предназначен только для библиотек, созданных в файле CMakeLists.txt, и не работает для библиотек, приобретенных с помощью pkg_search_module(). Для этого можно использовать вызов add_library(bar SHARED IMPORTED), но я еще не рассматривал это.

Что касается основного вопроса, то здесь это работает в большинстве случаев:

find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2)
...
target_link_libraries(testapp ${SDL2_LIBRARIES})
target_include_directories(testapp PUBLIC ${SDL2_INCLUDE_DIRS})
target_compile_options(testapp PUBLIC ${SDL2_CFLAGS_OTHER})

SDL2_CFLAGS_OTHER содержит определения и другие флаги, необходимые для успешной компиляции. Флаги SDL2_LIBRARY_DIRS и SDL2_LDFLAGS_OTHER, тем не менее, по-прежнему игнорируются, не зная, как часто это станет проблемой.

Больше документации здесь http://www.cmake.org/cmake/help/v3.0/module/FindPkgConfig.html

Ответ 3

Редко, что нужно было бы связать только с SDL2. В популярном в настоящее время ответе используется pkg_search_module(), который проверяет данные модули и использует первый рабочий.

Скорее всего, вы хотите установить связь с SDL2 и SDL2_Mixer и SDL2_TTF и т.д. pkg_check_modules() проверяет все данные модули.

# sdl2 linking variables
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL2 REQUIRED sdl2 SDL2_ttf SDL2_mixer SDL2_image)

# your app
file(GLOB SRC "my_app/*.c")
add_executable(my_app ${SRC})
target_link_libraries(my_app ${SDL2_LIBRARIES})
target_include_directories(my_app PUBLIC ${SDL2_INCLUDE_DIRS})
target_compile_options(my_app PUBLIC ${SDL2_CFLAGS_OTHER})

Отказ от ответственности: я бы просто прокомментировал сам ответ Громбеля, если у меня было достаточно уличных кредитов с помощью stackoverflow.

Ответ 4

Большинству доступных ответов не удается настроить заголовки для библиотеки pkg-config. После размышления над Документацией для FindPkgConfig я пришел к решению, которое также обеспечивает это:

include(FindPkgConfig)
if(NOT PKG_CONFIG_FOUND)
  message(FATAL_ERROR "pkg-config not found!" )
endif()

pkg_check_modules(<some-lib> REQUIRED IMPORTED_TARGET <some-lib>)

target_link_libraries(<my-target> PkgConfig::<some-lib>)

(Замените вашу цель вместо <my-target> и любую библиотеку вместо <some-lib>, соответственно.)

Опция IMPORTED_TARGET кажется ключевой и делает все PkgConfig:: пространстве имен PkgConfig::. Это было все, что требовалось, а также все, что требовалось.

Ответ 5

  • Нет такой команды, как target_use. Но я знаю несколько проектов, которые написали такую ​​команду для их внутреннего использования. Но каждый проект хочет передать дополнительные флаги или определяет, поэтому нет смысла иметь его вообще в CMake. Еще одна причина, по которой это не так: С++-шаблонные библиотеки, такие как Eigen, нет библиотеки, но у вас есть только куча включенных файлов.

  • Описанный способ часто бывает правильным. Это может различаться для некоторых библиотек, тогда вам придется добавить _LDFLAGS или _CFLAGS. Еще одна причина отсутствия target_use. Если это не сработает для вас, задайте новый вопрос, касающийся SDL2 или любой другой библиотеки, которую вы хотите использовать.

Ответ 6

Если вы хотите добавить определения из библиотеки, для этого есть инструкция add_definitions. Документацию можно найти здесь, а также дополнительные способы добавления флагов компилятора.

Следующий фрагмент кода использует эту инструкцию для добавления GTKGL в проект:

pkg_check_modules(GTKGL REQUIRED gtkglext-1.0)
include_directories(${GTKGL_INCLUDE_DIRS})
link_directories(${GTKGL_LIBRARY_DIRS})
add_definitions(${GTKGL_CFLAGS_OTHER})
set(LIBS ${LIBS} ${GTKGL_LIBRARIES})

target_link_libraries([insert name of program] ${LIBS})