Una solución que encontré recientemente es combinar el concepto de compilación fuera de la fuente con un contenedor Makefile.
En mi archivo CMakeLists.txt de nivel superior, I incluyen los siguientes prevenir la entrada fuente construye:
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()
A continuación, se crea un Makefile superior, e incluyen los siguientes:
# -----------------------------------------------------------------------------
# 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
Se llama al destino predeterminado all
escribiendo make
, e invoca el destino ./build/Makefile
.
Lo primero que el objetivo ./build/Makefile
hace es crear el directorio build
usando $(MKDIR)
, que es una variable para mkdir -p
. El directorio build
es donde realizaremos nuestra compilación fuera de la fuente. Proporcionamos el argumento -p
para asegurarnos de que mkdir
no nos grite por intentar crear un directorio que ya exista.
Lo segundo que hace el objetivo ./build/Makefile
es cambiar directorios al directorio build
e invocar cmake
.
Volver al destino all
, invocamos $(MAKE) -C build
, donde $(MAKE)
es una variable Makefile generada automáticamente para make
. make -C
cambia el directorio antes de hacer cualquier cosa. Por lo tanto, usar $(MAKE) -C build
es equivalente a hacer cd build; make
.
En resumen, llamando a este envoltorio Makefile con make all
o make
es equivalente a hacer:
mkdir build
cd build
cmake ..
make
El objetivo distclean
invoca cmake ..
, entonces make -C build clean
, y, finalmente, elimina todos los contenidos del directorio build
. Creo que esto es exactamente lo que solicitó en su pregunta.
La última parte del Makefile evalúa si el objetivo proporcionado por el usuario es o no es distclean
. Si no, cambiará los directorios a build
antes de invocarlo. Esto es muy poderoso porque el usuario puede escribir, por ejemplo, make clean
, y el Makefile lo transformará en un equivalente de cd build; make clean
.
En conclusión, esta envoltura de Makefile, en combinación con una configuración CMake de compilación obligatoria fuera de la fuente, hace que el usuario nunca tenga que interactuar con el comando cmake
. Esta solución también proporciona un método elegante para eliminar todos los archivos de salida CMake del directorio build
.
P.S. En el Makefile, usamos el prefijo @
para suprimir la salida de un comando de shell, y el prefijo @-
para ignorar los errores de un comando de shell. Cuando se usa rm
como parte del objetivo distclean
, el comando devolverá un error si los archivos no existen (pueden haberse eliminado ya usando la línea de comando con rm -rf build
, o nunca se generaron en primer lugar). Este error de retorno forzará a nuestro Makefile a salir. Usamos el prefijo @-
para evitar eso. Es aceptable si ya se eliminó un archivo; queremos que nuestro Makefile continúe y elimine el resto.
Otra cosa a tener en cuenta: este archivo Makefile puede no funcionar si utiliza una cantidad variable de variables CMake para construir su proyecto, por ejemplo, cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar"
. Este Makefile asume que invoca CMake de manera consistente, ya sea escribiendo cmake ..
o proporcionando cmake
una cantidad consistente de argumentos (que puede incluir en su Makefile).
Por último, crédito donde se debe crédito. Este contenedor Makefile fue adaptado del Makefile proporcionado por el C++ Application Project Template.
Esta respuesta fue originalmente publicada here. Pensé que se aplicaba a tu situación también.
Tengo la misma arquitectura de proyecto que usted. Mi dir de "compilación" siempre está aquí. Personalmente encuentro que escribir _cmake .._ no es tan importante. – Offirmo