The solution I found recently is to combine the concept of building outside the source code with the Makefile shell.
In my top-level CMakeLists.txt file, I include the following to prevent inline builds:
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()
Then I create a top-level Makefile and include the following:
# ----------------------------------------------------------------------------- # 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
The default target, all is invoked by typing make and invoking the target ./build/Makefile .
The first thing the ./build/Makefile goal ./build/Makefile is create the build directory using $(MKDIR) , which is the variable for mkdir -p . The build directory is where we build outside the source. We provide the -p argument so that mkdir does not yell at us, trying to create a directory that may already exist.
Secondly, the goal of ./build/Makefile is to change directories to the build directory and invoke cmake .
Returning to the all target, we call $(MAKE) -C build , where $(MAKE) is the Makefile variable automatically generated for make . make -C changes the directory before doing anything. Therefore, using $(MAKE) -C build equivalent to doing cd build; make cd build; make .
To summarize, calling this Makefile shell with make all or make equivalent to doing:
mkdir build cd build cmake .. make
The distclean invokes cmake .. , then make -C build clean and finally removes all the contents from the build directory. I believe that this is exactly what you asked in your question.
The last part of the Makefile evaluates whether the user-defined target is or is not a distclean . If not, this will change the directories to build before build it. This is very powerful because the user can print, for example, make clean , and the Makefile converts it to the equivalent of cd build; make clean cd build; make clean .
In conclusion, this Makefile, combined with the mandatory configuration of CMake to build outside the source code, makes it so that the user should never interact with the cmake command. This solution also provides an elegant method to remove all CMake output files from the build directory.
PS In the Makefile, we use the @ prefix to suppress the output from the shell command, and the @- prefix to ignore errors from the shell command. When using rm as part of the distclean target distclean command returns an error if the files do not exist (they may have already been deleted using the command line using rm -rf build , or they were never generated in the first place). This reverse error will force our Makefile to exit. We use the @- prefix to prevent this. This is acceptable if the file has already been deleted; we want our Makefile to keep going and delete the rest.
One more note: this Makefile may not work if you use a variable number of CMake variables to create your project, for example cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar" . This Makefile assumes that you invoke CMake sequentially, either by typing cmake .. or by providing cmake consistent number of arguments (which you can include in your Makefile).
Finally, a loan, which should be a loan. This Makefile shell was adapted from the Makefile provided by the C ++ Application Project Template .
This answer was originally posted here . I thought this applied to your situation.