Is there anyway to find library path dynamically in CMake? - cmake

I have libcurl.so in three different paths. lets say /usr/lib , /opt/a/.../lib/, /opt/b/.../lib/
I want to link proper library while building. How to write CMakeLists.txt to do that?
As of now I have hard coded to find it in /usr/lib/
project (mylib)
find_library(LIB_CURL_LIBRARY NAMES curl HINTS "/usr/lib/")
target_link_libraries (mylib curl)

Command find_library actually searches many places, which can also be adjusted by a user (the person, who uses the CMake project with find_library call, but do not modifies CMakeLists.txt).
Also, via HINTS and PATHS you (as the project's developer) may add more hints to search, and these hints could also be made modifiable by a user.
You may find complete description about search paths in documentation.
When decide how to make find_library to search in the specific path, you need to "classify" origin that path. Some common cases:
Is the path a standard one for specific OS or distro? If so, CMake usually searches this path by default.
Does the path come from the custom installation of the package? If so, the user could assign installation prefix to some variable (e.g. XXX_ROOT, where XXX is a package name or abbreviation), which is used as PATHS or HINTS in your find_library call.
Does the path come from the custom installation prefix, common for many packages? If so, the user could assign that common prefix to CMAKE_PREFIX_PATH variable, and find_library automatically will take this prefix into account.
Note, that find_library is usually used in a FindXXX.cmake module (which is activated via find_package(XXX)). Such module could include additional logic for find additional possible library locations according to the system introspection.

Related

Can I use any fuzzy search tricks in CMake find_library?

My motivation comes from this:
I want to find a library named libboost_python38.so, if I use find_library command like this, I cannot find the library:
find_library(USD_BOOST_PYTHON boost_python HINTS ${USD_LIBRARY_DIRECTORY})
Only when I use this command, the library can be found:
find_library(USD_BOOST_PYTHON boost_python38 HINTS ${USD_LIBRARY_DIRECTORY})
This method will make my cmake file lose some cross platform capabilities, so I hope to search this library by some fuzzy search method. Can I do this in a better way?
No particularly, but you can use the NAMES parameter, and pass a few candid names that find_library should look for, see here. You can also provide a few different PATH and PATH_SUFFIXES which could help.
If you still need more logic to find your library, then you most likely need to deal with them before your find_library call, e.g., conclude the name of your library beforehand, put it in a variable, and pass that as the name of the library to the find_library.
Don't use find_library for this purpose. Instead make use of the fact that boost comes with cmake configuration scripts and use find_package.
find_package(Boost REQUIRED COMPONENTS python)
target_link_libraries(my_target PRIVATE Boost::python)
This has the added benefit of any dependencies being added to my_target automatically alongside the necessary include directories.
If you've installed the package to the default location, no additional info should be required. If you've built boost yourself and installed it to a non-standard location, you may need to provide info about the install location, e.g. by adding the install location to CMAKE_PREFIX_PATH.
Note: find_package has additional parameters that allow you to restrict the acceptable boost version if desired.

Add to cmake search path [duplicate]

In CMake, is there a way to make built-in Find scripts to prioritize a custom directory that we specify? Because especially in windows, module finding scripts usually can't detect the module in, for example visual studio directories. Therefore I usually have to manually set the paths for the external libraries which is pretty tiring. Instead, I want those scripts to look in a custom directory, let's say 'dependencies' folder in the main project first so that I can directly put those externals in that folder which is much easier than putting them into the VC folder or manually setting the paths.
Setting CMAKE_PREFIX_PATH variable serves exactly these purposes: hinting find_* function about location of searched item.
While description of this variable doesn't note about find_package function, the variable affects it indirectly: the most of Find<name>.cmake scripts use find_library and find_path functions. Note, that all find_* functions have precise algorithm for search items, and paths constructed with CMAKE_PREFIX_PATH are checked before system ones.
Moreover, CMAKE_PREFIX_PATH affects some other search procedures. E.g., if 3rd party package provides <name>Config.cmake script instead of Find<name>.cmake one, this script is also searched for using this variable. pkg_check_modules also uses CMAKE_PREFIX_PATH to search for .pc files describing the package.
CMAKE_PREFIX_PATH variable can be set as environment one (in platform-depending and usage-specific way), as parameter to cmake call:
cmake -DCMAKE_PREFIX_PATH=<additional-path> <other-parameters>
or within CMakeLists.txt file. In the last case it is better to append search directories, so user of you package is able to set the variable too for search packages not shipped with your project:
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/dependencies")
Note, that variable CMAKE_PREFIX_PATH doesn't affect searching for FindXXX.cmake script itself. For specifying the directory where the script is located, use CMAKE_MODULE_PATH variable.

Cmake override find_package for a given target

We have a CMakeLists.txt that links (for instance) opencv to our various binaries. This is done as follow:
find_package(OpenCV REQUIRED core imgproc highgui contrib)
target_link_library(XXX opencv_core)
We also would like to allow the person building the library to provide its own opencv library. It seems that this could be done setting -DCMAKE_PREFIX_PATH to the right path.
cmake -DCMAKE_PREFIX_PATH=".../mybuild/include;.../mybuild/lib" .
However I would like to be sure the library used is exactly the one specified by the client (i.e. if there is nothing in /mybuild/lib the configuration fails).
How can I allow somebody building the library to override the library used ? (if nothing is specified it should fall back to find_package-s)
In short
If the package provides <package>Config.cmake script, user may specify <package>_DIR CMake variable for locate this script.
Searching other places in that case may be disabled with NO_DEFAULT_PATH option for find_package().
If a package is searched with Find<package>.cmake script, there is no (generic) way for disable searching other places if user provides hint variable but it is wrong.
Explanations
Firstly, CMAKE_PREFIX_PATH provides additional installation tree for all packages. As this variable is applied to all find_package() calls, it is not wise to require all packages to be found under it.
When talk about the ways for specify installation directory for specific package, we need to distinguish two kinds of "find" scripts:
<package>Config.cmake (or some alternative names, see find_package documentation).
These scripts are shipped with the packages themselves. And there is universal way for user to specify location of such packages: CMake variable <package>_DIR, which should point to the directory with *Config.cmake script.
While default behaviour of find_package() is treating <package>_DIR variable as an additional hint, passing NO_DEFAULT_PATH option disables all implicit paths:
if(<package>_DIR) # Variable is set by the user or by previous `cmake` run.
# Search only under given directory.
find_package(<package> NO_DEFAULT_PATH)
else()
# Search everywhere (as documented for 'find_package').
find_package(<package>)
endif()
Find<package>.cmake.
This script either is shipped with CMake or should be shipped with the project.
Most of such scripts allows to hint about package location with variable (CMake or environment one) like <package>_DIR, <package>_ROOT or so.
However, almost all such scripts treat hint variable only as additional search place, so if variable is set to wrong value, they simply ignore it. And without modifying the script you cannot change that behavior.

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

Hinting Find<name>.cmake Files with a custom directory

In CMake, is there a way to make built-in Find scripts to prioritize a custom directory that we specify? Because especially in windows, module finding scripts usually can't detect the module in, for example visual studio directories. Therefore I usually have to manually set the paths for the external libraries which is pretty tiring. Instead, I want those scripts to look in a custom directory, let's say 'dependencies' folder in the main project first so that I can directly put those externals in that folder which is much easier than putting them into the VC folder or manually setting the paths.
Setting CMAKE_PREFIX_PATH variable serves exactly these purposes: hinting find_* function about location of searched item.
While description of this variable doesn't note about find_package function, the variable affects it indirectly: the most of Find<name>.cmake scripts use find_library and find_path functions. Note, that all find_* functions have precise algorithm for search items, and paths constructed with CMAKE_PREFIX_PATH are checked before system ones.
Moreover, CMAKE_PREFIX_PATH affects some other search procedures. E.g., if 3rd party package provides <name>Config.cmake script instead of Find<name>.cmake one, this script is also searched for using this variable. pkg_check_modules also uses CMAKE_PREFIX_PATH to search for .pc files describing the package.
CMAKE_PREFIX_PATH variable can be set as environment one (in platform-depending and usage-specific way), as parameter to cmake call:
cmake -DCMAKE_PREFIX_PATH=<additional-path> <other-parameters>
or within CMakeLists.txt file. In the last case it is better to append search directories, so user of you package is able to set the variable too for search packages not shipped with your project:
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/dependencies")
Note, that variable CMAKE_PREFIX_PATH doesn't affect searching for FindXXX.cmake script itself. For specifying the directory where the script is located, use CMAKE_MODULE_PATH variable.