how to use find_package in cmake? - cmake

when using
find_package(OpenSSL MODULE REQUIRED)
I got the following output
-- Found OpenSSL: /usr/local/lib/libcrypto.so (found version "2.0.0")
but when i use
find_package(OpenSSL REQUIRED PATHS /usr/local/lib/libcrypto.so)
I am getting an error.
Could not find a package configuration file provided by "OpenSSL" with any of the following names: OpenSSLConfig.cmake openssl-config.cmake
can anyone explain why this is happening and also is it the coorect way of using the find_package in the config mode.

You are essentially using 2 different behaviors.
# This way is using Basic Signature and Module Mode
# https://cmake.org/cmake/help/latest/command/find_package.html?highlight=find_package#basic-signature-and-module-mode
find_package(OpenSSL MODULE REQUIRED)
"
The command has two modes by which it searches for packages: "Module" mode and "Config" mode. The above signature selects Module mode. If no module is found the command falls back to Config mode, described below. This fall back is disabled if the MODULE option is given.
In Module mode, CMake searches for a file called Find.cmake. The file is first searched in the CMAKE_MODULE_PATH, then among the Find Modules provided by the CMake installation. If the file is found, it is read and processed by CMake. It is responsible for finding the package, checking the version, and producing any needed messages. Some find-modules provide limited or no support for versioning; check the module documentation.
"
So essentially in the first one you are using the FindOpenSLL cmake module.
"https://cmake.org/cmake/help/latest/module/FindOpenSSL.html?highlight=openssl"
Where as in the second one you are saying to not use the module CMake has written for you. So of course it is confused as to where to look for.

Related

Excluding cmake's own distribution modules with `find_package()`

Cmake includes various distribution modules (i.e., populated inside the Modules/ directory of a cmake installation; e.g., /usr/share/cmake-3.5/Modules/FindBoost.cmake).
This creates challenges when developing code that includes internal libraries with names that conflict with these distribution modules, as find_package(Xyz) finds the distribution module (/usr/share/cmake-3.5/Modules/FindXyz.cmake) rather than the user module (/home/user/opt/lib/cmake/Xyz-config.cmake). I've tried setting CMAKE_FIND_ROOT_PATH and CMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY, but to no avail.
How can I force cmake to exclude its own distribution modules when evaluating find_package()?
As an author of the project you may find "legacy" find script (FindXXX.cmake) as non-suitable for you and prefer to use "modern" config script (XXXConfig.cmake or config-xxx.cmake) instead. In that case you may pass additional CONFIG or NO_MODULE option to the find_package:
find_package(Boost NO_MODULE)
This would prevent CMake from searching FindBoost.cmake script and forces it to search BoostConfig.cmake (or config-boost.cmake).
If config script could not be found with NO_MODULE or CONFIG option, then CMake will report an error even if corresponding find script exists.
Alternatively, you may set CMAKE_FIND_PACKAGE_PREFER_CONFIG variable:
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
so CMake would check config script first. But if this script is missing, then CMake will try to use find script.
As the user of the project you may find the config script for some package nicer than the find one... but it is better to change nothing in this case: It could be that project you are using can work only with the find script, and cannot work with config one. (E.g. the project uses variables, which are created by find script to refer the libraries, but config scripts usually create IMPORTED targets).

What's the difference between find_package(MPI) and FindMPI?

As stated in the documentation for CMake 3.0, find_package(MPI) and FindMPI seem to be interchangeable? But my questions are:
What are the differences between these two?
Is that also the case for the latest version?
Also, does FindMPI provide anything similar to the option REQUIRED in find_package()?
Because FindMPI is one of the Find Modules provided by the CMake installation, the find_package(MPI) and include(FindMPI) calls are essentially equivalent. (The include() is required here to load the module; simply writing FindMPI in a CMake file will result in an error.)
The find_package() command has two modes: MODULE and CONFIG. The default is MODULE mode, and from the find_package() documentation:
In Module mode, CMake searches for a file called Find<PackageName>.cmake. The file is first searched in the CMAKE_MODULE_PATH, then among the Find Modules provided by the CMake installation.
Therefore, find_package(MPI) will search for a file called FindMPI.cmake, which is equivalent to the command include(FindMPI). This holds up, unless you have another FindMPI.cmake file defined in your CMAKE_MODULE_PATH.
While they essentially equivalent commands, calling find_package() is typically more useful, as it lets you pass arguments, such as REQUIRED, to further specify how the settings of the external project are loaded.
I seem to figure it out. find_package() and FindMPI are two different things.
While find_package() is a CMake scripting command, FindMPI is a CMake Module.
As stated in the documentation of find_package(), one can select the "Module" mode by which it searches for packages. That means, when one calls find_package(MPI), it will make use of the FindMPI module (written in the FindMPI.cmake file) to search for the MPI library.
Similar things when you try to find other packages, all of which are listed here.

Best practices with CMake with non-standard include and library directories

