Difference between invoking `ninja` directly vs through `cmake --build` - cmake

Follow the commands:
First I do:
cmake -G Ninja ..
then:
cmake --build . -j10
or:
ninja -j10
What is the difference between them? Are there pros or cons between them?

When you run cmake -G Ninja.. it essentially means that you are using a build system namely Ninja. For better understanding this visual depiction will further clarify. Furthermore, the Ninja in cmake -G Ninja.. will generate Ninja build files.
Regarding your question what is the difference between cmake --build . -j10 and ninja -j10?
Apparently there is no difference in your case as you have already run cmake -G Ninja .. previously. Both cmake --build . -j10 and ninja -j10 are fine in your case.
To further clarify, the -j means "number of jobs". And to put it more precisely, it is -jN. Where N explicitly sets "number of jobs" to run in parallel. This means your build will use 10 threads as you have -j10

Related

Why do sources online tend to call `cmake .. && make` instead of `cmake .. && cmake --build build --target install`

Very often in projects which use CMake, you'll see the following instructions
mkdir build
cd build
cmake ..
make install
Or a variant
CMake is a build automation tool and works with a number of builders. So the steps above seemed strange to me because
It implies Linux (or at least access to mkdir and cd
It changes your $PWD which in my opinion shouldn't matter for a build
It hard codes make
In my personal code, I tend to instead call
cmake -S . -B build -DCMAKE_INSTALL_PREFIX=<wherever_I_want_to_install> # -DCMAKE_INSTALL_PREFIX is optional
cmake --build build --target install
# ... or ...
cmake --build build
cmake --install build --prefix=<wherever_I_want_to_install>
No hard-coded make. 100% CMake commands
No change in $PWD
Less OS-specific details
It's rarer but if I need compiler-specific options or other customizations, I pass them via command-line using -DCMAKE_CXX_FLAGS and try to keep the CMakeLists.txt as builder-agnostic as possible.
Are there objective differences (edit: for clarity: objective pros / cons) between these approaches. If so, what are they? And if there isn't any meaningful differences between the two approaches, why is the make install option so frequent?
Why do sources online tend to call cmake .. && make instead of cmake .. && cmake --build build --target install
I believe there are these reasons:
people are more familiar with make, so they tend to use what they are familiar with
cmake --build didn't exist at that time
the author doesn't know that cmake --build exists, because of the reason above

How to build a CMake project in parallel on all available cores?

This related question shows how to build a CMake project using a specified numbers of cores. For example if I wanted to use 10 cores, I could invoke CMake like this:
cmake --build . -j 10
My question is: how can I build using all my available cores. I effectively want CMake to autodetect my core count and use all of them.
As of CMake 3.22, there is no standard way to do this. However, there are a few practical approaches.
If you use the Ninja or Ninja Multi-Config generators, on any platform, simply running the build with cmake --build /path/to/build-dir will use all cores.
If you are on a UNIX-like command line, you can run cmake --build . -j $(nproc)
If you are on Windows/cmd, you can run cmake --build . -j %NUMBER_OF_PROCESSORS%

How to run CTest outside of the build folder? [duplicate]

I would like to be able in a similar manner as I can run cmake like
cmake --build <bld_directory>
to run ctest like
ctest --build <bld_directory>
Obviously running ctest from the <bld-directory> will work,
but it would be nice if I can just tell ctest where to look for its configuration file and where the test executables are located.
From the documentation it is not very clear (or I might not have looked in the right place) if this is possible at all or not.
It would great if somebody could shed some light on if this is possible or not ?
Many thanks,
Jiri
Since CMake 3.20 ctest has the option --test-dir for exactly that.
--test-dir <dir> Specify the directory in which to look for tests.
For CMake older than 3.20:
I couldn't find the way to do it through ctest options, but it is doable using the rule make test which is linked to ctest.
In the Makefile generated by cmake in your build folder you can find the rule:
#Special rule for the target test
test:
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running tests..."
/usr/bin/ctest --force-new-ctest-process $(ARGS)
.PHONY : test
make provides the option that you want with -C /path/to/build_directory/, and you can add any ctest options with ARGS='your ctest options here'
For example, from any directory in your system you can write:
make test -C /path/to/build_folder ARGS='-R SpecificTestIWantToRun -VV'
or
cmake --build <bld_directory> --target test -- ARGS="<ctest_args>"
Another approach without make, is to use parenthesis in your terminal to create a subshell. This will execute the command without changing the folder of your current shell.
(cd $build_folder; ctest -V)

Looking for a 'cmake clean' command to clear up CMake output

Just as make clean deletes all the files that a makefile has produced, I would like to do the same with CMake. All too often I find myself manually going through directories removing files like cmake_install.cmake and CMakeCache.txt, and the CMakeFiles folders.
Is there a command like cmake clean to remove all these files automatically? Ideally this should follow the recursive structure defined within the current directory's CMakeLists.txt file.
CMake 3.X
CMake 3.X offers a 'clean' target.
cmake --build C:/foo/build/ --target clean
From the CMake docs for 3.0.2:
--clean-first = Build target 'clean' first, then build.
(To clean only, use --target 'clean'.)
CMake 2.X
There is no cmake clean in CMake version 2.X
I usually build the project in a single folder like "build". So if I want to make clean, I can just rm -rf build.
The "build" folder in the same directory as the root "CMakeLists.txt" is usually a good choice. To build your project, you simply give cmake the location of the CMakeLists.txt as an argument. For example: cd <location-of-cmakelists>/build && cmake ... (From #ComicSansMS)
In these days of Git everywhere, you may forget CMake and use git clean -d -f -x, that will remove all files not under source control.
CMake official FAQ states:
Some build trees created with GNU autotools have a "make distclean"
target that cleans the build and also removes Makefiles and other
parts of the generated build system. CMake does not generate a "make
distclean" target because CMakeLists.txt files can run scripts and
arbitrary commands; CMake has no way of tracking exactly which files
are generated as part of running CMake. Providing a distclean target
would give users the false impression that it would work as expected.
(CMake does generate a "make clean" target to remove files generated
by the compiler and linker.)
A "make distclean" target is only
necessary if the user performs an in-source build. CMake supports
in-source builds, but we strongly encourage users to adopt the notion
of an out-of-source build. Using a build tree that is separate from
the source tree will prevent CMake from generating any files in the
source tree. Because CMake does not change the source tree, there is
no need for a distclean target. One can start a fresh build by
deleting the build tree or creating a separate build tree.
I googled it for like half an hour and the only useful thing I came up with was invoking the find utility:
# Find and then delete all files under current directory (.) that:
# 1. contains "cmake" (case-&insensitive) in its path (wholename)
# 2. name is not CMakeLists.txt
find . -iwholename '*cmake*' -not -name CMakeLists.txt -delete
Also, be sure to invoke make clean (or whatever CMake generator you're using) before that.
:)
You can use something like:
add_custom_target(clean-cmake-files
COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)
// clean-all.cmake
set(cmake_generated ${CMAKE_BINARY_DIR}/CMakeCache.txt
${CMAKE_BINARY_DIR}/cmake_install.cmake
${CMAKE_BINARY_DIR}/Makefile
${CMAKE_BINARY_DIR}/CMakeFiles
)
foreach(file ${cmake_generated})
if (EXISTS ${file})
file(REMOVE_RECURSE ${file})
endif()
endforeach(file)
I usually create a "make clean-all" command adding a call to "make clean" to the previous example:
add_custom_target(clean-all
COMMAND ${CMAKE_BUILD_TOOL} clean
COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)
Don't try to add the "clean" target as a dependence:
add_custom_target(clean-all
COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
DEPENDS clean
)
Because "clean" isn't a real target in CMake and this doesn't work.
Moreover, you should not use this "clean-cmake-files" as dependence of anything:
add_custom_target(clean-all
COMMAND ${CMAKE_BUILD_TOOL} clean
DEPENDS clean-cmake-files
)
Because, if you do that, all CMake files will be erased before clean-all is complete, and make will throw you an error searching "CMakeFiles/clean-all.dir/build.make". In consequence, you can not use the clean-all command before "anything" in any context:
add_custom_target(clean-all
COMMAND ${CMAKE_BUILD_TOOL} clean
COMMAND ${CMAKE_COMMAND} -P clean-all.cmake
)
That doesn't work either.
Simply issuing rm CMakeCache.txt works for me too.
Maybe it's a little outdated, but since this is the first hit when you google cmake clean, I will add this:
Since you can start a build in the build dir with a specified target with
cmake --build . --target xyz
you can of course run
cmake --build . --target clean
to run the clean target in the generated build files.
Starting with CMake 3.24, there exists the --fresh command line option which rebuilds the entire build tree every time:
--fresh
New in version 3.24.
Perform a fresh configuration of the build tree. This removes any
existing CMakeCache.txt file and associated CMakeFiles/ directory, and
recreates them from scratch.
https://cmake.org/cmake/help/latest/manual/cmake.1.html#options
I agree that the out-of-source build is the best answer. But for the times when you just must do an in-source build, I have written a Python script available here, which:
Runs "make clean"
Removes specific CMake-generated files in the top-level directory such as CMakeCache.txt
For each subdirectory that contains a CMakeFiles directory, it removes CMakeFiles, Makefile, cmake_install.cmake.
Removes all empty subdirectories.
It's funny to see this question gets so many attentions and complicated solutions, which indeed shows a pain to not have a clean method with cmake.
Well, you can definitely cd build_work to do you work, then do a rm -rf * when you need to clean. However, rm -rf * is a dangerous command given that many people are often not aware which dir they are in.
If you cd .., rm -rf build_work and then mkdir build_work and then cd build_work, that's just too much typing.
So a good solution is to just stay out of the build folder and tell cmake the path:
to configure: cmake -B build_work
to build: cmake --build build_work
to install: cmake --install build_work
to clean: rm -rf build_work
to recreate build folder: you don't even need mkdir build_work, just configure it with cmake -B build_work.
In the case where you pass -D parameters into CMake when generating the build files and don't want to delete the entire build/ directory:
Simply delete the CMakeFiles/ directory inside your build directory.
rm -rf CMakeFiles/
cmake --build .
This causes CMake to rerun, and build system files are regenerated. Your build will also start from scratch.
try to use:
cmake --clean-first path-of-CMakeLists.txt-file -B output-dir
--clean-first: Build target clean first, then build.
(To clean only, use --target clean.)
Of course, out-of-source builds are the go-to method for Unix Makefiles, but if you're using another generator such as Eclipse CDT, it prefers you to build in-source. In which case, you'll need to purge the CMake files manually. Try this:
find . -name 'CMakeCache.txt' -o -name '*.cmake' -o -name 'Makefile' -o -name 'CMakeFiles' -exec rm -rf {} +
Or if you've enabled globstar with shopt -s globstar, try this less disgusting approach instead:
rm -rf **/CMakeCache.txt **/*.cmake **/Makefile **/CMakeFiles
A solution that I found recently is to combine the out-of-source build concept with a Makefile wrapper.
In my top-level CMakeLists.txt file, I include the following to prevent in-source 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 called by typing make, and invokes the target ./build/Makefile.
The first thing the target ./build/Makefile does is to create the build directory using $(MKDIR), which is a variable for mkdir -p. The directory build is where we will perform our out-of-source build. We provide the argument -p to ensure that mkdir does not scream at us for trying to create a directory that may already exist.
The second thing the target ./build/Makefile does is to change directories to the build directory and invoke cmake.
Back to the all target, we invoke $(MAKE) -C build, where $(MAKE) is a Makefile variable automatically generated for make. make -C changes the directory before doing anything. Therefore, using $(MAKE) -C build is equivalent to doing cd build; make.
To summarize, calling this Makefile wrapper with make all or make is equivalent to doing:
mkdir build
cd build
cmake ..
make
The target distclean invokes cmake .., then make -C build clean, and finally, removes all contents from the build directory. I believe this is exactly what you requested in your question.
The last piece of the Makefile evaluates if the user-provided target is or is not distclean. If not, it will change directories to build before invoking it. This is very powerful because the user can type, for example, make clean, and the Makefile will transform that into an equivalent of cd build; make clean.
In conclusion, this Makefile wrapper, in combination with a mandatory out-of-source build CMake configuration, make it so that the user never has to interact with the command cmake. This solution also provides an elegant method to remove all CMake output files from the build directory.
P.S. In the Makefile, we use the prefix # to suppress the output from a shell command, and the prefix #- to ignore errors from a shell command. When using rm as part of the distclean target, the command will return an error if the files do not exist (they may have been deleted already using the command line with rm -rf build, or they were never generated in the first place). This return error will force our Makefile to exit. We use the prefix #- to prevent that. It is acceptable if a file was removed already; we want our Makefile to keep going and remove the rest.
Another thing to note: This Makefile may not work if you use a variable number of CMake variables to build your project, for example, cmake .. -DSOMEBUILDSUSETHIS:STRING="foo" -DSOMEOTHERBUILDSUSETHISTOO:STRING="bar". This Makefile assumes you invoke CMake in a consistent way, either by typing cmake .. or by providing cmake a consistent number of arguments (that you can include in your Makefile).
Finally, credit where credit is due. This Makefile wrapper was adapted from the Makefile provided by the C++ Application Project Template.
I use the following shell script for such purposes:
#!/bin/bash
for fld in $(find -name "CMakeLists.txt" -printf '%h ')
do
for cmakefile in CMakeCache.txt cmake_install.cmake CTestTestfile.cmake CMakeFiles Makefile
do
rm -rfv $fld/$cmakefile
done
done
If you are using Windows then use Cygwin for this script.
Clear the cmake build output:
Command line:
$ rm -rf [folder that you builded the project]/
$ cmake --build .
Cmake:
cmake --build . --target clean
To simplify cleaning when using "out of source" build (i.e. you build in the build directory), I use the following script:
$ cat ~/bin/cmake-clean-build
#!/bin/bash
if [ -d ../build ]; then
cd ..
rm -rf build
mkdir build
cd build
else
echo "build directory DOES NOT exist"
fi
Every time you need to clean up, you should source this script from the build directory:
. cmake-clean-build
CMake 3.X
CMake 3.0 and above offers a 'clean' target. This removes any artifacts like object files, library files, executables, generated files, etc.
cmake --build C:/foo/build/ --target clean
You can also clean the build, then run the build. In 1 command.
cmake --build C:/foo/build --clean-first
However, this WON'T cleanup things like the CMakeCache.txt or the associated CMakeFiles/ directory. Which you may want to do. You just have to delete the build folder.
# Just delete the build folder
rm C:/foo/build -rf
# You can also just let git delete the build folder as well
git clean -d -f -x
CMake 3.24
Now in CMake 3.24 you can perform a fresh configuration of the build tree. This removes any existing CMakeCache.txt file and associated CMakeFiles/ directory, and recreates them from scratch.
Generally you want to do this when:
You want to clear cached variable in CMakeCache.txt
You want to change compilers
Any other operations related to CMake caching
cmake -B C:/foo/build --fresh
If you run
cmake .
it will regenerate the CMake files. Which is necessary if you add a new file to a source folder that is selected by *.cc, for example.
While this isn't a "clean" per se, it does "clean" up the CMake files by regenerating the caches.
This is pretty old, but if you completely remove the cmake-build-debug folder, when you compile using cmake it should automatically create a new cmake-build-debug folder with everything you need. Works especially well in CLion.
If you have custom defines and want to save them before cleaning, run the following in your build directory:
sed -ne '/variable specified on the command line/{n;s/.*/-D \0 \\/;p}' CMakeCache.txt
Then create a new build directory (or remove the old build directory and recreate it) and finally run cmake with the arguments you'll get with the script above.
cmake mostly cooks a Makefile, one could add rm to the clean PHONY.
For example,
[root#localhost hello]# ls
CMakeCache.txt CMakeFiles cmake_install.cmake CMakeLists.txt hello Makefile test
[root#localhost hello]# vi Makefile
clean:
$(MAKE) -f CMakeFiles/Makefile2 clean
rm -rf *.o *~ .depend .*.cmd *.mod *.ko *.mod.c .tmp_versions *.symvers *.d *.markers *.order CMakeFiles cmake_install.cmake CMakeCache.txt Makefile
Here is what I use. It's wrapped in a function, It's cross platform and it demonstrated how to find matching filenames or folder names, in case you wanted to make any easy adjustments. This function runs every time I build my scripts and has worked flawlessly for my needs.
function(DELETE_CACHE)
if(CMAKE_HOST_WIN32)
execute_process(COMMAND cmd /c for /r %%i in (CMakeCache.*) do del "%%i" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
execute_process(COMMAND cmd /c for /d /r %%i in (*CMakeFiles*) do rd /s /q "%%i" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
else()
execute_process(COMMAND find . -name "CMakeCache.*" -delete WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
execute_process(COMMAND "rm -rf `find . -type d -name CMakeFiles`" WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()
endfunction()
I used zsxwing's answer successfully to solve the following problem:
I have source that I build on multiple hosts (on a Raspberry Pi Linux board, on a VMware Linux virtual machine, etc.)
I have a Bash script that creates temporary directories based on the hostname of the machine like this:
# Get hostname to use as part of directory names
HOST_NAME=`uname -n`
# Create a temporary directory for cmake files so they don't
# end up all mixed up with the source.
TMP_DIR="cmake.tmp.$HOSTNAME"
if [ ! -e $TMP_DIR ] ; then
echo "Creating directory for cmake tmp files : $TMP_DIR"
mkdir $TMP_DIR
else
echo "Reusing cmake tmp dir : $TMP_DIR"
fi
# Create makefiles with CMake
#
# Note: switch to the temporary dir and build parent
# which is a way of making cmake tmp files stay
# out of the way.
#
# Note 2: to clean up cmake files, it is OK to
# "rm -rf" the temporary directories
echo
echo Creating Makefiles with cmake ...
cd $TMP_DIR
cmake ..
# Run makefile (in temporary directory)
echo
echo Starting build ...
make
Create a temporary build directory, for example, build_cmake. Hence all your build files will be inside this folder.
Then in your main CMake file add the below command.
add_custom_target(clean-all
rm -rf *
)
Hence while compiling do
cmake ..
And to clean do:
make clean-all

What is CMake equivalent of 'configure --prefix=DIR && make all install '?

I do cmake . && make all install. This works, but installs to /usr/local.
I need to install to a different prefix (for example, to /usr).
What is the cmake and make command line to install to /usr instead of /usr/local?
You can pass in any CMake variable on the command line, or edit cached variables using ccmake/cmake-gui. On the command line,
cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr . && make all install
Would configure the project, build all targets and install to the /usr prefix. The type (PATH) is not strictly necessary, but would cause the Qt based cmake-gui to present the directory chooser dialog.
Some minor additions as comments make it clear that providing a simple equivalence is not enough for some. Best practice would be to use an external build directory, i.e. not the source directly. Also to use more generic CMake syntax abstracting the generator.
mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr .. && cmake --build . --target install --config Release
You can see it gets quite a bit longer, and isn't directly equivalent anymore, but is closer to best practices in a fairly concise form... The --config is only used by multi-configuration generators (i.e. MSVC), ignored by others.
The ":PATH" part in the accepted answer can be omitted. This syntax may be more memorable:
cmake -DCMAKE_INSTALL_PREFIX=/usr . && make all install
...as used in the answers here.
Note that in both CMake and Autotools you don't always have to set the installation path at configure time. You can use DESTDIR at install time (see also here) instead as in:
make DESTDIR=<installhere> install
See also this question which explains the subtle difference between DESTDIR and PREFIX.
This is intended for staged installs and to allow for storing programs in a different location from where they are run e.g. /etc/alternatives via symbolic links.
However, if your package is relocatable and doesn't need any hard-coded (prefix) paths set via the configure stage you may be able to skip it.
So instead of:
cmake -DCMAKE_INSTALL_PREFIX=/usr . && make all install
you would run:
cmake . && make DESTDIR=/usr all install
Note that, as user7498341 points out, this is not appropriate for cases where you really should be using PREFIX.
The way I build CMake projects cross platform is the following:
/project-root> mkdir build
/project-root> cd build
/project-root/build> cmake -G "<generator>" -DCMAKE_INSTALL_PREFIX=stage ..
/project-root/build> cmake --build . --target=install --config=Release
The first two lines create the out-of-source build directory
The third line generates the build system specifying where to put the installation result (which I always place in ./project-root/build/stage - the path is always considered relative to the current directory if it is not absolute)
The fourth line builds the project configured in . with the buildsystem configured in the line before. It will execute the install target which also builds all necessary dependent targets if they need to be built and then copies the files into the CMAKE_INSTALL_PREFIX (which in this case is ./project-root/build/stage. For multi-configuration builds, like in Visual Studio, you can also specify the configuration with the optional --config <config> flag.
The good part when using the cmake --build command is that it works for all generators (i.e. makefiles and Visual Studio) without needing different commands.
Afterwards I use the installed files to create packages or include them in other projects...
Starting with CMake 3.15, the correct way of achieving this would be using:
cmake --install <dir> --prefix "/usr"
Official Documentation
Starting with CMake 3.21 you can use the --install-prefix option instead of manually setting CMAKE_INSTALL_PREFIX.
The modern equivalent of configure --prefix=DIR && make all install would now be:
cmake -B build --install-prefix=DIR
cmake --build build
cmake --install build
Regarding Bruce Adams answer:
Your answer creates dangerous confusion. DESTDIR is intended for
installs out of the root tree. It allows one to see what would be
installed in the root tree if one did not specify DESTDIR.
PREFIX is the base directory upon which the real installation is
based.
For example, PREFIX=/usr/local indicates that the final destination
of a package is /usr/local. Using DESTDIR=$HOME will install the files
as if $HOME was the root (/). If, say DESTDIR, was /tmp/destdir, one
could see what 'make install' would affect. In that spirit, DESTDIR
should never affect the built objects.
A makefile segment to explain it:
install:
cp program $DESTDIR$PREFIX/bin/program
Programs must assume that PREFIX is the base directory of the final
(i.e. production) directory. The possibility of symlinking a program
installed in DESTDIR=/something only means that the program does not
access files based upon PREFIX as it would simply not work. cat(1)
is a program that (in its simplest form) can run from anywhere.
Here is an example that won't:
prog.pseudo.in:
open("#prefix#/share/prog.db")
...
prog:
sed -e "s/#prefix#/$PREFIX/" prog.pseudo.in > prog.pseudo
compile prog.pseudo
install:
cp prog $DESTDIR$PREFIX/bin/prog
cp prog.db $DESTDIR$PREFIX/share/prog.db
If you tried to run prog from elsewhere than $PREFIX/bin/prog,
prog.db would never be found as it is not in its expected location.
Finally, /etc/alternatives really does not work this way. There are
symlinks to programs installed in the root tree (e.g. vi -> /usr/bin/nvi,
vi -> /usr/bin/vim, etc.).
It is considered bad practice to invoke the actual build system (e.g. via the make command) if using CMake. It is highly recommended to do it like this:
Configure + Generation stages:
cmake -S foo -B _builds/foo/debug -G "Unix Makefiles" -D CMAKE_BUILD_TYPE:STRING=Debug -D CMAKE_DEBUG_POSTFIX:STRING=d -D CMAKE_INSTALL_PREFIX:PATH=/usr
Build and Install stages:
cmake --build _builds/foo/debug --config Debug --target install
When following this approach, the generator can be easily switched (e.g. -G Ninja for Ninja) without having to remember any generator-specific commands.
Note that the CMAKE_BUILD_TYPE variable is only used by single-config generators and the --config argument of the build command is only used by multi-config generators.
Lots of answer, but I figured I'd do a summary to properly group them and explain the differences.
First of all, you can define that prefix one of two ways: during configuration time, or when installing, and that's really up to your needs.
During configuration time
Two options:
cmake -S $src_dir -B $build_dir -D CMAKE_INSTALL_PREFIX=$install_dir
cmake -S $src_dir -B $build_dir --install-prefix=$install_dir # Since CMake 3.21
During install time
Advantage: no need to reconfigure if you want to change it.
Two options:
cmake DESTDIR=$install_dir --build $build_dir --target=install # Makefile only
cmake --install $build_dir --prefix=$install_dir