J’essaie de faire fonctionner un système de construction multi-plateformes en utilisant CMake. 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 un find_package()
qui ouvre un fichier Find*.cmake
et qui recherche la bibliothèque du système et définit certaines variables comme 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 des recherches après le Find*.cmake
et j’ai ajouté le répertoire de SomeLib
où FindSomeLib.cmake
peut être trouvé, donc 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 non croisés.
Comment cela se fait-il habituellement? Dois-je copier le répertoire cmake/
de SomeLib
dans mon projet et définir le CMAKE_MODULE_PATH
relativement?
La commande find_package
a deux modes: le mode Module
et le mode Config
. Vous essayez d’utiliser le mode Module
lorsque vous avez réellement besoin du mode Config
.
Find
fichier Find
situé dans votre projet. Quelque chose comme ça:
CMakeLists.txt cmake/FindFoo.cmake cmake/FindBoo.cmake
Contenu CMakeLists.txt
:
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
.
Fichier
situé à l’ extérieur et produit par la commande install
d’un autre projet ( Foo
par exemple).
foo
library:
> 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 projet par défaut 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 imscope:
> 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 imscope est hautement configurable. Voir ma réponse
Mettre à jour
Comment cela se fait-il habituellement? Dois-je copier le répertoire
cmake/
de SomeLib dans mon projet et définir le CMAKE_MODULE_PATH relativement?
Si vous ne faites pas confiance à CMake pour avoir ce module, alors – oui, faites-le . C’est ce que je fais comme solution de rechange.
Notez que les modules FindFoo.cmake
sont chacun une sorte de pont entre la dépendance à la plate-forme et l’indépendance de la plate-forme – ils recherchent des chemins dans des variables dont les noms sont indépendants de la plate-forme.
Vous n’avez pas besoin de spécifier le chemin du module en soi. CMake est livré avec son propre ensemble de scripts find_package intégrés, et leur emplacement est défini par défaut sur CMAKE_MODULE_PATH.
Le cas d’utilisation plus normal des projets dépendants ayant été CMakeified serait d’utiliser la commande external_project de CMake, puis d’inclure le fichier Use [Project] .cmake du sous-projet. Si vous avez juste besoin du script Find [Project] .cmake, copiez-le du sous-projet et dans le code source de votre propre projet, et vous n’aurez pas besoin d’augmenter le CMAKE_MODULE_PATH pour trouver le sous-projet au niveau du système.
Si vous exécutez cmake
pour générer vous-même SomeLib
(par exemple dans le cadre d’une super-construction), envisagez d’utiliser le registre des packages utilisateur . 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 à l’aide du mode CONFIG
de la commande find_packages () , vous verrez que le registre de packages utilisateur est l’un des éléments.
Brève comment faire
Associez les cibles de SomeLib
dont vous avez besoin en dehors de ce projet externe en les ajoutant à un jeu d’export dans les fichiers CMakeLists.txt
où elles sont 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 des packages utilisateur en ajoutant deux appels à export () vers CMakeLists.txt
associé à SomeLib
:
export(EXPORT SomeLib-export NAMESPACE SomeLib:: FILE SomeLibConfig.cmake) # Create SomeLibConfig.cmake export(PACKAGE SomeLib) # Store location of SomeLibConfig.cmake
find_package(SomeLib REQUIRED)
votre commande find_package(SomeLib REQUIRED)
dans le fichier CMakeLists.txt
du projet qui dépend de SomeLib
sans le bricolage des “chemins non codés sur plusieurs plates-formes” avec CMAKE_MODULE_PATH
.
Quand cela pourrait être la bonne approche
Cette approche est probablement la mieux adaptée aux situations où vous n’utiliserez jamais votre logiciel en aval du répertoire de construction (par exemple, vous effectuez une compilation croisée et n’installez jamais rien sur votre machine, ou vous construisez le logiciel uniquement pour exécuter des tests sur votre ordinateur). le répertoire de construction), car il crée un lien vers un fichier .cmake dans votre sortie “build”, qui peut être temporaire.
Mais si vous n’installez jamais SomeLib
dans votre stream de travail, l’appel d’ EXPORT(PACKAGE
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., donc l’excellente réponse de @ user2288008 vous couvrira.