Une solution que j'ai trouvée récemment consiste à combiner le concept de construction hors source avec un wrapper Makefile.
Dans mon fichier CMakeLists.txt de niveau supérieur, j'inclus les éléments suivants pour empêcher les builds en source:
if ( ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR} )
message( FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt." )
endif()
Ensuite, je crée un Makefile de niveau supérieur et j'inclus les éléments suivants:
# -----------------------------------------------------------------------------
# CMake project wrapper Makefile ----------------------------------------------
# -----------------------------------------------------------------------------
SHELL := /bin/bash
RM := rm -rf
MKDIR := mkdir -p
all: ./build/Makefile
@ $(MAKE) -C build
./build/Makefile:
@ ($(MKDIR) build > /dev/null)
@ (cd build > /dev/null 2>&1 && cmake ..)
distclean:
@ ($(MKDIR) build > /dev/null)
@ (cd build > /dev/null 2>&1 && cmake .. > /dev/null 2>&1)
@- $(MAKE) --silent -C build clean || true
@- $(RM) ./build/Makefile
@- $(RM) ./build/src
@- $(RM) ./build/test
@- $(RM) ./build/CMake*
@- $(RM) ./build/cmake.*
@- $(RM) ./build/*.cmake
@- $(RM) ./build/*.txt
ifeq ($(findstring distclean,$(MAKECMDGOALS)),)
$(MAKECMDGOALS): ./build/Makefile
@ $(MAKE) -C build $(MAKECMDGOALS)
endif
La cible par défaut all
est appelée en tapant make
et appelle la cible./build/Makefile
.
La première chose que la cible ./build/Makefile
fait est de créer le build
répertoire en utilisant $(MKDIR)
, qui est une variable pour mkdir -p
. Le répertoire build
est l'endroit où nous effectuerons notre build out-of-source. Nous fournissons l'argument -p
pour nous assurer que mkdir
cela ne nous crie pas pour essayer de créer un répertoire qui peut déjà exister.
La deuxième chose que la cible ./build/Makefile
fait est de changer de répertoire en build
répertoire et d'appeler cmake
.
De retour à la all
cible, nous invoquons $(MAKE) -C build
, où se $(MAKE)
trouve une variable Makefile générée automatiquement pour make
. make -C
change le répertoire avant de faire quoi que ce soit. Par conséquent, utiliser $(MAKE) -C build
équivaut à faire cd build; make
.
Pour résumer, appeler ce wrapper Makefile avec make all
ou make
équivaut à faire:
mkdir build
cd build
cmake ..
make
La cible distclean
invoque cmake ..
, puis make -C build clean
, et enfin, supprime tout le contenu du build
répertoire. Je pense que c'est exactement ce que vous avez demandé dans votre question.
La dernière partie du Makefile évalue si la cible fournie par l'utilisateur est ou non distclean
. Sinon, il changera de répertoire en build
avant de l'invoquer. C'est très puissant car l'utilisateur peut taper, par exemple make clean
, et le Makefile le transformera en un équivalent de cd build; make clean
.
En conclusion, ce wrapper Makefile, en combinaison avec une configuration CMake de construction hors source obligatoire, fait en sorte que l'utilisateur n'ait jamais à interagir avec la commande cmake
. Cette solution fournit également une méthode élégante pour supprimer tous les fichiers de sortie CMake du build
répertoire.
PS Dans le Makefile, nous utilisons le préfixe @
pour supprimer la sortie d'une commande shell, et le préfixe @-
pour ignorer les erreurs d'une commande shell. Lors de l'utilisation rm
dans le cadre de la distclean
cible, la commande retournera une erreur si les fichiers n'existent pas (ils peuvent avoir été supprimés déjà en utilisant la ligne de commande avec rm -rf build
, ou ils n'ont jamais été générés en premier lieu). Cette erreur de retour forcera notre Makefile à quitter. Nous utilisons le préfixe @-
pour éviter cela. Il est acceptable si un fichier a déjà été supprimé; nous voulons que notre Makefile continue et supprime le reste.
Une autre chose à noter: Ce Makefile ne peut pas fonctionner si vous utilisez un nombre variable de variables CMake pour construire votre projet, par exemple, cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
. Ce Makefile suppose que vous appelez CMake de manière cohérente, soit en tapant, cmake ..
soit en fournissant cmake
un nombre cohérent d'arguments (que vous pouvez inclure dans votre Makefile).
Enfin, le crédit là où le crédit est dû. Ce wrapper Makefile a été adapté du Makefile fourni par le modèle de projet d'application C ++ .