web-dev-qa-db-fra.com

Comment utiliser CMake ExternalProject_Add ou des alternatives de manière multiplateforme?

Je voudrais construire un projet tiers qui a déjà CMake dans le cadre des bandes CMake de mon projet. ExternalProject_Add est à cet effet, mais j'ai trouvé qu'il ne peut être fait fonctionner qu'avec un générateur spécifique, et je voulais qu'il fonctionne facilement sur de nombreuses plates-formes.

Par exemple, voici mon projet externe avec un script ajouté pour zlib, qui a son propre CMakeLists.txt:

set(USE_PROJECT_CMAKE_MODULE_PATH "-DCMAKE_MODULE_PATH=${MAKE_MODULE_PATH}")
ExternalProject_Add(ZLIB
                    SOURCE_DIR ${CMAKE_SOURCE_DIR}/external/zlib
                    DOWNLOAD_COMMAND ""
                    UPDATE_COMMAND ""
                    CMAKE_ARGS
                       -DCMAKE_INSTALL_PREFIX=<INSTALL_DIR>
                       -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}
                       -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
                       -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
                       ${USE_PROJECT_CMAKE_MODULE_PATH}
                    INSTALL_COMMAND "")

ExternalProject_Add_Step(ZLIB installInternally
                         COMMAND cd <BINARY_DIR> && make install
                         DEPENDEES install
                         ALWAYS 1)
ExternalProject_Get_Property(ZLIB install_dir)

if(UNIX)
    set(ZLIB_NAME libz)
else(UNIX)
    set(ZLIB_NAME zlib)
endif(UNIX)

add_library(zlib UNKNOWN IMPORTED)
set_property(TARGET zlib PROPERTY IMPORTED_LOCATION ${install_dir}/lib/${ZLIB_NAME}.a)
set(ZLIB_LIBRARIES zlib)
set(ZLIB_LIBRARIES_OPTIONAL ${ZLIB_LIBRARIES})
set(ZLIB_DIR ${install_dir} CACHE INTERNAL "zlib ROOT dir")
set(ZLIB_INCLUDE_DIRS ${install_dir}/include CACHE INTERNAL "zlib include dirs")
set(ZLIB_DEFINES "-msse2 -mfpmath=sse" CACHE INTERNAL "zlib defines")

Le problème avec cela est qu'il fonctionne avec make, mais pas avec Xcode ou Visual Studio. Peut-être existe-t-il un moyen de prendre les commandes de build CMake transmises à mon projet et de les transmettre à ExternalProject_Add.

Comment puis-je écrire des appels ExternalProject_Add de manière multiplateforme avec une complexité de code minimale, ou existe-t-il une meilleure alternative?

30
Andrew Hundt

Problèmes

-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}

Cela suffit pour les projets à configuration unique. Mais pour Xcode et Visual Studio, vous devez définir CMAKE_CONFIGURATION_TYPES plus appel build . --config au stade de la construction. Voir ma réponse .

COMMAND cd <BINARY_DIR> && make install

Cela ne fonctionnera bien sûr que pour les générateurs Makefile. Pour être multiplateforme, vous pouvez utiliser:

--build . --target install --config à l'intérieur INSTALL_COMMAND de ExternalProject_Add.

Jetez un oeil à ce fichier modèle , et en particulier les lignes suivantes :

ExternalProject_Add(
    "${current_project}"
    URL
    @HUNTER_PACKAGE_URL@
    URL_HASH
    SHA1=@HUNTER_PACKAGE_SHA1@
    DOWNLOAD_DIR
    "@HUNTER_PACKAGE_DOWNLOAD_DIR@"
    SOURCE_DIR
    "@HUNTER_PACKAGE_SOURCE_DIR@"
    INSTALL_DIR
    "@HUNTER_PACKAGE_INSTALL_PREFIX@"
        # Not used, just avoid creating Install/<name> empty directory
    BUILD_COMMAND ""
        # This command is empty because all necessary targets will
        # be built on install stage
    CMAKE_ARGS
    "-G@CMAKE_GENERATOR@"
    "-C@HUNTER_CACHE_FILE@"
    "-C@HUNTER_ARGS_FILE@"
    "-D${postfix_name}=${${postfix_name}}"
    "-DCMAKE_BUILD_TYPE=${configuration}"
    "-DCMAKE_CONFIGURATION_TYPES=${configuration}"
    "-DCMAKE_INSTALL_PREFIX=@HUNTER_PACKAGE_INSTALL_PREFIX@"
    "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}"
    INSTALL_COMMAND
        "@CMAKE_COMMAND@"
        --build .
        --target install
        --config ${configuration}
        --
        ${jobs_option}
)

