How to do dry run with CMake? - makefile

With GNU make, a dry run can be performed via
make -n
Is there a similar option for CMake? The best I could come up with is
cmake ..
make -n | grep -vi cmake
However, I am being too restrictive and am wondering if there is an easier way to achieve this.

According to the command line syntax, if you use -- on the command line with cmake, the parameters following that are passed directly to the native build tool. Eg. what you did is somewhat equivalent to this:
cmake ..
cmake --build -- -n

Related

How to get CMake variable of package in shellscript

I want to find the Qt5WaylandClient_PRIVATE_INCLUDE_DIRS variable which is set by the Qt5WaylandClient package. How can I get it from the shell (dash)? Something like this:
cmake -find_package(Qt5WaylandClient) -get_variable Qt5WaylandClient_PRIVATE_INCLUDE_DIRS
or
cmake -file path/to/my/CMakeLists.txt -get_variable Qt5WaylandClient_PRIVATE_INCLUDE_DIRS
CMake does have a --find-package command line option, but it is not well supported, nor well-documented. There is an answer describing its functionality here, but that's probably not what you're looking for.
Initially, it appears you could just run cmake in script mode, using -P, on a CMake file containing your find_package(Qt5WaylandCleint) command and print its variables to the console.
cmake -P MyFindQt5WaylandClient.cmake
However, running find_package() outside the confines of a CMake project does not work. It yields several errors because CMake doesn't know anything about the system or your target language. So, you must create a minimal CMake project, then run find_package(). Something like this CMakeLists.txt file should work:
cmake_minimum_required(VERSION 3.16)
project(MyProj)
find_package(Qt5WaylandClient REQUIRED)
# Print the desired variable.
message("${Qt5WaylandClient_PRIVATE_INCLUDE_DIRS}")
You can then run cmake from the command line, and this will print the Qt5WaylandClient_PRIVATE_INCLUDE_DIRS variable to the console. You can use the -S and -B command line options to specify the CMake source and binary directories, respectively.
cmake -S . -B build

How to alias a particular cmake command

I'm trying to work around a QtCreator bug (https://bugreports.qt.io/browse/QTCREATORBUG-20972) where QtCreator fails to open a CMake project because it is trying to create a socket file in /tmp/RANDOM_PATH/socket whereas "RANDOM_PATH" does not exist.
I can reproduce the issue manually with:
$ /usr/bin/cmake -E server --pipe=/tmp/not-existing-path/socket
--experimental CMake Error: Internal Error with /tmp/not-existing-path/socket: EACCES
The suggestion given in https://bugreports.qt.io/browse/QTCREATORBUG-18444 is to create an alias of cmake which would report
"serverMode":false
when given the command
cmake -E capabilities
which on my machine (Ubuntu 18.04) outputs:
{"generators":[{"extraGenerators":[],"name":"Watcom WMake","platformSupport":false,"toolsetSupport":false},{"extraGenerators":["CodeBlocks","CodeLite","Sublime Text 2","Kate","Eclipse CDT4","KDevelop3"],"name":"Unix Makefiles","platformSupport":false,"toolsetSupport":false},{"extraGenerators":["CodeBlocks","CodeLite","Sublime Text 2","Kate","Eclipse CDT4"],"name":"Ninja","platformSupport":false,"toolsetSupport":false}],"serverMode":true,"version":{"isDirty":false,"major":3,"minor":10,"patch":2,"string":"3.10.2","suffix":""}}
What's the easiest way to achieve this?
I've tried to add such an alias:
cmake='cmake | sed "s/\"serverMode\":true/\"serverMode\":false/g"'
, but the issue is that the "sed" command needs to be after the arguments given to cmake, and not before.
I see from that bug report:
If you want to run a newer cmake without server-mode, then you will need to write a wrapper around cmake that removes the server-mode support indicator from the output reported by
cmake -E capabilities
That would be something like
cmake() {
if [[ "$*" == "-E capabilities" ]]; then
command cmake "$#" | jq -c 'del(.serverMode)'
else
command cmake "$#"
fi
}
You make have to make that a standalone script rather than a shell function.

Is there a default way to have cmake run make with an appropriate -jX argument?

If I have a cmake build tree configured with the -G"Unix Makefiles" option, I understand that I can run
cmake --build . -- -j10
to pass the -j10 option to make but is there a way to tell cmake --build to do this by default (probably when I run the initial cmake)? I'd like to avoid having to write shell scripts that call cmake --build with arguments that depend on the generator.
Right now I'm looking at a bunch of scripts that figure out arguments to cmake, and they hardcoded calls to make -j$NCPUS; I'd like to improve the scripts to make them generator-agnostic, but would really rather not have a bunch of code that looks like if GENERATOR == Unix Makefiles; then DO A THING else DO SOMETHING ELSE.
I did find https://blog.kitware.com/cmake-building-with-all-your-cores/, but that just talks about how to hand-code the flags for each generator.

How do I configure CMake to make the VS solution use a specific build commandline?