I have been trying to build Mozilla RR on a Linux box at work using CMake. We have a slightly eccentric arrangement where shared libraries are stored on network drives in locations like /sw/external/product-name/linux64_g63.dll/. Further, I have built some dependencies for the project in $HOME/sw/. (I am not a sudoer on this box.)
I am rather baffled as how I am supposed to communicate to CMake to look in non-standard directories. So far I have fudged:
PKG_CONFIG_PATH=$HOME/sw/capnproto-0.6.1/lib/pkconfig \
CC=gcc-6.3 CXX=g++-6.3 \
cmake \
-DCMAKE_INSTALL_PREFIX=$HOME/sw/rr-5.1.0 \
-DPYTHON_EXECUTABLE=$HOME/bin/python2 \
-DCMAKE_FIND_ROOT_PATH=$HOME/sw/libseccomp-2.2.3/ \
../src/
Which is obviously not a scalable solution, but it does at least complete the configuration successfully and emit some Makefiles.
If I omit -DCMAKE_FIND_ROOT_PATH=$HOME/sw/libseccomp-2.2.3/, CMake fails, complaining about a missing libseccomp-2.2.3 dependency. But it works if I do have that definition, telling me that CMake understands where the libseccomp-2.2.3 files are and so will properly add the paths to the necessary compiler invocations.
However, make does not succeed, because gcc fails to find a required header file from the libseccomp probject. Examining make VERBOSE=1, I find that CMake hasn't added -I$HOME/sw/libseccomp-2.2.3/include to the gcc invocation.
I feel like this is not the right approach. The other answers I have looked at tell me to modify the CMakeLists.txt file, but surely
that is not going to be scalable across multiple CMake projects, and
for each project, that will need me to maintain a separate CMakeLists.txt file for every platform (Solaris/Linux/Darwin/Cygwin) I build the software on.
Is there a canonical solution to solving this problem? Perhaps a per-site configuration file that will tell CMake how to find libraries and headers, for all projects I build on that site?
Your approach is correct, but cmake is never told to include SECCOMP - see end of this post.
The way cmake can be informed about custom dependency directory depends on how the dependency is searched (i.e. on what is written in CMakeLists.txt).
find_package/find_library/find_path/find_program
If dependency is found with one of above-mentioned commands, custom search directories can be easily added with CMAKE_PREFIX_PATH. There is no need to add full path to include, lib or bin - when package root is added find_-command will check appropriate sub-directories. CMAKE_PREFIX_PATH can be also set with environment variable.
Second option is CMAKE_FIND_ROOT_PATH. Every path added to CMAKE_FIND_ROOT_PATH list treated as separate root directory and is searched before system root directory.
Note that CMAKE_FIND_ROOT_PATH will be ignored by find_-commands with NO_CMAKE_FIND_ROOT_PATH argument.
Following four variables may be used to tune the usage of CMAKE_FIND_ROOT_PATH:
CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
CMAKE_FIND_ROOT_PATH_MODE_INCLUDE
CMAKE_FIND_ROOT_PATH_MODE_LIBRARY
CMAKE_FIND_ROOT_PATH_MODE_PROGRAM
When use of host system default libraries is undesired setting CMAKE_FIND_ROOT_PATH_MODE_INCLUDE and CMAKE_FIND_ROOT_PATH_MODE_LIBRARY to ONLY is a good practice. If dependency library or header is not found in CMAKE_FIND_ROOT_PATH the configuration will fail. If cmake is allowed search system paths too, it is most likely that errors will occur during linking step or even runtime.
See find_package docs for more details.
find_package only
All above applies to find_package command too.
find_package can operate in two modes MODULE and CONFIG.
In MODULE mode cmake uses Find[PackageName].cmake script (module) to find dependent package. CMake comes with large number of modules and custom modules can be added with CMAKE_MODULE_PATH variable. Often find-modules can be informed about custom search paths via environment or cmake variables.
E.g. FindGTest.cmake searches path stored in GTEST_ROOT variable.
If no find module is available, find_package enters CONFIG mode. If a dependency package provides [PackageName]Config.cmake or [LowercasePackageName]-config.cmake cmake can be easily informed about that package with [PackageName]_DIR variable.
Example:
CMakeLists.txt contains:
find_package(Qt5)
FindQt5.cmake is not available, but ~/Qt5/Qt5.8/lib/cmake/Qt5Config.cmake file exists, so add
-DQt5_DIR="${HOME}/Qt5/Qt5.8/lib/cmake"
to cmake call.
pkg-config
CMake can use information provided by external pkg-config tool. It is usually done with pkg_check_modules command. Directory used by pkg-config can be customized with PKG_CONFIG_PATH environment variable. According to cmake documentation instead of setting PKG_CONFIG_PATH, custom .pc-files directories can be added via CMAKE_PREFIX_PATH. If CMake version is pre-3.1, PKG_CONFIG_USE_CMAKE_PREFIX_PATH have to be set to TRUE(ON) to enable this feature.
Methods of customizing dependencies search path is defined by CMakeLists.txt content. There is no universal solution here.
And now back to missing SECCOMP headers...
In CMakeLists.txt SECCOMP header is found with
find_path(SECCOMP NAMES "linux/seccomp.h")
but I cannot find any command telling CMake to use the found header. For example:
target_include_directories(<target_name> ${SECCOMP})
or globally:
include_directories(${SECCOMP})
I belive that CMakeLists.txt should be fixed. It is not a platform dependent solution.

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.

Package vs Library

I've just started working with CMake and I noticed that they have both a find_package and a find_library. And this confuses me. Can somebody explain the difference between a package and a library in the world of programming? Or, in the world of CMake?
Appreciate it, guys!
Imagine you want to use zlib in your project, you need to find the header file zlib.h, and the library libz.so (on Linux). You can use the low-level cmake commands find_path and find_library to find them, or you can use find_package(ZLIB). The later command will try to find out all what is necessary to use zlib. It can be extra macro definitions, or dependencies.
Update, more detail about find_package: when the CMake command find_package(SomeThing) is called, as in the documentation, there are two possible modes that cmake can run:
the module mode (that searches for a file FindSomeThing.cmake)
or the config mode (that searches for a file named SomeThingConfig.cmake)
For ZLIB, there is a module named FindZLIB, shipped with CMake itself (on my Linux machine that is the file /usr/share/cmake/Modules/FindZLIB.cmake). That module is a CMake script that uses the CMake API to search for ZLIB files in default locations, or ask the user for the location if it cannot be found automatically.