Custom Cmake handling functions for build/clean - cmake

i'm new to cmake and I'm trying to find an option to commit the following
cmake .. && make && ./(project_name) --> in order to run my code using 1 commnad
and
rm -rf * --> in order to clean my build directory.
As custom commands to add to my cmake to use like MakeFile uses make all / make clean.
How would I approach this with building a custom command in Cmake to run ? is it even possible to do ?

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 run sanitizers on whole project

I'm trying to get familiar with sanitizers as ASAN, LSAN etc and got a lot of useful information already from here: https://developers.redhat.com/blog/2021/05/05/memory-error-checking-in-c-and-c-comparing-sanitizers-and-valgrind
I am able to run all sort of sanitizers on specific files, as shown on the site, like this:
clang -g -fsanitize=address -fno-omit-frame-pointer -g ../TestFiles/ASAN_TestFile.c
ASAN_SYMBOLIZER_PATH=/usr/local/bin/llvm-symbolizer ./a.out >../Logs/ASAN_C.log 2>&1
which generates a log with found issue. Now I would like to extend this to run upon building the project with cmake. This is the command to build it at the moment:
cmake -S . -B build
cd build
make
Is there any way I can use this script with adding the sanitizers, without having to alter the cmakelist.txt file??
For instance something like this:
cmake -S . -B build
cd build
make -fsanitize=address
./a.out >../Logs/ASAN_C.log 2>&1
The reason is that I want to be able to build the project multiple times with different sanitizers (since they cannot be used together) and have a log created without altering the cmakelist.txt file (just want to be able to quickly test the whole project for memory issues instead of doing it for each file created).
You can add additional compiler flags from command line during the build configuration:
cmake -D CMAKE_CXX_FLAGS="-fsanitize=address" -D CMAKE_C_FLAGS="-fsanitize=address" /path/to/CMakeLists.txt
If your CMakeLists.txt is configured properly above should work. If that does not work then try adding flags as environment variable:
cmake -E env CXXFLAGS="-fsanitize=address" CFLAGS="-fsanitize=address" cmake /path/to/CMakeLists.txt

How to restrict cmake commands based on which target is built

I have a cmake project which produces several executables. I want to package each executable in seperate Docker containers, so inside the Dockefile, I only built the target that I need:
RUN mkdir build \
&& cd build \
&& cmake /app/project -DCMAKE_BUILD_TYPE=Release
&& make -j 2 myExecutable \
&& make install/fast
This works as expected, but I run into an issue with the conan cmake integration. The installation is done when cmake is called, not during the actual build - this means that no matter which target I want to actually build, all the conan installation calls present in my cmake files are called - so way more packages are installed than necessary.
# for every target
# include conan dependencies (each target has its own conanfile.txt)
conan_cmake_run(CONANFILE conanfile.txt
BASIC_SETUP CMAKE_TARGETS
BUILD_TYPE "${CMAKE_BUILD_TYPE}"
BUILD outdated
${update_conan}
)
conan_target_link_libraries(${PROJECT_NAME})
Is there a way to make the cmake calls dependend on which target I actually want to build?
Unfortunately not, the macro conan_cmake_run has no distinction about which target is involved or even it was executed before. You could use CMake options to run or not conan_cmake_run.
Also, you could comment/vote your request thorough the issue https://github.com/conan-io/cmake-conan/issues/105
Regards!

configure-like for CMake

G'day.
Is there a tool which provides autoconf-like configure interface to CMake? eg instead of
cmake -DCMAKE_C_COMPILER=mpicc
invoke same command via
./configure CC=mpicc
Just wrap the call to cmake in the configure script (from OpenSceneGraph):
openscenegraph$ cat ./configure
cmake . -DCMAKE_BUILD_TYPE=Release $#
Be aware that this will perform an "in-source" build. You can pass build variables via the usual -DVARNAME=VALUE, e.g.:
./configure -DCMAKE_VERBOSE_MAKEFILE=On
This github project provides a configure script that understands and translates between a cmake project and a standard autotools configure including support for --prefix and --enable
It takes a little bit to grok, but I believe its the closest solution to what you're expecting.

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