web-dev-qa-db-fra.com

Quelle est la bonne façon d'utiliser `pkg-config` à partir de` cmake`?

En regardant autour de moi, j'ai vu beaucoup de code comme celui-ci:

include(FindPkgConfig)
pkg_search_module(SDL2 REQUIRED sdl2)

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

Cependant, cela semble être une mauvaise façon de procéder, car il utilise uniquement les répertoires et bibliothèques include, mais les définitions, chemins d'accès aux bibliothèques et autres indicateurs ignorés qui pourraient être retournés par pkg-config.

Quelle serait la bonne façon de procéder et de vous assurer que tous les indicateurs de compilation et de lien renvoyés par pkg-config sont utilisés par la app compilée? Et y at-il une seule commande pour accomplir cela, c’est-à-dire quelque chose comme target_use(app SDL2)?

47
Grumbel

Tout d'abord, l'appel:

include(FindPkgConfig)

doit être remplacé par:

find_package(PkgConfig)

L’appel find_package() est plus flexible et offre des options telles que REQUIRED, qui font automatiquement les choses qu’il faudrait faire manuellement avec include().

Deuxièmement, appeler manuellement pkg-config devrait être évité autant que possible. CMake est livré avec un ensemble complet de définitions de paquets, trouvées sous Linux sous /usr/share/cmake-3.0/Modules/Find*cmake. Ceux-ci fournissent plus d'options et de choix à l'utilisateur qu'un appel brut à pkg_search_module().

En ce qui concerne la commande hypothétique target_use() mentionnée, CMake l’a déjà intégrée, de la même manière que PUBLIC | PRIVATE | INTERFACE. Un appel tel que target_include_directories(mytarget PUBLIC ...) entraînera l’utilisation automatique des répertoires d’inclusion dans chaque cible utilisant mytarget, par exemple. target_link_libraries(myapp mytarget). Cependant, ce mécanisme semble ne concerner que les bibliothèques créées dans le fichier CMakeLists.txt et ne fonctionne pas pour les bibliothèques acquises avec pkg_search_module(). L'appel add_library(bar SHARED IMPORTED) pourrait être utilisé pour cela, mais je ne me suis pas encore penché sur la question.

Quant à la question principale, cela fonctionne ici dans la plupart des cas:

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})

Le SDL2_CFLAGS_OTHER contient définit et d’autres indicateurs nécessaires au succès de la compilation. Les drapeaux SDL2_LIBRARY_DIRS et SDL2_LDFLAGS_OTHER sont cependant toujours ignorés, aucune idée de la fréquence à laquelle cela poserait problème.

Plus de documentation ici http://www.cmake.org/cmake/help/v3.0/module/FindPkgConfig.html

36
Grumbel

Il est rare que l'on ait seulement besoin de se connecter à SDL2. La réponse actuellement populaire utilise pkg_search_module() qui vérifie la présence de modules et utilise le premier module actif.

Il est plus probable que vous souhaitiez établir une liaison avec SDL2, SDL2_Mixer et SDL2_TTF, etc ... pkg_check_modules() pour tous les modules donnés.

# 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})

Clause de non-responsabilité: j'aurais simplement commenté la réponse de Grumbel si j'avais assez de cartes de rue avec stackoverflow.

5
fluxrider

La plupart des réponses disponibles ne permettent pas de configurer les en-têtes de la bibliothèque pkg-config. Après avoir médité sur le Documentation pour FindPkgConfig , je suis arrivé à une solution qui fournit également ceux-ci:

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>)

( Substituez votre cible à la place de <my-target> et toute bibliothèque à la place de <some-lib>, en conséquence. )

L'option IMPORTED_TARGET semble être la clé et rend tout disponible dans l'espace de noms PkgConfig::. C’était tout ce qui était requis et aussi tout ce qui devait être requis.

0
Eero Aaltonen
  1. Il n'y a pas de commande telle que target_use. Mais je connais plusieurs projets qui ont écrit une telle commande pour leur usage interne. Mais chaque projet veut passer des drapeaux ou des définitions supplémentaires, il n’a donc aucun sens de le faire en général avec CMake. Les bibliothèques basées sur des modèles C++ comme Eigen sont une autre raison de ne pas l'avoir.

  2. La manière décrite est souvent correcte. Cela peut différer d'une bibliothèque à l'autre, vous devrez alors ajouter _LDFLAGS ou _CFLAGS. Une raison de plus pour ne pas avoir target_use. Si cela ne fonctionne pas pour vous, posez une nouvelle question sur SDL2 ou sur la bibliothèque que vous souhaitez utiliser.

0
usr1234567