view command before build code in Cmake [duplicate] - cmake

I'm trying to debug a compilation problem, but I cannot seem to get GCC (or maybe it is make??) to show me the actual compiler and linker commands it is executing.
Here is the output I am seeing:
CCLD libvirt_parthelper
libvirt_parthelper-parthelper.o: In function `main':
/root/qemu-build/libvirt-0.9.0/src/storage/parthelper.c:102: undefined reference to `ped_device_get'
/root/qemu-build/libvirt-0.9.0/src/storage/parthelper.c:116: undefined reference to `ped_disk_new'
/root/qemu-build/libvirt-0.9.0/src/storage/parthelper.c:122: undefined reference to `ped_disk_next_partition'
/root/qemu-build/libvirt-0.9.0/src/storage/parthelper.c:172: undefined reference to `ped_disk_next_partition'
/root/qemu-build/libvirt-0.9.0/src/storage/parthelper.c:172: undefined reference to `ped_disk_next_partition'
collect2: ld returned 1 exit status
make[3]: *** [libvirt_parthelper] Error 1
What I want to see should be similar to this:
$ make
gcc -Wall -c -o main.o main.c
gcc -Wall -c -o hello_fn.o hello_fn.c
gcc main.o hello_fn.o -o main
Notice how this example has the complete gcc command displayed. The above example merely shows things like "CCLD libvirt_parthelper". I'm not sure how to control this behavior.

To invoke a dry run:
make -n
This will show what make is attempting to do.

Build system independent method
make SHELL='sh -x'
is another option. Sample Makefile:
a:
#echo a
Output:
+ echo a
a
This sets the special SHELL variable for make, and -x tells sh to print the expanded line before executing it.
One advantage over -n is that is actually runs the commands. I have found that for some projects (e.g. Linux kernel) that -n may stop running much earlier than usual probably because of dependency problems.
One downside of this method is that you have to ensure that the shell that will be used is sh, which is the default one used by Make as they are POSIX, but could be changed with the SHELL make variable.
Doing sh -v would be cool as well, but Dash 0.5.7 (Ubuntu 14.04 sh) ignores for -c commands (which seems to be how make uses it) so it doesn't do anything.
make -p will also interest you, which prints the values of set variables.
CMake generated Makefiles always support VERBOSE=1
As in:
mkdir build
cd build
cmake ..
make VERBOSE=1
Dedicated question at: Using CMake with GNU Make: How can I see the exact commands?

Library makefiles, which are generated by autotools (the ./configure you have to issue) often have a verbose option, so basically, using make VERBOSE=1 or make V=1 should give you the full commands.
But this depends on how the makefile was generated.
The -d option might help, but it will give you an extremely long output.

Since GNU Make version 4.0, the --trace argument is a nice way to tell what and why a makefile do, outputing lines like:
makefile:8: target 'foo.o' does not exist
or
makefile:12: update target 'foo' due to: bar

Use make V=1
Other suggestions here:
make VERBOSE=1 - did not work at least from my trials.
make -n - displays only logical operation, not command line being executed. E.g. CC source.cpp
make --debug=j - works as well, but might also enable multi threaded building, causing extra output.

I like to use:
make --debug=j
https://linux.die.net/man/1/make
--debug[=FLAGS]
Print debugging information in addition to normal processing. If the FLAGS are omitted, then the behavior is the same as if -d was specified. FLAGS may be a for all debugging output (same as using -d), b for basic debugging, v for more verbose basic debugging, i for showing implicit rules, j for details on invocation of commands, and m for debugging while remaking makefiles.

Depending on your automake version, you can also use this:
make AM_DEFAULT_VERBOSITY=1
Reference: AM_DEFAULT_VERBOSITY
Note: I added this answer since V=1 did not work for me.

In case you want to see all commands (including the compiled ones) of the default target run:
make --always-make --dry-run
make -Bn
show commands executed the next run of make:
make --dry-run
make -n
You are free to choose a target other than the default in this example.

Related

How to forward output from CMake execute_process to CMake's logs?

In my CMake file, I set up a Python test environment:
execute_process(
COMMAND pip install -U -r ${REQUIREMENTS}
RESULT_VARIABLE STATUS
)
The issue is, I usually don't need its verbose OUTPUT. So I want to optionally hide it. This is what I've done:
if(SHOW_PIP_LOGS)
execute_process(...)
else()
execute_process(... OUTPUT_QUIET)
endif()
The thing is, there is already a way to control what logs are shown in CMake: it's --log-level coupled with message(). This way I don't need to manage any logging-related variables. But the command outputs directly to stdout, without going through CMake log system.
Can I somehow forward the output of a command invocation to CMake's logs?
The output must be printed on-line, without buffering everything to a variable first, so that if a pip takes a long time installing packages, I can see what's going on.

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 can I get make to be verbose but with only "meaningful" lines when building with cmake?