Alternative

ou existe-t-il une meilleure alternative?

Avez-vous vu Hunter ?

Vous pouvez ajouter zlib comme this :

hunter_add_package(ZLIB)
find_package(ZLIB CONFIG REQUIRED)
target_link_libraries(... ZLIB::zlib)

Ce code fonctionne partout. Les dépendances tierces seront téléchargées automatiquement lors de l'étape de configuration. Exemple de construction avec différents générateurs/chaînes d'outils ( build.py est juste un wrapper CMake qui définit CMAKE_TOOLCHAIN_FILE et -G/-B):

build.py --toolchain mingw --config Release # MinGW Makefiles
build.py --toolchain vs-12-2013 --config Debug # Visual Studio 12 2013
build.py --toolchain xcode --config Release # Xcode
build.py --toolchain libcxx --config Release # Makefile with -stdlib=libc++ toolchain
build.py --toolchain ios-8-2 --config Release # Xcode with iOS SDK 8.2 toolchain

Vous avez le contrôle total sur ce que options , types de build ou nombre de jobs que vous souhaitez avoir lors de la construction de packages tiers. Par exemple, voici comment vous pouvez créer quatre types, Debug, Release, MinSizeRel et RelWithDebInfo for zlib et lier MinSizeRel au projet en cours:

> build.py --toolchain xcode --verbose --config MinSizeRel --fwd "HUNTER_CONFIGURATION_TYPES=Release;Debug;MinSizeRel;RelWithDebInfo"
/.../clang  /.../lib/libz-MinSizeRel.a ... -o /.../_builds/xcode/MinSizeRel/foo

> ls -la /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz*
   99056 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz-MinSizeRel.a
  307872 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz-RelWithDebInfo.a
  109536 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libz.a
  258904 /.../.hunter/_Base/d1232c0/326318e/37e4682/Install/lib/libzd.a
26
user2288008

Les appels CMake ExternalProject_Add fonctionnent par défaut sur plusieurs plates-formes et ne le feront que si l'on utilise des commandes particulières qui ne sont disponibles que sur un sous-ensemble de systèmes d'exploitation.

En règle générale, CMAKE_ARGS est utilisé pour transmettre des informations à chaque unité de super-construction dans une génération de projet externe. Les fichiers CMakeLists.txt qui contrôlent chaque partie miniature de la construction globale utilisent la syntaxe déclarative de CMake (par exemple, "add_library (nom_bibliothèques SHARED nom_fichier1.hpp nom_fichier1.cpp)). CMake convertira cette syntaxe en commandes qui sont spécifiques au système de génération particulier vous souhaitez utiliser (par exemple, make et Ninja ).

L'exemple ci-dessus re: zlib ne parvient pas à être multiplateforme en partie parce que ExternalProject_Add_Step contient "COMMAND cd && make install", qui ne fonctionne nécessairement que dans les situations où l'invocation de "cd" est en fait la bonne façon de modifier les répertoires, et lorsque l'invocation " make "est en fait la bonne façon de créer un logiciel.

L'option -E de CMake fournit un moyen d'invoquer des opérations de base comme changer/copier/créer/supprimer des répertoires sans faire de telles hypothèses.

(Soit dit en passant, si vous utilisez des IDE tels que Visual Studio ou Xcode, vous souhaiterez probablement invoquer un ou plusieurs générateurs IDE lors de l'utilisation de CMake. Par exemple, définir

-G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_Eclipse_GENERATE_SOURCE_PROJECT=TRUE

entraînera la génération de projets Eclipse dans chaque zone de génération, ainsi que dans la zone de code source partagée pour toutes les générations. Bien sûr, si vous utilisez Xcode ou Visual Studio, vous devrez remplacer l'indicateur approprié pour ces IDE. Alternativement, vous pouvez envisager d'utiliser Eclipse avec Ninja sur toutes les plates-formes, bien qu'au moment de la rédaction, je ne suis pas complètement certain que Ninja soit prêt pour les heures de grande écoute sur les systèmes d'exploitation non Linux et non Windows.)

0
newbrific