88 votes

Ajout de plusieurs exécutables dans CMake

Mon code dans un projet C++ est organisé comme suit

  • J'ai plusieurs .cpp y .h qui contient mes classes
  • J'ai plusieurs .cxx qui doivent être compilés par rapport à l .cpp et certaines bibliothèques externes.

Maintenant, chacun des .cxx Les fichiers ont un main() Je dois donc ajouter un exécutable différent pour chacun de ces fichiers ayant le même nom que le fichier.

De plus, ces .cxx peuvent ne pas être liés aux mêmes bibliothèques externes.

Je veux écrire cette construction en CMake, dans lequel je suis un peu un débutant, comment dois-je procéder ?

124voto

Andre Points 5805

Je vous suggère d'aborder cette question en deux phases :

  1. Construire une bibliothèque à partir du .cpp y .h en utilisant add_library
  2. Faire un itération dans tous vos .cxx et créer un exécutable à partir de chacun d'entre eux, en utilisant add_executable y foreach

Construire la bibliothèque

Cela peut être quelque chose d'aussi simple que

file( GLOB LIB_SOURCES lib/*.cpp )
file( GLOB LIB_HEADERS lib/*.h )
add_library( YourLib ${LIB_SOURCES} ${LIB_HEADERS} )

Construire tous les exécutables

Il suffit de boucler sur tous les fichiers .cpp et de créer des exécutables séparés.

# If necessary, use the RELATIVE flag, otherwise each source file may be listed 
# with full pathname. RELATIVE may makes it easier to extract an executable name
# automatically.
# file( GLOB APP_SOURCES RELATIVE app/*.cxx )
file( GLOB APP_SOURCES app/*.cxx )
foreach( testsourcefile ${APP_SOURCES} )
    # I used a simple string replace, to cut off .cpp.
    string( REPLACE ".cpp" "" testname ${testsourcefile} )
    add_executable( ${testname} ${testsourcefile} )
    # Make sure YourLib is linked to each app
    target_link_libraries( ${testname} YourLib )
endforeach( testsourcefile ${APP_SOURCES} )

Quelques avertissements :

  • file( GLOB ) n'est généralement pas recommandé, car CMake ne reconstruira pas automatiquement si un nouveau fichier est ajouté. Je l'ai utilisé ici, car je ne connais pas vos fichiers sources.
  • Dans certaines situations, les fichiers sources peuvent être trouvés avec un nom de chemin complet. Si nécessaire, utilisez la fonction drapeau RELATIF pour find( GLOB ... ) .
  • Le paramétrage manuel des fichiers sources nécessite une modification de CMakeLists.txt, ce qui déclenche une reconstruction. Voir cette question pour les (dés)avantages du globbing.
  • J'ai généré le nom du test en utilisant un string( REPLACE ... ) . J'aurais pu utiliser get_filename_component avec le NAME_WE drapeau.

En ce qui concerne les informations "générales" sur CMake, je vous conseille de lire certaines des questions générales sur "CMake Overview" déjà posées ici sur stackoverflow. Par exemple :

4voto

icwnd Points 1130

Je me retrouve dans une situation similaire lorsque j'organise un projet OpenGL avec plusieurs fichiers d'exemple où chacun de ces fichiers contient une méthode principale.

Les paramètres ci-dessous permettront de générer un exécutable distinct par fichier c/cpp et de copier les dépendances requises dans le dossier bin cible.

Structure des dossiers

my-project
 ch01_01.c
 ch02_01.cpp
 CMakeLists.txt
 Resources
    Libraries
       glew
          bin
          include
          lib
       glfw    
          include 
          lib 

CMakeLists.txt

cmake_minimum_required (VERSION 3.9)

project ("my-project")

include_directories(Resources/Libraries/glew/include
                    Resources/Libraries/glfw/include)

link_directories(Resources/Libraries/glew/lib
                 Resources/Libraries/glfw/lib)

link_libraries(opengl32.lib
               glew32.lib
               glfw3.lib)

set(CMAKE_EXE_LINKER_FLAGS "/NODEFAULTLIB:MSVCRT")

file(GLOB SOURCE_FILES *.c *.cpp)

foreach(SOURCE_PATH ${SOURCE_FILES})

    get_filename_component(EXECUTABLE_NAME ${SOURCE_PATH} NAME_WE)

    add_executable(${EXECUTABLE_NAME} ${SOURCE_PATH})

    # Copy required DLLs to the target folder
    add_custom_command(TARGET ${EXECUTABLE_NAME} POST_BUILD
                       COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_SOURCE_DIR}/Resources/Libraries/glew/bin/glew32.dll" 
                                                                     "${CMAKE_BINARY_DIR}/glew32.dll")

endforeach(SOURCE_PATH ${SOURCE_FILES})

Étapes facultatives

Dans Visual Studio

  • Ouvrez le projet avec l'option "Ouvrir un dossier local" dans la fenêtre de démarrage.

  • Lorsque vous ajoutez un nouveau fichier, vous pouvez soit :

    • Annulez la boîte de dialogue demandant d'automatiser add_executable à CMakeLists.txt
    • Désactiver ce comportement en décochant 'Enable automatic CMake script modification for file operations from folder view' dans Tools > Options > CMake

Comme les fichiers nouvellement ajoutés ne sont pas récupérés automatiquement puisque CMakeLists.txt n'est jamais modifié, régénérez simplement le cache comme suit :

  • Project > CMake Cache (x64-Debug) > Delete Cache
  • Project > Generate Cache for my-project

Maintenant, vous pouvez simplement faire un clic droit sur un fichier c/cpp donné et Set as Startup Item pour pouvoir le déboguer avec F5 .

Environnement

  • cmake version 3.18.20081302-MSVC_2
  • Microsoft Visual Studio Community 2019 Version 16.8.3

Modèle de démarrage

J'ai mis en place ce modèle de départ sur GitHub au cas où vous seriez intéressé.

-1voto

xitong Points 75

Ce site CMakeLists.txt fonctionne pour mon projet OpenCV
en supposant que *.cpp se trouvent dans le même répertoire que CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(opencv LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(OpenCV REQUIRED)
include_directories( ${OpenCV_INCLUDE_DIRS} )

file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp )
foreach( sourcefile ${APP_SOURCES} )
    file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${sourcefile})
    string( REPLACE ".cpp" "" file ${filename} )
    add_executable( ${file} ${sourcefile} )
    target_link_libraries( ${file} ${OpenCV_LIBS} )
endforeach( sourcefile ${APP_SOURCES} )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X