I'm using CMake with the GNU Make generator on a project of mine, and then want to build it - verbosely.
I'm interested in lines which actually produce things, and not interested in lines such as:
gmake[2]: Entering directory '/some/where'
gmake[2]: Leaving directory '/some/other/place'
nor the lines saying:
cd /some/where && /path/to/cmake/bin/cmake -E cmake_link_script CMakeFiles/some.dir/link.txt --verbose=1
as those are "wrapping" the actual work that will happen when cmake runs that script (e.g. calls a linker executable such as gcc).
I don't mind very much the percentage headers such as:
[ 97%] Building CXX object /path/to/proj/CMakeFiles/something.dir/foo.o
i.e. if your solution removes them, then fine, if it keeps them - also fine.
I've read answers and comments on this question: Using CMake with GNU Make: How can I see the exact commands?, and the best I've come up with so far is:
MAKEFLAGS="$MAKEFLAGS --no-print-dir" cmake --build build_dir/ --verbose
The --verbose gives you maximum (?) verbosity, with everything you don't want. Then, the --no-print-dir is picked up by GNU Make, making it avoid the Entering/Leaving Directory messages.
Can I do better, and actually avoid the cd and the cmake -E commands?
Notes:
I realize I can use maximum verbosity, then filter using grep. That's not what I want - I want the lines not to be emitted in the first place.
Nothing may be hard-coded into the CMakeLists.txt file; everything must be done via the command-line, after CMake configuration.
You can discover for yourself that there is no way to do what you want.
Since cmake is just generating makefiles, and it's make that is actually running the recipes and printing the output, you need to look at the makefile and see how the rules are constructed. If you find a sample rule for a link line for example you will see it looks like this:
myexecutable: ...
#$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green --bold --progress-dir=/mydir/CMakeFiles --progress-num=$(CMAKE_PROGRESS_2) "Linking CXX executable myexecutable"
cd /mydir && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/myexecutable.dir/link.txt --verbose=$(VERBOSE)
Note that there is no special variable, or token, or anything appearing in this recipe before the cd /mydir ... text.
So, there is absolutely no way to control how this particular recipe is printed, separately from how all the other recipes are printed. You either get them all, or you get none of them.

From CMake setup 'make' to use '-j' option by default

