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 allest appelée en tapant makeet appelle la cible./build/Makefile .
La première chose que la cible ./build/Makefilefait est de créer le buildrépertoire en utilisant $(MKDIR), qui est une variable pour mkdir -p. Le répertoire buildest l'endroit où nous effectuerons notre build out-of-source. Nous fournissons l'argument -ppour nous assurer que mkdircela 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/Makefilefait est de changer de répertoire en buildrépertoire et d'appeler cmake.
De retour à la allcible, nous invoquons $(MAKE) -C build, où se $(MAKE)trouve une variable Makefile générée automatiquement pour make. make -Cchange 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 allou makeéquivaut à faire:
mkdir build
cd build
cmake ..
make
La cible distcleaninvoque cmake .., puis make -C build clean, et enfin, supprime tout le contenu du buildré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 buildavant 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 buildré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 rmdans le cadre de la distcleancible, 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 cmakeun 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 ++ .