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

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.

Related

How to use find_package in CMake? (Example: GMP library)

I'm trying to use find_package to include libraries in CMake.
This question talks about how to tell CMake to link to the GMP library (external). I am trying to follow the steps of the answer there but do not have any of the <name>Config.cmake or <name>-config.cmake files, as mentioned by some of the comments, which appears to be the default. The answer does not mention any solution for when you don't know how to get/find these files. The comments to that answer link to an old website (external) with a lot of broken links, that describes a list of Load Modules. It's unclear to me where these modules come from and how to get them.
According to the official CMake documentation (external), if the configuration files are not found, find_package falls back from "Module Mode" to "Config Mode". I don't understand what this means and in what cases this would be relevant, especially since the documentation discourages reading about "Config Mode".
The documentation says that
The file is first searched in the CMAKE_MODULE_PATH, then among the Find Modules provided by the CMake installation.
I am still confused about whether these configuration files are supposed to come with CMake or with the library in question and where they are supposed to be located. Probably both are possible but how does one know in a specific case?
Example code, trying to follow modern best practices:
# CMakeLists.txt (not working)
cmake_minimum_required(VERSION 3.2) # I have no idea what version I actually need
project (GMP_demo_project)
# Enable C++17 standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(GMP REQUIRED)
# Create the executable from sources
add_executable(GMP_demo GMP_demo.cpp)
target_link_libraries(GMP_demo gmp gmpxx)
The code outputs an error message along the lines of
CMake Error at CMakeLists.txt:10 (find_package):
By not providing "FindGMP.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "GMP", but
CMake did not find one.
Could not find a package configuration file provided by "GMP" with any of
the following names:
GMPConfig.cmake
gmp-config.cmake
Add the installation prefix of "GMP" to CMAKE_PREFIX_PATH or set "GMP_DIR"
to a directory containing one of the above files. If "GMP" provides a
separate development package or SDK, be sure it has been installed.
Question: How does one, in general, obtain and organize these configuration files (CMake Load Modules)? How can one expect another user to have these files on his system? My question is intended to be general and only use GMP as an example (although I am in fact interested in being able to use it).
Just as an aside, I can compile, link and execute my demo code just fine using gcc GMP_demo.cpp -lstdc++ -lgmp after having installed GMP as suggested by the library documentation. The problem is just getting CMake to do it. I can also just give CMake the absolute path of the library, which would of course be much easier but not portable (assuming one can get find_package to actually work and be portable with reasonable amounts of work).
How does one, in general, obtain and organize these configuration files (CMake Load Modules)?
Broadly speaking, there are three buckets these fall into:
Files provided directly by the package. This is the ideal solution, and would be what CMake calls Config mode. There would be a file called GMPConfig.cmake which cmake could find by searching preconfigured paths, or by providing a specific path at configuration time (cmake -DGMP_Dir=/path/to/GMP/install/root). The advantages of this approach are that generation of GMPConfig.cmake is mostly automatic, and the libraries can include things like installation paths and compilation flags. The disadvantage is that the library develops have to actually go to the effort of leveraging modern CMake, and not everybody does this.
Files provided directly by CMake. For common packages (e.g., boost) CMake ships FindXXX.cmake files that search well-known paths and take care of this for you. These work identically to the above from an end-user perspective, but which Find modules are available depends on the version of CMake you have installed.
Files provided by some random person that are copy/pasted into projects. How these works depends on the person who wrote it, so you'll have to read their documentation. Use your favorite search engine and try to find FindGMP.cmake, then drop it in a module folder somewhere and update CMAKE_MODULE_PATH appropriately.
How can one expect another user to have these files on his system?
It's your job to install whatever dependencies a package requires. Anything using modern CMake (bullet 1 listed above) should install the XXXConfig.cmake file as part of its installation. If a library is built by something other than CMake, you'd have to either hope for bullet #2, or find/write your own FindXXX.cmake file (bullet #3).
For your specific case, you might be better off with find_library, since your sample compilation line looks like it just needs to link.

CMake does not find includes / libraries

