I'm trying to get a cross-plattform build system working using CMake. Now the software has a few dependencies. I compiled them myself and installed them on my system.
Some example files which got installed:
-- Installing: /usr/local/share/SomeLib/SomeDir/somefile
-- Installing: /usr/local/share/SomeLib/SomeDir/someotherfile
-- Installing: /usr/local/lib/SomeLib/somesharedlibrary
-- Installing: /usr/local/lib/SomeLib/cmake/FindSomeLib.cmake
-- Installing: /usr/local/lib/SomeLib/cmake/HelperFile.cmake
Now CMake has a find_package()
which opens a Find*.cmake
file and searches after the library on the system and defines some variables like SomeLib_FOUND
etc.
My CMakeLists.txt contains something like this:
set(CMAKE_MODULE_PATH "/usr/local/lib/SomeLib/cmake/;${CMAKE_MODULE_PATH}")
find_package(SomeLib REQUIRED)
The first command defines where CMake searches after the Find*.cmake
and I added the directory of SomeLib
where the FindSomeLib.cmake
can be found, so find_package()
works
as expected.
But this is kind of weird because one of the reasons why find_package()
exists is to get away from non-cross-plattform hard coded paths.
How is this usually done? Should I copy the cmake/
directory of SomeLib
into my project and set the CMAKE_MODULE_PATH
relatively?
If you are running
cmake
to generateSomeLib
yourself (say as part of a superbuild), consider using the User Package Registry. This requires no hard-coded paths and is cross-platform. On Windows (including mingw64) it works via the registry. If you examine how the list of installation prefixes is constructed by theCONFIG
mode of the find_packages() command, you'll see that the User Package Registry is one of elements.Brief how-to
Associate the targets of
SomeLib
that you need outside of that external project by adding them to an export set in theCMakeLists.txt
files where they are created:Create a
XXXConfig.cmake
file forSomeLib
in its${CMAKE_CURRENT_BUILD_DIR}
and store this location in the User Package Registry by adding two calls to export() to theCMakeLists.txt
associated withSomeLib
:Issue your
find_package(SomeLib REQUIRED)
commmand in theCMakeLists.txt
file of the project that depends onSomeLib
without the "non-cross-platform hard coded paths" tinkering with theCMAKE_MODULE_PATH
.When it might be the right approach
This approach is probably best suited for situations where you'll never use your software downstream of the build directory (e.g., you're cross-compiling and never install anything on your machine, or you're building the software just to run tests in the build directory), since it creates a link to a .cmake file in your "build" output, which may be temporary.
But if you're never actually installing
SomeLib
in your workflow, callingEXPORT(PACKAGE <name>)
allows you to avoid the hard-coded path. And, of course, if you are installingSomeLib
, you probably know your platform,CMAKE_MODULE_PATH
, etc, so @user2288008's excellent answer will have you covered.If you don't trust CMake to have that module, then - yes, do that. That's what I do as a fallback.
Note that the
FindFoo.cmake
modules are each a sort of a bridge between platform-dependence and platform-independence - they look in various platform-specific places to obtain paths in variables whose names is platform-independent.You don't need to specify the module path per se. CMake ships with its own set of built-in find_package scripts, and their location is in the default CMAKE_MODULE_PATH.
The more normal use case for dependent projects that have been CMakeified would be to use CMake's external_project command and then include the Use[Project].cmake file from the subproject. If you just need the Find[Project].cmake script, copy it out of the subproject and into your own project's source code, and then you won't need to augment the CMAKE_MODULE_PATH in order to find the subproject at the system level.
Command
find_package
has two modes:Module
mode andConfig
mode. You are trying to useModule
mode when you actually needConfig
mode.Module mode
Find<package>.cmake
file located within your project. Something like this:CMakeLists.txt
content:Note that
CMAKE_MODULE_PATH
has high priority and may be usefull when you need to rewrite standardFind<package>.cmake
file.Config mode (install)
<package>Config.cmake
file located outside and produced byinstall
command of other project (Foo
for example).foo
library:Simplified version of config file:
By default project installed in
CMAKE_INSTALL_PREFIX
directory:Config mode (use)
Use
find_package(... CONFIG)
to includeFooConfig.cmake
with imported targetfoo
:Note that imported target is highly configurable. See my answer.
Update