The example I presented in my talk has a specific requirement:
I want to look for a specific (configuration of a) set of external libraries, that should be used throughout my entire program!
So, this external dependency is some kind of global dependency for my entire project. Each target which uses that dependency has to use it with the same settings.
Explanation on the example from the slides
For simpler reasoning I am reproducing the code from my presentation here:
# ./external/boost/CMakeLists.txt -- Traditional/Modern CMake
set( BOOST_VERSION 1.58.0 )
# Settings for finding correct Boost libraries.
set( Boost_USE_STATIC_LIBS FALSE )
set( Boost_USE_MULTITHREADED TRUE )
set( Boost_USE_STATIC_RUNTIME FALSE )
set( Boost_ADDITIONAL_VERSIONS "${BOOST_VERSION}" )
set( Boost_COMPILER "-gcc" )
# Search for Boost libraries.
find_package( Boost ${BOOST_VERSION} EXACT REQUIRED
COMPONENTS program_options
graph )
# Make found targets globally available.
if ( Boost_FOUND )
set_target_properties( Boost::boost
Boost::program_options
Boost::graph
PROPERTIES IMPORTED_GLOBAL TRUE )
endif ()
What I am doing here is to look for an installed Boost libraries collection in version 1.58.0, but specifically only for the header-only part and the Boost.ProgramOptions and Boost.Graph shared libraries.
Additionally I am saying, the shared libraries need to be compiled in such a way that they support multi-threading and are linked against a dynamic runtime. (The additional Boost_COMPILER
variable indicates that they should have been compiled with the GCC compiler, although for newer built Boost versions that variable should probably contain the GCC version, too.)
What settings-variables need to be set to find the correct libraries depends on the individual find-script for or the import-file of the library you are looking for. (For example, newer Boost libraries, in general, require a Boost_ARCHITECTURE
variable, too, to be able to find the correct libraries.)
This might then find the shared libraries with the following names:
libboost_program_options-gcc-mt-1_58.so
libboost_graph-gcc-mt-1_58.so
Due to setting the IMPORTED_GLOBAL
property the three found targets (Boost::boost
, Boost::program_options
and Boost::graph
) are made globally visible and are therefore accessible from other directories, too, and not only sub-directories.
This is fine as long as you only ever need these three Boost targets throughout your entire project and all targets are fine with linking (via target_link_libraries
) with these.
However, if one of your targets somehow requires a statically linked Boost library it cannot use these targets. In that case, you cannot use my approach because different targets need to find different libraries.
In this situation you need to do local searches only (= do not set IMPORTED_GLBOAL
).
Possible solution for you problem
If you want to give a user the chance to modify the set of variables which are needed to find your dependency, you should probably provide some CMake option
that should be set by the user and you then set these variables according to the value of the option
.
Or you can require, that these variables need to be set directly by the user. (You can always provide variables externally when calling CMake.)
If, however, two or more targets require different versions of your dependency then I do not see another way then to search for this dependency twice with different settings and not make the targets externally visible.
Other settings, that are not required for finding the correct dependency but “only” for how to use such a dependency, you should probably set through specific targets that you need to link, too, at the place where you link against the dependency.