J'essaie de faire fonctionner CMake avec un système de construction multi-plateformes. Maintenant, le logiciel a quelques dépendances. Je les ai compilés moi-même et les ai installés sur mon système.
Quelques exemples de fichiers installés:
-- Installing: /usr/local/share/SomeLib/SomeDir/somefile
-- Installing: /usr/local/share/SomeLib/SomeDir/someotherfile
-- Installing: /usr/local/lib/SomeLib/somesharedlibrary
-- Installing: /usr/local/lib/SomeLib/cmake/FindSomeLib.cmake
-- Installing: /usr/local/lib/SomeLib/cmake/HelperFile.cmake
Maintenant, CMake a une find_package()
qui ouvre un fichier Find*.cmake
, recherche la bibliothèque sur le système et définit des variables telles que SomeLib_FOUND
etc.
Mon CMakeLists.txt contient quelque chose comme ceci:
set(CMAKE_MODULE_PATH "/usr/local/lib/SomeLib/cmake/;${CMAKE_MODULE_PATH}")
find_package(SomeLib REQUIRED)
La première commande définit où CMake effectue ses recherches après le Find*.cmake
et j'ai ajouté le répertoire de SomeLib
où le FindSomeLib.cmake
peut être trouvé, de sorte que find_package()
fonctionne comme prévu.
Mais c’est un peu étrange, car l’une des raisons pour lesquelles find_package()
existe est de s’éloigner des chemins codés en dur sans la plate-forme croisée.
Comment cela se fait-il habituellement? Dois-je copier le répertoire cmake/
de SomeLib
dans mon projet et définir relativement le CMAKE_MODULE_PATH
?
La commande find_package
a deux modes: le mode Module
et le mode Config
. Vous essayez d'utiliser le mode Module
alors que vous avez réellement besoin du mode Config
.
Find<package>.cmake
fichier situé dans de votre projet. Quelque chose comme ça:
CMakeLists.txt
cmake/FindFoo.cmake
cmake/FindBoo.cmake
CMakeLists.txt
contenu:
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
find_package(Foo REQUIRED) # FOO_INCLUDE_DIR, FOO_LIBRARIES
find_package(Boo REQUIRED) # BOO_INCLUDE_DIR, BOO_LIBRARIES
include_directories("${FOO_INCLUDE_DIR}")
include_directories("${BOO_INCLUDE_DIR}")
add_executable(Bar Bar.hpp Bar.cpp)
target_link_libraries(Bar ${FOO_LIBRARIES} ${BOO_LIBRARIES})
Notez que CMAKE_MODULE_PATH
a une priorité élevée et peut être utile lorsque vous devez réécrire le fichier standard Find<package>.cmake
.
<package>Config.cmake
fichier situé à l'extérieur et produit par la commande install
d'un autre projet (Foo
par exemple).
foo
bibliothèque:
> cat CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(Foo)
add_library(foo Foo.hpp Foo.cpp)
install(FILES Foo.hpp DESTINATION include)
install(TARGETS foo DESTINATION lib)
install(FILES FooConfig.cmake DESTINATION lib/cmake/Foo)
Version simplifiée du fichier de configuration:
> cat FooConfig.cmake
add_library(foo STATIC IMPORTED)
find_library(FOO_LIBRARY_PATH foo HINTS "${CMAKE_CURRENT_LIST_DIR}/../../")
set_target_properties(foo PROPERTIES IMPORTED_LOCATION "${FOO_LIBRARY_PATH}")
Par défaut, le projet installé dans le répertoire CMAKE_INSTALL_PREFIX
:
> cmake -H. -B_builds
> cmake --build _builds --target install
-- Install configuration: ""
-- Installing: /usr/local/include/Foo.hpp
-- Installing: /usr/local/lib/libfoo.a
-- Installing: /usr/local/lib/cmake/Foo/FooConfig.cmake
Utilisez find_package(... CONFIG)
pour inclure FooConfig.cmake
avec la cible importée foo
:
> cat CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(Boo)
# import library target `foo`
find_package(Foo CONFIG REQUIRED)
add_executable(boo Boo.cpp Boo.hpp)
target_link_libraries(boo foo)
> cmake -H. -B_builds -DCMAKE_VERBOSE_MAKEFILE=ON
> cmake --build _builds
Linking CXX executable Boo
/usr/bin/c++ ... -o Boo /usr/local/lib/libfoo.a
Notez que la cible importée est hautement configurable. Voir mon réponse .
Mettre à jour
Si vous utilisez cmake
pour générer SomeLib
vous-même (par exemple, dans le cadre d'un super-build), envisagez d'utiliser le ser Package Registry . Cela ne nécessite aucun chemin codé en dur et est multi-plateforme. Sous Windows (y compris mingw64), cela fonctionne via le registre. Si vous examinez comment la liste des préfixes d'installation est construite par le mode CONFIG
de la commande find_packages () , vous verrez que le registre de packages utilisateur est l'un des éléments.
bref comment faire
Associez les cibles de SomeLib
dont vous avez besoin en dehors de ce projet externe en les ajoutant à un ensemble d'exportation dans les fichiers CMakeLists.txt
où elles ont été créées:
add_library(thingInSomeLib ...)
install(TARGETS thingInSomeLib Export SomeLib-export DESTINATION lib)
Créez un fichier XXXConfig.cmake
pour SomeLib
dans son ${CMAKE_CURRENT_BUILD_DIR}
et stockez cet emplacement dans le registre de packages utilisateur en ajoutant deux appels à export () dans le CMakeLists.txt
associé à SomeLib
:
export(EXPORT SomeLib-export NAMESPACE SomeLib:: FILE SomeLibConfig.cmake) # Create SomeLibConfig.cmake
export(PACKAGE SomeLib) # Store location of SomeLibConfig.cmake
Émettez votre commande find_package(SomeLib REQUIRED)
dans le fichier CMakeLists.txt
du projet qui dépend de SomeLib
sans les "chemins codés en dur non multiplateformes" avec le CMAKE_MODULE_PATH
.
Quand cela pourrait être la bonne approche
Cette approche convient probablement mieux aux situations dans lesquelles vous n’utiliserez jamais votre logiciel en aval du répertoire de construction (par exemple, vous n’effectuez pas de compilation croisée et n’installez jamais rien sur votre ordinateur, ou vous construisez le logiciel uniquement pour exécuter des tests le répertoire de construction), car il crée un lien vers un fichier .cmake dans votre sortie "build", ce qui peut être temporaire.
Mais si vous n'installez jamais réellement SomeLib
dans votre flux de travail, l'appel de EXPORT(PACKAGE <name>)
vous permet d'éviter le chemin codé en dur. Et, bien sûr, si vous installez SomeLib
, vous connaissez probablement votre plate-forme, CMAKE_MODULE_PATH
, etc., de sorte que l'excellente réponse de @ user2288008 saura vous couvrir.
Comment cela se fait-il habituellement? Devrais-je copier le répertoire
cmake/
de SomeLib dans mon projet et définir relativement CMAKE_MODULE_PATH?
Si vous ne faites pas confiance à CMake pour avoir ce module, alors - oui, faites-le - en quelque sorte: Copiez le find_SomeLib.cmake
et ses dépendances dans votre répertoire cmake/
. C'est ce que je fais comme solution de secours. C'est une solution laide cependant.
Notez que les modules FindFoo.cmake
constituent chacun une sorte de pont entre dépendance à la plate-forme et indépendance de la plate-forme. Ils examinent différents emplacements spécifiques à la plate-forme pour obtenir des chemins dans des variables dont le nom est indépendant de la plate-forme.
Vous n'avez pas besoin de spécifier le chemin du module en tant que tel. CMake est livré avec son propre ensemble de scripts find_package intégrés et leur emplacement est l'emplacement par défaut CMAKE_MODULE_PATH.
Le cas d'utilisation plus normal pour les projets dépendants qui ont été CMakeified serait d'utiliser la commande external_project de CMake puis d'inclure le fichier. Use [Projet] .cmake du sous-projet. Si vous avez simplement besoin du script Find [Project] .cmake, copiez-le hors du sous-projet et dans le code source de votre propre projet. Vous n'aurez alors pas besoin d'étendre CMAKE_MODULE_PATH pour trouver le sous-projet au niveau du système.