What is the point of using find_package () if you still need to specify CMAKE_MODULE_PATH?

I am trying to create a cross-plattform build system using CMake. The software now has several dependencies. I myself compiled and installed them in my system.

Some sample files that were 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 find_package() , which opens the Find*.cmake and performs a search after the library in the system and defines some variables, such as 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 determines where CMake searches after Find*.cmake , and I added the SomeLib directory where FindSomeLib.cmake can be found, so find_package() works as expected.

But this is rather strange, because one of the reasons find_package() exists is to get away from disjoint hard coded paths.

How is this usually done? Should I copy the cmake/ SomeLib to my project and set CMAKE_MODULE_PATH relative?

+131
cmake
Dec 23 '13 at 15:57
source share
4 answers

The find_package command has two modes: Module mode and Config . You try to use Module mode when you really need Config mode.

Module mode

Find<package>.cmake file located inside your project. Something like that:

 CMakeLists.txt cmake/FindFoo.cmake cmake/FindBoo.cmake 

CMakeLists.txt :

 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") find_package(Foo REQUIRED) # FOO_INCLUDE_DIR, FOO_LIBRARIES find_package(Boo REQUIRED) # BOO_INCLUDE_DIR, BOO_LIBRARIES include_directories("${FOO_INCLUDE_DIR}") include_directories("${BOO_INCLUDE_DIR}") add_executable(Bar Bar.hpp Bar.cpp) target_link_libraries(Bar ${FOO_LIBRARIES} ${BOO_LIBRARIES}) 

Please note that CMAKE_MODULE_PATH has high priority and can be useful when you need to rewrite the standard Find<package>.cmake file.

Configuration Mode (Installation)

<package>Config.cmake file located outside and created by the install command of another project (for example, Foo ).

Foo library:

 > cat CMakeLists.txt cmake_minimum_required(VERSION 2.8) project(Foo) add_library(foo Foo.hpp Foo.cpp) install(FILES Foo.hpp DESTINATION include) install(TARGETS foo DESTINATION lib) install(FILES FooConfig.cmake DESTINATION lib/cmake/Foo) 

A simplified version of the configuration file:

 > cat FooConfig.cmake add_library(foo STATIC IMPORTED) find_library(FOO_LIBRARY_PATH foo HINTS "${CMAKE_CURRENT_LIST_DIR}/../../") set_target_properties(foo PROPERTIES IMPORTED_LOCATION "${FOO_LIBRARY_PATH}") 

By default, the project is installed in the CMAKE_INSTALL_PREFIX directory:

 > cmake -H. -B_builds > cmake --build _builds --target install -- Install configuration: "" -- Installing: /usr/local/include/Foo.hpp -- Installing: /usr/local/lib/libfoo.a -- Installing: /usr/local/lib/cmake/Foo/FooConfig.cmake 

Configuration Mode (use)

Use find_package(... CONFIG) to enable FooConfig.cmake with the imported target Foo :

 > cat CMakeLists.txt cmake_minimum_required(VERSION 2.8) project(Boo) # import library target `foo` find_package(Foo CONFIG REQUIRED) add_executable(boo Boo.cpp Boo.hpp) target_link_libraries(boo foo) > cmake -H. -B_builds -DCMAKE_VERBOSE_MAKEFILE=ON > cmake --build _builds Linking CXX executable Boo /usr/bin/c++ ... -o Boo /usr/local/lib/libfoo.a 

Note that the imported target is highly customizable. See my answer.

Update

+167
Dec 31 '14 at 12:00
source share

You do not need to specify the path to the module as such. CMake comes with its own set of find_package built-in scripts, and their location is in CMAKE_MODULE_PATH by default.

A more normal use case for dependent projects that have been processed by CMake would be to use the CMake external_project command and then include the Use [Project] .cmake file from the subproject. If you just need a Find [Project] .cmake script, copy it from the subproject and into your own project source code, and then you do not need to increase CMAKE_MODULE_PATH to find the subproject at the system level.

+1
Dec 31 '14 at 2:26
source share

How is this usually done? Should I copy the cmake/ SomeLib directory to my project and set relative to CMAKE_MODULE_PATH?

If you do not trust CMake to have this module, then - yes, do it - sort of: Copy find_SomeLib.cmake and its dependencies into your cmake/ directory. This is what I do as a fallback. This is an ugly solution, though.

Note that FindFoo.cmake modules is a kind of bridge between platform dependency and platform independence - they search in various platform-specific places to find paths in variables whose names are platform-independent.

+1
Jan 15 '17 at 23:11
source share

If you run cmake to generate SomeLib (say, as part of a super build), consider using a custom package registry . It does not require hard-coded paths and is cross-platform. On Windows (including mingw64), it works through the registry. If you look at how the list of installation prefixes is created in the CONFIG mode of the find_packages () command, you will see that the user packages registry is one of the elements.

Quick guide

SomeLib you SomeLib goals outside this external project by adding them to the export set in the CMakeLists.txt files where they are created:

 add_library(thingInSomeLib ...) install(TARGETS thingInSomeLib Export SomeLib-export DESTINATION lib) 

Create the XXXConfig.cmake file for SomeLib in its ${CMAKE_CURRENT_BUILD_DIR} and save this location in the user package registry by adding two export () calls to CMakeLists.txt associated with SomeLib :

 export(EXPORT SomeLib-export NAMESPACE SomeLib:: FILE SomeLibConfig.cmake) # Create SomeLibConfig.cmake export(PACKAGE SomeLib) # Store location of SomeLibConfig.cmake 

find_package(SomeLib REQUIRED) in the project’s CMakeLists.txt file, which depends on SomeLib without the “ SomeLib hard-coded paths” associated with CMAKE_MODULE_PATH .

When can this be the right approach

This approach is probably best suited for situations where you will never use your software below the build directory (for example, you cross-compile and never install anything on your computer, or you only create software to run tests in the directory assemblies) because it creates a link to the .cmake file in the output of the “assembly”, which may be temporary.

But if you actually never install SomeLib in your SomeLib , calling EXPORT(PACKAGE <name>) allows you to avoid a hard-coded path. And of course, if you install SomeLib , you probably know your platform, CMAKE_MODULE_PATH etc., so @ user2288008 an excellent answer will catch you.

+1
Jul 08 '18 at 9:32
source share



All Articles