How to set cmake parameter CMAKE_MODULE_PATH in Yocto project recipe? - cmake

I need to set CMAKE_MODULE_PATH for my recipe. How do you set it correctly? How can I add a path to CMAKE_MODULE_PATH before calling cmake?

In general, you can set the CMAKE_MODULE_PATH from the command line like this:
cmake -DCMAKE_MODULE_PATH=/path/to/your/local/modules ..
However, if using this for find_package(), I suggest checking out the documentation for how this will affect the find_package() behavior. Depending on your project setup, you may not want to universally add this path to the CMAKE_MODULE_PATH; so it may be best to set an intermediate variable instead, and use the intermediate variable to update CMAKE_MODULE_PATH only in certain cases.

Related

CMake if(DEFINED MY_COMPILE_DEF) does not work. How can I use precompile definition as conditional?

I'm trying to use a compile definition as a conditional to build a Gtest executable. The problematic CMake code is as follows:
add_compile_definitions(TEST_BENCH)
if(DEFINED TEST_BENCH)
enable_testing()
endif()
This does not work though. I've read a few similar questions and answers that have been regarding the use of ${my_var} syntax which is not the case in my code.
Can compile definitions be used in conditionals, and if so how?
Use a cmake (cache) variable, which will also allow users to configure your project properly.
set(TEST_BENCH OFF CACHE BOOL "Enables testing of your project")
if(TEST_BENCH)
add_compile_definition(TEST_BENCH)
enable_testing()
endif()
Then the user (and you) can configure your project according to their needs with the help of ccmake or cmake-gui or with cmake -DTEST_BENCH=ON. I believe target_compile_definitions is generally preferred over global add_compile_definitions.
Still, I wouldn't advise it, you can match COMPILE_DEFINITIONS variable that is modified by add_compile_definition with the TEST_BENCH and that way check if the macro is set or not.
In short, add_compile_definitions() is for source files while set() is for CMake variables. if(DEFINED) is to check your CMake or env variables thus you need to use set().
Credit to #squareskittles
https://stackoverflow.com/a/61815468/2324483

How to execute CMake's default find module from my own find module with the same name?

For some reason I want to extend a find module (FindThreads in my case) to do some specific stuff if CMake's FindThreads fails. For the ordinary developer of other parts of our software system this should happen transparently, such that s/he could call find_package(Threads) as usual, so I don't want to give my own find module an exclusive name.
My idea is to add my own FindThreads.cmake in a folder contained in the CMAKE_MODULE_PATH. Because CMAKE_MODULE_PATH has priority find_package(Threads) will execute my own FindThreads.cmake.
But, inside my own FindThreads.cmake I need to execute find_package(Threads ...) such that it executes CMake's original FindThreads.cmake. How to do that?
If that fails my own FindThreads.cmake should try to add a specific Threads lib.
Unfortunately, there is no option NO_CMAKE_MODULE_PATH for find_package to fall back to CMake's own find modules and it seems not to be possible to pass a search path (for example ${CMAKE_ROOT}/Modules) to find_package to override CMAKE_MODULE_PATH.
Versions
CMake 3.5 on Linux (Ubuntu 16.04)
CMake 3.14 on Windows
You may set CMAKE_MODULE_PATH before find_package call and restore the variable after the call:
# Save old value of CMAKE_MODULE_PATH.
set(CMAKE_MODULE_PATH_OLD ${CMAKE_MODULE_PATH})
# Temporary replace CMAKE_MODULE_PATH
set(CMAKE_MODULE_PATH "${CMAKE_ROOT}/Modules")
# Call find_package() with specific CMAKE_MODULE_PATH set.
find_package(Threads ...)
# Restore CMAKE_MODULE_PATH
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH_OLD})
Note, that FindXXX.cmake is executed in the same scope as the caller code, so restoring CMAKE_MODULE_PATH variable is needed even if your script no longer calls find_package but simply returns.
Also, it is better to use some unique variable's name instead of CMAKE_MODULE_PATH_OLD: it is possible that caller already uses that variable for its own purposes. E.g. you may add some suffix to the variable's name which related to your organization or is unlikely to be used by others.

Obtaining Vcpkg paths within a CMake script

Is there a simple way to find either the root, or the "installed" subdirectory of Microsoft's Vcpkg, from within a CMake build script? Let's assume the CMAKE_TOOLCHAIN_FILE has already been set to the standard vcpkg.cmake file.
You most likely need to set an environment variable to tell CMake where to find the toolchain file.
Possible answer: Call cmake with -DCMAKE_TOOLCHAIN_FILE=%VCPKG_ROOT%\scripts\buildsystems\vcpkg.cmake

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.

CMake requires me to manually copy CMAKE_INCLUDE_PATH

I'm trying to test a project on a cluster where I can't install some libraries in the default locations, so I'm trying to override the default CMake search path with the CMAKE_INCLUDE_PATH environment variable.
Unfortunately it doesn't seem to be picked up. I'm having to set the path explicitly with
include_directories("." $ENV{CMAKE_INCLUDE_PATH})
but this seems like a bit of a hack. So I have two questions:
Is this expected behavior?
Is there some cleaner way to add a directory to CMake's include path via an environment variable?
First of all, there is a predefined cmake variable CMAKE_INCLUDE_PATH variable that is a ";-list of directories specifying a search path for the find_file() and find_path() commands." This is not meant to specify the compiler include path.
Secondly, good use of cmake should not involve environment variables. To the extent you can, you should use the conventional cmake find_package to configure your build paths. When you need to explicitly add a path to the compiler include search path, then, yes, include_directories is what you need. But you should a cmake cache variable rather than environment variable. For details on setting a cache variable, see this page, which says
set(<variable> <value>... CACHE <type> <docstring> [FORCE])
For your example this becomes:
set(MYINCLUDE /usr/local/foo/include CACHE PATH "path to the foo include directory")
include_directories(${MYINCLUDE})
Then if you need to override the default /usr/local/foo/include, you may specify it with the command line used when invoking cmake; e.g., cmake -DMYINCLUDE=/home/foo/include .