Make CMake not search for Python components on reconfigure - cmake

I added googletest to my build using FetchContent like this:
FetchContent_Declare(googletest
GIT_REPOSITORY https://github.com/google/googletest
GIT_TAG main
)
FetchContent_MakeAvailable(googletest)
But after I did this, each time CMake needs to rerun its configure/generate steps it takes about ~25 seconds. This is really interfering with my workflow when making iterative changes to the build.
C:\NSEW>cmake --build .
[0/2] Re-checking globbed directories...
[1/2] Re-running CMake...
| It takes about 20 seconds until the following output is shown |
-- Could NOT find Python (missing: Python_EXECUTABLE Interpreter)
-- Found SFML 2.5.1 in C:/install/lib/cmake/SFML
-- Configuring done
-- Generating done
-- Build files have been written to: C:/NSEW
[0/2] Re-checking globbed directories...
ninja: no work to do.
googletest has an optional Python dependency but since Python isn't installed, CMake tries every possible installation path which takes very long. CMake appears to do this search on every reconfigure. How to stop CMake from doing this very slow search for a component I don't need?
I tried to set the cache variable Python_EXECUTABLE to NO / Python-NOTFOUND but that didn't seem to help.

You can disable any non-REQUIRED find_package(PackageName) command using CMAKE_DISABLE_FIND_PACKAGE_<PackageName>. This variable has existed since at least CMake 3.0, so this will work in general.
You can set it just before FetchContent_MakeAvailable and then unset() it afterward. Otherwise, just set CMAKE_DISABLE_FIND_PACKAGE_Python=TRUE (and/or ...Python3) at the cmake command line.

The FindPython module that googletest/CMake uses has a Python_FIND_IMPLEMENTATIONS variable you can configure. This is an allow list of what Python implementations CMake should look for.
If you configure this to an empty string it should not spend any time searching for a Python installation.
cmake -DPython_FIND_IMPLEMENTATIONS:STRING="" <build directory>

Related

how to use clang tidy in CMake

I would like to use CMake and clang-tidy in my project, however I see that build times are quite a bit higher when I use this in all the main cmake file:
set(CMAKE_CXX_CLANG_TIDY
clang-tidy-11;
-format-style='file';
-header-filter=${CMAKE_CURRENT_SOURCE_DIR};
)
It is working well, but I don't want to have this build-time penalty every time I build the project during development. Therefore I thought I would make a separate target that builds all, but uses clang-tidy. And when I do a regular debug or release build it does not do any checking. However I don't know how to do this in Cmake. Do I make a custom target with a command "cmake --build" with a target_set_property of CMAKE_CXX_CLANG_TIDY?
This feels rather clunky, so my question is, are there other ways to do this?
however I see that build times are quite a bit higher when I use this in all the main cmake file:
You're going to have to pay for the cost of running clang-tidy sometime or another. It's essentially running the first few phases of a compiler to analyze your code and look for errors.
Setting CMAKE_CXX_CLANG_TIDY runs clang-tidy in line with your build, as you have observed.
This feels rather clunky, so my question is, are there other ways to do this?
Yes. When using the Ninja or Makefile generators, you may set -DCMAKE_EXPORT_COMPILE_COMMANDS=ON at the command line. That will create a file called compile_commands.json in your build folder that the standalone clang-tidy can read.
In sum, at the command line, you would manually run:
$ cmake -G Ninja -S . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
$ clang-tidy-11 -format-style=file -header-filter=. -p build
The -p flag tells clang-tidy in which directory to find your compile_commands.json.

How to write CMakeLists.txt with NOT using 'MSBuild.exe' on windows? [duplicate]

