So if I'm making a package with cmake/cpack, there must be a variable already set in cmake that tells it where to put the *.cmake files that will be used by find_package for my module...right?
What's that variable?
According to the documentation of find_package, it is either CMAKE_MODULE_PATH, but I would not recommend that, otherwise you can put your <name>-config.cmake files anywhere, as long as you specify the path in your find_package call.
Otherwise system-wide paths might be set, being CMAKE_SYSTEM_PREFIX_PATH, CMAKE_SYSTEM_FRAMEWORK_PATH andCMAKE_SYSTEM_APPBUNDLE_PATH.
from the documentation (removed unnecessary information):
find_package(<package> ...
[CONFIG]
...
[NAMES name1 [name2 ...]]
[CONFIGS config1 [config2 ...]]
[HINTS path1 [path2 ... ]]
[PATHS path1 [path2 ... ]]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
...)
It will search for <NAMES>-config.cmake in all PATHS and all HINTS (in that order), as well as predefines CMAKE Paths.
The exact search order (from the documentation cited above):
Search paths specified in cmake-specific cache variables. These are intended to be used on the command line with a -DVAR=value. This can be skipped if NO_CMAKE_PATH is passed
Search paths specified in cmake-specific environment variables. These are intended to be set in the user’s shell configuration. This can be skipped if NO_CMAKE_ENVIRONMENT_PATH is passed
Search paths specified by the HINTS option. These should be paths computed by system introspection, such as a hint provided by the location of another item already found. Hard-coded guesses should be specified with the PATHS option.
Search the standard system environment variables. This can be skipped if NO_SYSTEM_ENVIRONMENT_PATH is passed. Path entries ending in /bin or /sbin are automatically converted to their parent directories
The Variable
I've found the variable named CMAKE_ROOT to include the path to the default cmake modules:
CMAKE_ROOT=/usr/share/cmake-3.10
This path is what it is set to under Ubuntu 18.04 which is correct compared to the cmake version on that platform:
$ cmake --version
cmake version 3.10.2
CMake suite maintained and supported by Kitware (kitware.com/cmake).
How do you find such hidden variables?
A while back, I stole a piece of code I found on stackoverflow which I can use to display all the variables at a given point in the processing of my CMakeLists.txt files. I create a command I called DumpCMakeVariables.
To use it (assuming the Modules directory is somehow accessible):
find_package(DumpCMakeVariables)
DumpCMakeVariables()
If you have an idea of the variable name, then you can include a valid regular expression as the parameter of that function. To only list variables that start with "CMAKE_" write:
DumpCMakeVariables("^CMAKE_")
Then re-run your configuration process, something like this:
cmake <path to source> | less -S
and search for a specific variable or what your think the value should be. In out case here:
/usr.share.cmake
That will eventually point us to CMAKE_ROOT.
Other Installation Path
Note that I also install files directly under:
/usr/share/cmake/<name>/<name>Config.cmake
And if you want to include a version:
/usr/share/cmake/<name>/<name>ConfigVersion.cmake
where <name> is generally Camel Case.
Having such a directory allows you to have many sub-.cmake files that your main configuration uses to find this or that. So it is a way to make it much cleaner if you need many files instead of just one.
That being, that /usr/share/cmake directory works great. However, certain types of modules should certainly be installed under CMAKE_ROOT to 100% work as expected.
Catch2 also uses that scheme:
# This variable is used in some subdirectories, so we need it here, rather
# than later in the install block
set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
Related
Upon reading about CMake policy 74 - https://cmake.org/cmake/help/latest/policy/CMP0074.html
[...] now searches prefixes specified by the _ROOT CMake variable and the ROOT environment variable. Package roots are maintained as a stack so nested calls to all find* commands inside find modules and config packages also search the roots as prefixes.
Does this mean <PackageName>_ROOT need not be included in the find_* paths explicitly?
Does this mean <PackageName>_ROOT will be checked automatically?
Yes, but this only applies to CMake 3.12 and greater, as stated in the policy documentation:
In CMake 3.12 and above the find_package(<PackageName>) command now searches prefixes specified by the <PackageName>_ROOT CMake variable and the <PackageName>_ROOT environment variable.
This also only applies to find_* commands within find modules and config packages.
This behavior is stated explicitly in the documentation for all of the find_* commands. For example, here is a snippet from the find_library() documentation (important section bolded):
If NO_DEFAULT_PATH is not specified, the search process is as follows:
If called from within a find module or any other script loaded by a call to find_package(<PackageName>), search prefixes unique to the current package being found. Specifically, look in the <PackageName>_ROOT CMake variable and the <PackageName>_ROOT environment variable. The package root variables are maintained as a stack, so if called from nested find modules or config packages, root paths from the parent’s find module or config package will be searched after paths from the current module or package. In other words, the search order would be <CurrentPackage>_ROOT, ENV{<CurrentPackage>_ROOT}, <ParentPackage>_ROOT, ENV{<ParentPackage>_ROOT}, etc. This can be skipped if NO_PACKAGE_ROOT_PATH is passed or by setting the CMAKE_FIND_USE_PACKAGE_ROOT_PATH to FALSE.
Also note, the <PackageName>_ROOT variable will not be used for the search if the find module is called with NO_DEFAULT_PATH or NO_PACKAGE_ROOT_PATH.
We have a CMakeLists.txt that links (for instance) opencv to our various binaries. This is done as follow:
find_package(OpenCV REQUIRED core imgproc highgui contrib)
target_link_library(XXX opencv_core)
We also would like to allow the person building the library to provide its own opencv library. It seems that this could be done setting -DCMAKE_PREFIX_PATH to the right path.
cmake -DCMAKE_PREFIX_PATH=".../mybuild/include;.../mybuild/lib" .
However I would like to be sure the library used is exactly the one specified by the client (i.e. if there is nothing in /mybuild/lib the configuration fails).
How can I allow somebody building the library to override the library used ? (if nothing is specified it should fall back to find_package-s)
In short
If the package provides <package>Config.cmake script, user may specify <package>_DIR CMake variable for locate this script.
Searching other places in that case may be disabled with NO_DEFAULT_PATH option for find_package().
If a package is searched with Find<package>.cmake script, there is no (generic) way for disable searching other places if user provides hint variable but it is wrong.
Explanations
Firstly, CMAKE_PREFIX_PATH provides additional installation tree for all packages. As this variable is applied to all find_package() calls, it is not wise to require all packages to be found under it.
When talk about the ways for specify installation directory for specific package, we need to distinguish two kinds of "find" scripts:
<package>Config.cmake (or some alternative names, see find_package documentation).
These scripts are shipped with the packages themselves. And there is universal way for user to specify location of such packages: CMake variable <package>_DIR, which should point to the directory with *Config.cmake script.
While default behaviour of find_package() is treating <package>_DIR variable as an additional hint, passing NO_DEFAULT_PATH option disables all implicit paths:
if(<package>_DIR) # Variable is set by the user or by previous `cmake` run.
# Search only under given directory.
find_package(<package> NO_DEFAULT_PATH)
else()
# Search everywhere (as documented for 'find_package').
find_package(<package>)
endif()
Find<package>.cmake.
This script either is shipped with CMake or should be shipped with the project.
Most of such scripts allows to hint about package location with variable (CMake or environment one) like <package>_DIR, <package>_ROOT or so.
However, almost all such scripts treat hint variable only as additional search place, so if variable is set to wrong value, they simply ignore it. And without modifying the script you cannot change that behavior.
I would also like to know the default variables which are set when find_package(<package>) finds <package> in Linux (Ubuntu) ?
Turning my comment into an answer
If you have to melt it down the "single most important" path it would be CMake's own module path containing pre-shipped Find... modules.
The most important global variable variable to point CMake to custom paths would be CMAKE_MODULE_PATH.
If you want to see which directories CMake is search in your case just call
cmake -D CMAKE_FIND_DEBUG_MODE=ON ..
The whole "search algorithm" is documented in find_package() command documentation:
Search paths specified in cmake-specific cache variables. This can be skipped if NO_CMAKE_PATH is passed:
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
Search paths specified in cmake-specific environment variables. This can be skipped if NO_CMAKE_ENVIRONMENT_PATH is passed:
<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
Search paths specified by the HINTS option. Hard-coded guesses should be specified with the PATHS option.
Search the standard system environment variables. This can be skipped if NO_SYSTEM_ENVIRONMENT_PATH is passed:
PATH
Search paths stored in the CMake User Package Registry. This can be skipped if NO_CMAKE_PACKAGE_REGISTRY is passed or by setting the CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY to TRUE.
Search cmake variables defined in the Platform files for the current system. This can be skipped if NO_CMAKE_SYSTEM_PATH is passed:
CMAKE_SYSTEM_PREFIX_PATH
CMAKE_SYSTEM_FRAMEWORK_PATH
CMAKE_SYSTEM_APPBUNDLE_PATH
Search paths stored in the CMake System Package Registry. This can be skipped if NO_CMAKE_SYSTEM_PACKAGE_REGISTRY is passed or by setting the CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY to TRUE.
Search paths specified by the PATHS option. These are typically hard-coded guesses.
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 .
cmake version 2.8.4
I have the following apache portable runtime libraries that I have compiled myself and want my application to link against.
My project directory where my apr libraries are:
gw_proj/tools/apr/libs
In my CMakeLists.txt I have the following:
FIND_LIBRARY(APRUTIL NAMES "aprutil-1"
PATHS ${PROJECT_SOURCE_DIR}/tools/apr/libs)
My problem is on a machine that already has the apache portable runtime already installed it will look for it in this folder:
/usr/lib
So will always ignore my custom path.
How can I force the FIND_LIBRARY to always look in my custom directory:
gw_proj/tools/apr/libs
Many thanks for any suggestions
You can specify the search order using one or more of NO_DEFAULT_PATH, NO_CMAKE_ENVIRONMENT_PATH
, NO_CMAKE_PATH, NO_SYSTEM_ENVIRONMENT_PATH, NO_CMAKE_SYSTEM_PATH, CMAKE_FIND_ROOT_PATH_BOTH, ONLY_CMAKE_FIND_ROOT_PATH, orNO_CMAKE_FIND_ROOT_PATH.
From the docs for find_library:
The default search order is designed to be most-specific to least-specific for common use cases. Projects may override the order by simply calling the command multiple times and using the NO_* options:
find_library(<VAR> NAMES name PATHS paths... NO_DEFAULT_PATH)
find_library(<VAR> NAMES name)
Once one of the calls succeeds the result variable will be set and stored in the cache so that no call will search again.
So in your case, you can do
FIND_LIBRARY(APRUTIL NAMES "aprutil-1"
PATHS ${PROJECT_SOURCE_DIR}/tools/apr/libs NO_DEFAULT_PATH)