Ajouter automatiquement tous les fichiers d'un dossier à une cible à l'aide de CMake?

163

J'envisage de passer d'un projet multiplateforme à partir de systèmes de gestion de build séparés dans Visual C ++, XCode et makefiles vers CMake.

Une fonctionnalité essentielle dont j'ai besoin est d'ajouter automatiquement tous les fichiers d'un répertoire à une cible. Bien que cela soit facile à faire avec make, ce n'est pas facilement faisable avec Visual C ++ et XCode (corrigez-moi si je me trompe). Est-il possible de le faire directement dans CMake? Comment?

Martjno
la source
Btw. Dans Visual Studio, au moins dans les projets C #, il existe un bouton de barre d'outils dans l'explorateur de projet, nommé afficher tous les fichiers. Il rend tous les sous-répertoires d'un projet visibles, grisés s'ils ne contiennent aucun fichier logiquement inclus dans le projet. Vous pouvez inclure ces répertoires via le menu contextuel, qui comprend tous les fichiers source qu'ils contiennent, de manière récursive :)
yeoman

Réponses:

229

C'est possible. Par exemple avec file(GLOB:

cmake_minimum_required(VERSION 2.8)

file(GLOB helloworld_SRC
    "*.h"
    "*.cpp"
)

add_executable(helloworld ${helloworld_SRC})

Notez que cela nécessite manuel réexécuter de cmakesi un fichier source est ajouté ou supprimé, étant donné que le système de construction généré ne sait pas quand demander CMake à se régénérer, et de le faire à chaque construction augmenterait le temps de construction.

Kleist
la source
11
Une alternative à la réexécution manuelle de cmake consiste à toucher le fichier CMakeLists.txt avant d'exécuter make.
Seamus Connor
8
> "Nous ne recommandons pas d'utiliser GLOB pour collecter une liste de fichiers source à partir de votre arborescence source. Si aucun fichier CMakeLists.txt ne change lorsqu'une source est ajoutée ou supprimée, le système de construction généré ne peut pas savoir quand demander à CMake de se régénérer." Ce n'est plus recommandé dans les documents CMAKE3.7 liés à propos par Hand1Cloud
triple
4
quelle est l'alternative à GLOB alors?
Shayne
13
Un meilleur moyen depuis la v3.1 est suggéré ici: target_sources () crascit.com/2016/01/31/…
Sheen
34

La réponse de Kleist fonctionne certainement, mais il y a une mise en garde importante:

Lorsque vous écrivez un Makefilemanuellement, vous pouvez générer une SRCSvariable en utilisant une fonction pour sélectionner tous les fichiers .cppet .h. Si un fichier source est ajouté ultérieurement, la réexécution makel'inclura.

Cependant, CMake (avec une commande comme file(GLOB ...)) générera explicitement une liste de fichiers et la placera dans le fichier auto-généré Makefile. Si vous avez un nouveau fichier source, vous devrez le régénérer en le Makefileréexécutant cmake.

edit: Pas besoin de supprimer le Makefile.

kara deniz
la source
4
Vous ne pouvez pas simplement réexécuter cmake, ce qui devrait supprimer / modifier le Makefile obsolète?
Ethan
25
Ce n'est pas une réponse, c'est un commentaire sur la réponse de @ Kleist.
Neowizard
3
@Neowizard n'est pas dans la terminologie Stackoverflow.
kara deniz
1
Ce commentaire est sympa, mais c'est "standard", non? Le demandeur utilise déjà cmake, donc suggérer que make peut être «plus intelligent» n'est pas si utile.
frankliuao
Existe-t-il donc un moyen d'ajouter de nouveaux fichiers source, puis de construire sans réexécuter cmake?
artin
6

Extension pour la réponse @Kleist :

Depuis CMake 3.12, l'option supplémentaire CONFIGURE_DEPENDS est prise en charge par les commandes file(GLOB)et file(GLOB_RECURSE). Avec cette option, il n'est pas nécessaire de réexécuter manuellement CMake après l'ajout / la suppression d'un fichier source dans le répertoire - CMake sera réexécuté automatiquement lors de la prochaine construction du projet.

Cependant, l'option CONFIGURE_DEPENDS implique que le répertoire correspondant sera revérifié chaque fois que la construction est demandée, donc le processus de construction prendrait plus de temps que sans CONFIGURE_DEPENDS .

Même avec l' option CONFIGURE_DEPENDS disponible, la documentation CMake ne recommande toujours pas d' utiliser file(GLOB)ou file(GLOB_RECURSE)de collecter les sources.

Tsyvarev
la source
"La documentation CMake ne recommande toujours pas d'utiliser file(GLOB)ou file(GLOB_RECURSE)de collecter les sources" Que recommandent-ils alors? Vous utilisez autre chose pour collecter les sources ou pour lister manuellement chaque fichier source?
Thomas le
1
@Thomas: Ils recommandent de lister manuellement chaque fichier source. Cette réponse donne une excellente explication de la recommandation.
Tsyvarev
-2

Alors pourquoi ne pas utiliser PowerShell pour créer la liste des fichiers source pour vous. Jetez un œil à ce script

param (
    [Parameter(Mandatory=$True)]
    [string]$root 
)

if (-not (Test-Path  -Path $root)) {    
throw "Error directory does not exist"
}

#get the full path of the root
$rootDir = get-item -Path $root
$fp=$rootDir.FullName;


$files = Get-ChildItem -Path $root -Recurse -File | 
         Where-Object { ".cpp",".cxx",".cc",".h" -contains $_.Extension} | 
         Foreach {$_.FullName.replace("${fp}\","").replace("\","/")}

$CMakeExpr = "set(SOURCES "

foreach($file in $files){

    $CMakeExpr+= """$file"" " ;
}
$CMakeExpr+=")"
return $CMakeExpr;

Supposons que vous ayez un dossier avec cette structure

C:\Workspace\A
--a.cpp
C:\Workspace\B 
--b.cpp

Maintenant, enregistrez ce fichier sous "generateSourceList.ps1" par exemple, et exécutez le script en tant que

~>./generateSourceList.ps1 -root "C:\Workspace" > out.txt

Le fichier out.txt contiendra

set(SOURCE "A/a.cpp" "B/b.cpp")
Alcoforado
la source
La question est étiquetée multi-plateforme - PowerShell n'est pas multi-plateforme.
reichhart
@reichhart powershell fonctionne aussi sur Linux et Mac
Noone le
Je connais. Mais il n'y a pas de balise pour powershell et "CMake" est déjà crossplatform. "Powershell" serait une dépendance supplémentaire et est très rarement utilisé sur d'autres OS que Windows. Vous pourriez trouver encore plus de développeurs C # sur Linux que de personnes avec PowerShell. Et le fait le plus important est la question: "Est-il possible de le faire directement dans CMake? Comment?"
reichhart le