This question already has answers here:
cmake: Selecting a generator within CMakeLists.txt
(5 answers)
Closed 3 years ago.
I'm trying to write the CMakeLists.txt for building a custom targets only project.
That is, it's not for the usual C/C++ project; all build recipes are provided using ADD_CUSTOM_COMMAND() and ADD_CUSTOM_TARGET(). The reason why I'm using CMake is to manage dependencies between build target stuffs and utilize the advantages of incremental build.
The problem is, when I execute cmake CMakeLists.txt on Windows cmd.exe, it tries to find Windows SDK or MSBuild.exe -- which are never needed for building targets in the project.
cmd.exe> cmake CMakeLists.txt
-- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.17134.
CMake Error at CMakeLists.txt:6 (PROJECT):
Failed to run MSBuild Command:
MSBuild.exe
to get the value of VCTargetsPath:
Cannot find file
-- Configuring incomplete, errors occurred!
See also "CMakeFiles/CMakeOutput.log"
The header of the CMakeLists.txt is:
cmake_minimum_required ( VERSION 3.0 )
set ( CMAKE_GENERATOR "Unix Makefile" )
set ( CMAKE_VERBOSE_MAKEFILE true )
# Project name
project ( "awesome-project" NONE ) # <language>=NONE for skipping compiler check
...
As I mentioned above, all recipes of the build targets are provided in the CMakeLists.txt; neither Windows SDK nor Visual Studio is required.
I think there is some CMake directives for skipping the invocation of MSBuild, but I could not find it. How can I write the CMakeLists.txt in this case?
As the answer here suggests, setting the CMAKE_GENERATOR variable in the CMake file has no effect when running CMake for the first time. CMake will use the default generator on the first attempt, if no generator is provided via the command line or via environment variable. So try adding the command line option -G to specify the generator like this:
cmake -G "Unix Makefiles" .
Then, on subsequent CMake runs, the generator setting will be cached and you no longer need to provide the -G generator option.
As a side note, you can simply provide the path to your top-level CMakeLists.txt file. So if it's in the current directory, you can just use . for the path.
The documentation is pretty explicit The value of this variable should never be modified by project code. A generator may be selected via the cmake(1) -G option, interactively in cmake-gui(1), or via the CMAKE_GENERATOR environment variable.
You can always make a CMake script that runs CMake with the proper options to create the project.
You may want to keep watch on CMAKE_VERBOSE_MAKEFILE because This variable is a cache entry initialized (to FALSE) by the project() command. I wouldn't be surprised if it doesn't work as shown in your script. Instead You'd probably have to add a -D option on the command line to set it. https://bytefreaks.net/programming-2/make-building-with-cmake-verbose

Is it possible to alter CMAKE_MODULE_PATH from CMake commandline?