I want to use some third-party headers (or a library) in a project that uses CMake. But it does not find the headers (the library). Why does CMake not find it?
CMake's find routines look for headers and libraries at some specific places. This includes the PATH variable, and the default locations for installed software, e.g., for many Linuces /usr/bin. Additionally, it evaluates the CMake variable CMAKE_PREFIX_PATH.
You have two possibilities to help CMake finding the required files:
Check whether your software is properly installed. For self-compiled software, that's usually done by make install or similar. If you use packages (RPM or deb), they are in general installed and can be found with the PATH variable.
If you don't want or can install the software, add its path to the CMAKE_PREFIX_PATH variable. Either pass it to the CMake call cmake -DCMAKE_PREFIX_PATH=/path/to/software .. or edit/add the according field in the CMake-GUI.
You have to delete the CMakeCache.txt, otherwise CMake will not find the library, because it does not check but use the cached result. Re-run CMake and it should work.
Evaluation order
If you have multiple versions of a library on your system, add the one you want to use to the CMAKE_PREFIX_PATH as the variables gets evaluated prior to the system path variables.
Module-specific variables
Some modules offer specific variables like mylib_DIR or mylib_ROOT to indicate the search path. Its use is discouraged and they are only left for backwards-compatibility. New modules don't have these modules and commits adding such variables are rejected by the CMake developers.
Documentation
More details on how CMake searches files and in which order can be found in the documentation: https://cmake.org/cmake/help/latest/command/find_library.html

What does 'module' in cmake 'pkg_check_modules' stand for?

I am building a certain module in GNU Radio. (Let's call it my-module.)
GNU Radio uses cmake to build and intall a my-module.
In the project, I need to use a module that was made by others. This can be it++ and other gnuradio-modules. And I will be using a gnuradio module. (Let's call it other-module.)
To use other modules in my gr-module, I need to use find_package, pkg_check_modules and find_library to tell 'I will be using pre-built modules'
And pkg_check_modules(PC_ITPP itpp) can successfully detect it++.
But I am having difficulties in finding other-module. As I put pkg_check_modules(PC_OTHER_MODULE other_module), it can't detect the module.
What I am curious is, what does module in pkg_check_modules(<PREFIX> <MODULE>) stand for and how and where does cmake find a given module?
Of course, I don't think it's a kernel module since I don't see it++ in the list of kernel modules. Then, are they cmake-modules? I don't think so, neither, becausecmake --help-module-list doesn't show it++.
Is there a special file that contains a list of modules that can be referred by cmake? If then, should it++and other library, modules be registered in that file at the build and installation steps in order to be recognized as modules by cmake?
pkg_check_modules(<PREFIX> <MODULE>) invokes pkg-config, queries for <MODULE> and returns the result in variables which have names beginning with <PREFIX>_. Thus module is the name of the software you / pkg-config are looking for.
If your other_module is not found, try directly with pkg-config, whether pkg-config knows about other_module, use pkg-config --modversion other_module to do so.
With pkg-config --list-all you get a list of all modules known by pkg-config.
If your 3rd party software is not part of pkg-config and there is no FindOTHER_MODULE.cmake provided by CMake, you can google for it. Maybe someone else wrote exactly that test and you can use it. Or you have to write your own test using find_includs, find_library et al.

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.

Is there any interactive shell for module development in cmake?

CMake is awesome, especially with lots of modules (FindOOXX). However, when it comes to write a FindXXX module, a library XXX which your project depends, it's not that easy to handle for non-cmake-expert. I sometimes encounter a library without support to CMake, and I like to make one for it. I'm wondering if there is any interactive shell while writing/testing cmake modules?
Are you writing FindXXX for project "XXX" or is "XXX" a dependency of your project that you're trying to find? If the former, you should instead write a file called XXX-config.cmake (or XXXConfig.cmake) and install it into one of the directories mentioned in the docs for find_package. In general, XXX-config.cmake files are for projects which are expected to be found by CMake (and installed by the project itself) and FindXXX.cmake files are for projects which don't support CMake (and usually have to support finding any version of XXX).
That said, for FindXXX.cmake, usually you just need a few find_file (e.g., for headers), some find_library calls, or even just a single pkg_check_module from FindPkgConfig.cmake followed by a find_package_handle_standard_args call (use include(FindPackageHandleStandardArgs) to get it). FPHSA makes writing proper Find modules a breeze.
For XXX-config.cmake files, I have typically used configure_file to generate two versions: one for the install (which includes your install(EXPORT) file) and one for the build tree (generated by export() calls). Using this, other useful variables can be accurately set such as things like "which exact version of Boost was used" or "was Python support compiled in" so that dependent projects can get a better picture of what the dependency looks like.
I have also recently discovered that CMake ships with the CMakePackageConfigHelpers module which is supposed to help with making these files. There looks to be quite a bit of documentation for it.