I am trying to set up CMake to generate a MSVC (2010) solution for our project, and need to configure the projects so that they use our specific build system rather than compiling using the default command line.
Here's what the project file looks like for VS2008 (which we generate using another script that I'd like to get away from):
<Tool
Name="VCNMakeTool"
BuildCommandLine="../bam.bat -j %%NUMBER_OF_PROCESSORS%%"
ReBuildCommandLine="../bam.bat -j %%NUMBER_OF_PROCESSORS%% -c && ../bam.bat -j %%NUMBER_OF_PROCESSORS%%"
CleanCommandLine="../bam.bat -j %%NUMBER_OF_PROCESSORS%% -c "
Output="..\..\..\common\win32\container.exe"
PreprocessorDefinitions=""
IncludeSearchPath=""
ForcedIncludes=""
AssemblySearchPath=""
ForcedUsingAssemblies=""
CompileAsManaged=""
/>
It's basically the three CommandLine settings I'd like to be able to specify from my cmake config.
I've found the build_command command in the documentation but from the description it sounds like it does sort of the opposite of what I want, i.e. writes the command line it'll generate to a variable rather than take a string and set the command line to that.
Something that seems a bit related is the cross-compile feature in CMake but I'm sure if that is a good way to do this.
Basically I just want VS to run a batch file when I do a build and then parse the results back to get nice error messages etc.
It looks to me like what you want is simply a "custom command" in CMake parlance.
Something like:
set(custom_exe "${CMAKE_CURRENT_BINARY_DIR}/common/win32/container.exe")
add_custom_command(OUTPUT ${custom_exe}
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bam.bat -j $ENV{NUMBER_OF_PROCESSORS}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bam.bat
)
add_custom_target(bam ALL DEPENDS ${custom_exe})
Maybe you need to write your own CMake Toolchain. You can see examples of toolchains in CMAKE_ROOT/share/Modules/Platform, or in CMake documentation, but i'm not sure whether cmake can generate MSVC solution for custom compiler.

cmake and parallel building with "make -jN"

I'm trying to setup a parallel CMake-based build for my source tree, but when I issue
$ cmake .
$ make -j2
I get:
jobserver unavailable: using -j1. Add '+' to parent make rule
as a warning. Does anyone have an idea if it is possible to fix it somehow?
In the generated Makefile, when calling into a sub-make it needs to either use $(MAKE) (not just 'make') or else precede the line with a +. That is, a rule should look like this:
mysubdir:
$(MAKE) -C mysubdir
or like this:
mysubdir:
+make -C mysubdir
If you don't do it one of those two ways, make will give you that warning.
I don't know anything about cmake, so maybe it's generating Makefiles that aren't correct. Or maybe you did something incorrectly on your end.
In my case (with CMake 3.5.2) the trivial cd build && cmake .. && make -j5 works just fine.
But, I do get the jobserver unavailable error when building custom targets (as dependencies of other targets) via the cmake --build . --target foo idiom.
Like this:
add_custom_target(buildroot
COMMAND ${CMAKE_COMMAND} --build . --target install
COMMENT "Populating buildroot..."
)
add_dependencies(deb buildroot)
add_dependencies(rpm buildroot) #... etc
— so that the user can make deb and it Just Works. CMake will regenerate makefiles if needed, run the compilation, install everything exactly as with make install, and then run my custom scripts to package up the populated buildroot into whatever shape or form I need.
Sure enough, I'd like to make -j15 deb — but that fails.
Now, as explained on the mailing list by CMake devs, the root cause lies, surprisingly (or not), within GNU Make; there is a workaround.
The root cause is that make will not pass its jobserver environment to child processes it thinks aren't make.
To illustrate, here's a process tree (ps -A f) branch:
…
\_ bash
\_ make -j15 deb
\_ make -f CMakeFiles/Makefile2 deb
\_ make -f CMakeFiles/buildroot.dir/build.make CMakeFiles/buildroot.dir/build
\_ /usr/bin/cmake --build . --target install ⦿
\_ /usr/bin/gmake install
…
At ⦿ point, make drops jobserver environment, ultimately causing single-threaded compilation.
The workaround which worked great for me, as given away in the linked email, is to prefix all custom commands with +env. Like this:
add_custom_target(buildroot
#-- this ↓↓↓ here -- https://stackoverflow.com/a/41268443/531179
COMMAND +env ${CMAKE_COMMAND} --build . --target install
COMMENT "Populating buildroot..."
)
add_dependencies(deb buildroot)
add_dependencies(rpm buildroot) #... etc
In the end, this appears in the rule for buildroot in the appropriate makefile (CMake generates a bunch of them), and causes GNU Make to behave properly and respect -j.
Hope this helps.
As pointed out by #Carlo Wood in his comment to this answer, trying to convince cmake to add + to the beginning of the command in the cmake-generated makefile is not possible.
A work-around I found is to shield underlying make command from the make flags coming from cmake. This can be done by setting environment variable MAKEFLAGS to empty string for the custom command:
COMMAND ${CMAKE_COMMAND} -E env
MAKEFLAGS=
make <your target and make options>
Hope this helps.

Resources