Edit: The accepted answer actually shows that it is pretty normally possible to set CMAKE_MODULE_PATH as any other CMake variable e.g. via the -DCMAKE_MODULE_PATH path CLI parameter. It seems that in my case there is some included CMake script that calls set(CMAKE_MODULE_PATH /library_path), which erases all previous paths set to the variable. That's why I couldn't get the variable to do what I wanted it to do. I'll leave the question here in case anybody else faces this kind of situation.
I'm building a (3rd party) project that uses the Protobuf library (but this question is general). My system has a system-wide install of a newer version of Protobuf than the project is compatible with. So I've downloaded and compiled from source an older version of Protobuf.
The project uses CMake, and in its CMakeLists.txt, there is:
find_package(Protobuf REQUIRED)
Which, however, finds the (incompatible) system install. Of course, CMake doesn't know about my custom build of Protobuf. But how do I tell it?
I've created a FindProtobuf.cmake file in, say, ~/usr/share/cmake-3.0/Modules/ and want the build process to use this one for finding Protobuf. But I haven't succeeded forcing CMake to pick up this one and not the system one. I think the reason is quite obvious from the CMake docs of find_package:
The command has two modes by which it searches for packages: “Module” mode and “Config” mode. Module mode is available when the command is invoked with the above reduced signature. CMake searches for a file called Find<package>.cmake in the CMAKE_MODULE_PATH followed by the CMake installation. If the file is found, it is read and processed by CMake. ... If no module is found and the MODULE option is not given the command proceeds to Config mode.
So until I succeed to change CMAKE_MODULE_PATH, CMake will just pick up the FindProtobuf.cmake installed to the default system path and won't ever proceed to the "Config" mode where I could probably make use of CMAKE_PREFIX_PATH.
It's important for me to not edit the CMakeLists.txt since it belongs to a 3rd party project I don't maintain.
What I've tried (all without success):
calling CMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules cmake ... (the env. variable is not "transferred" to the CMake variable with the same name)
calling cmake -DCMAKE_MODULE_PATH=~/usr/share/cmake-3.0/Modules ... (doesn't work, probably by design?)
calling Protobuf_DIR=path/to/my/protobuf cmake ... (the project doesn't support this kind of override for Protobuf)
It seems to me that, unfortunately, the only way to alter the CMAKE_MODULE_PATH used by find_package is to alter it from within CMakeLists.txt, which is exactly what I want to avoid.
Do you have any ideas/workarounds on how not to touch the CMakeLists.txt and still convince find_package to find my custom Protobuf?
For reference, the CMake part of this project is on github .
As a direct answer to your question, yes, you can set CMAKE_MODULE_PATH at the command line by running cmake -DCMAKE_MODULE_PATH=/some/path -S /path/to/src -B /path/to/build.
But that probably doesn't do what you want it to do; see below.
The Bitbucket link you supplied is dead, but here are a few suggestions that might help.
Avoid writing your own find modules, especially when the upstream supplies CMake config modules.
You can direct CMake to your custom Protobuf installation by setting one of CMAKE_PREFIX_PATH or Protobuf_ROOT (v3.12+) to the Protobuf install root.
You can tell find_package to try CONFIG mode first by setting CMAKE_FIND_PACKAGE_PREFER_CONFIG to true (v3.15+). Then set Protobuf_DIR to the directory containing ProtobufConfig.cmake.
Failing all else, you can manually set the variables documented in CMake's own FindProtobuf module, here: https://cmake.org/cmake/help/latest/module/FindProtobuf.html
All these variables can be set at the configure command line with the -D flag.
There are very few environment variables that populate CMake variables to start and I would avoid relying on them. There is an exhaustive list here: https://cmake.org/cmake/help/latest/manual/cmake-env-variables.7.html. CMAKE_MODULE_PATH is not among them.

Forcing PROTOBUF_GENERATE_CPP To Complete When Using Make Multithreaded

Given a simple cmake file such as
PROTOBUF_GENERATE_CPP( ProtoSources ProtoHeaders Example.proto )
ADD_LIBRARY( Example SHARED Example.cpp )
is there a way force the PROTOBUF_GENERATE_CPP to complete before the next step begins when using make -j8?
(Context: when using cmake . ; make -j8 on a cmake file, the first run almost always fails because the protobuf files havn't finished processing by the time the library is being compiled. The second run always works fine but it would be nice to avoid having to run make twice everytime.)
I assume that 'Example' depends on ProtoSources and/or ProtoHeaders.
Otherwise the build order wouldn't matter.
You will need to tell CMake that there is a dependency between 'Example' and the generated files.
Try adding these lines to your script
add_custom_target(generated_code DEPENDS ${ProtoSources} ${ProtoHeaders})
add_dependencies(Example generated_code)

How to do Parallel CMake ExternalProject Builds

When building a CMake project (e.g. on Windows), I can perform a parallel build by executing the following command:
cmake --build . -- /m
The /m switch is passed to msbuild and I get parallelized builds. However, if I have some external project in my CMakeLists, that switch is not passed through to its build command.
What's the best way to ensure my ExternalProject is built in parallel? I don't want to hardcode a BUILD_COMMAND if I can avoid it.
In CMake 3.12, support was added to kick off parallel jobs from within cmake.
The previous versions only supported this via passthrough arguments after the --, which understandably wouldn't pass through to external builds. Though, I'm not sure if the new support works for ExternalProject, it'd be great to try and report back if it works!
I had the same problem with make based external_projects. I ended up with the solution to pass the -j8 flag via a cmake cached variable.
set(EXTERNAL_BUILD_ARGS "/m" CACHE STRING "flags for external project builds")