I want my CMake project to be built by make -j N, whenever I call make from the terminal. I don't want to set -j option manually every time.
For that, I set CMAKE_MAKE_PROGRAM variable to the specific command line. I use the ProcessorCount() function, which gives the number of procesors to perform build in parallel.
When I do make, I do not see any speed up. However if I do make -j N, then it is built definitely faster.
Would you please help me on this issue? (I am developing this on Linux.)
Here is the snippet of the code that I use in CMakeList.txt:
include(ProcessorCount)
ProcessorCount(N)
message("number of processors: " ${N})
if(NOT N EQUAL 0)
set(CTEST_BUILD_FLAGS -j${N})
set(ctest_test_args ${ctest_test_args} PARALLEL_LEVEL ${N})
set(CMAKE_MAKE_PROGRAM "${CMAKE_MAKE_PROGRAM} -j ${N}")
endif()
message("cmake make program" ${CMAKE_MAKE_PROGRAM})
Thank you very much.
In case you want to speed up the build you can run multiple make processes in parallel but not cmake.
To perform every build with predefined number of parallel processes you can define this in MAKEFLAGS.
Set MAKEFLAGS in your environment script, e.g. ~/.bashrc as you want:
export MAKEFLAGS=-j8
On Linux the following sets MAKEFLAGS to the number of CPUs - 1: (Keep one CPU free for other tasks while build) and is useful in environments with dynamic ressources, e.g. VMware:
export MAKEFLAGS=-j$(($(grep -c "^processor" /proc/cpuinfo) - 1))
New from cmake v3.12 on:
The command line has a new option --parallel <JOBS>.
Example:
cmake --build build_arm --parallel 4 --target all
Example with number of CPUs- 1 using nproc:
cmake --build build_arm --parallel $(($(nproc) - 1)) --target all
Via setting the CMAKE_MAKE_PROGRAM variable you want to affect the build process. But:
This variable affects only the build via cmake --build, not on native tool (make) call:
The CMAKE_MAKE_PROGRAM variable is set for use by project code. The value is also used by the cmake(1) --build and ctest(1) --build-and-test tools to launch the native build process.
This variable should be a CACHEd one. It is used in such way by make-like generators:
These generators store CMAKE_MAKE_PROGRAM in the CMake cache so that it may be edited by the user.
That is, you need to set this variable with
set(CMAKE_MAKE_PROGRAM <program> CACHE PATH "Path to build tool" FORCE)
This variable should refer to the executable itself, not to a program with arguments:
The value may be the full path to an executable or just the tool name if it is expected to be in the PATH.
That is, value "make -j 2" cannot be used for that variable (splitting arguments as list
set(CMAKE_MAKE_PROGRAM make -j 2 CACHE PATH "Path to build tool" FORCE)
wouldn't help either).
In summary, you may redefine the behavior of cmake --build calls with setting the CMAKE_MAKE_PROGRAM variable to the script, which calls make with parallel options. But you may not affect the behavior of direct make calls.
You may set the env variable MAKEFLAGS using this command
export MAKEFLAGS=-j$(nproc)
My solution is to have a small script which will run make include all sorts of other features, not just the number of CPUs.
I call my script mk and I do a chmod 755 mk so I can run it with ./mk in the root of my project. I also have a few flags to be able to run various things with a simple command line. For example, while working on the code and I get many errors, I like to pipe the output to less. I can do that with ./mk -l without having to retype all the heavy duty Unix stuff...
As you can see, I have the -j4 in a couple of places where it makes sense. For the -l option, I don't want it because in this case it would eventually cause multiple errors to be printed at the same time (I tried that before!)
#!/bin/sh -e
#
# Execute make
case "$1" in
"-l")
make -C ../BUILD/Debug 2>&1 | less -R
;;
"-r")
make -j4 -C ../BUILD/Release
;;
"-d")
rm -rf ../BUILD/Debug/doc/lpp-doc-?.*.tar.gz \
../BUILD/Debug/doc/lpp-doc-?.*
make -C ../BUILD/Debug
;;
"-t")
make -C ../BUILD/Debug
../BUILD/Debug/src/lpp tests/suite/syntax-print.logo
g++ -std=c++14 -I rt l.cpp rt/*.cpp
;;
*)
make -j4 -C ../BUILD/Debug
;;
esac
# From the https://github.com/m2osw/lpp project
With CMake, it wouldn't work unless, as Tsyvarev mentioned, you create your own script. But I personally don't think it's sensible to call make from your make script. Plus it could break a build process which would not expect that strange script. Finally, my script, as I mentioned, allows me to vary the options depending on the situation.
I usually use alias in linux to set cm equal to cmake .. && make -j12. Or write a shell to specify make and clean progress ...
alias cm='cmake .. && make -j12'
Then use cm to make in a single command.

syntax error near unexpected token `AX_VALGRIND_CHECK'

I am trying to integrate valgrind into my unit test framework by using the following m4 macro described at https://www.gnu.org/software/autoconf-archive/ax_valgrind_check.html. In my configure.ac I have
AC_CONFIG_MACRO_DIR([m4])
...
AX_VALGRIND_DFLT()
AX_VALGRIND_CHECK
I have placed the .m4 script provided, in both ./m4 and in /usr/share/aclocal. To generate the configure script etc, I run the following:
aclocal && autoconf && autoreconf --no-recursive --install && \
autoheader && libtoolize --force && automake --force-missing \
--add-missing
However when I go an run ./configure I get the following error
./configure: line 12914: syntax error near unexpected token `AX_VALGRIND_CHECK'
./configure: line 12914: `AX_VALGRIND_CHECK'
What do I need to do to get my configure script to work with the macros provided by the .m4 script above. I am not sure what other information to provide.
Below is my configure.ac. I will try to find at which point things break using this configure.ac vs the one generated by autoreconf -i as posted by #Kusalananda.
AC_INIT([binary_balanced], [0.1], [mehoggan#gmail.com])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
AC_CONFIG_SRCDIR([./src/])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_CC
AM_PROG_AR
AM_PATH_CHECK
LT_INIT
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
AX_VALGRIND_DFLT()
AX_VALGRIND_CHECK
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile
src/Makefile
tests/Makefile])
AC_OUTPUT
I can not re-create your problem.
I also very seldom run anything other than autoreconf -i. This will re-run the other autotools as needed.
I put the ax_valgrind_check.m4 into a ./m4 directory and created a stub configure.ac:
AC_PREREQ([2.69])
AC_INIT([test],[0.0.0-dev])
AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_MACRO_DIR([m4])
AX_VALGRIND_DFLT()
AX_VALGRIND_CHECK
Running autoreconf -i creates a configure script that does the following:
$ ./configure
checking for a BSD-compatible install... /Users/kk/sw/bin/ginstall -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /Users/kk/sw/bin/gmkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for valgrind... no
So the macros are picked up (which they weren't in your case).
So, run autoreconf -i to see if that sorts things out for you.
If you can't get this to work, try installing the autoconf-archive package for whatever Unix you're on. It will also contain this macro.