For my project, I am building specific versions of the dependency libraries in a separate folder, say, /home/ubuntu/libs
. I will use real libraries as an example, however, the question is pretty generic.
I was able to build the freetype library and make
installed the headers into /home/ubuntu/libs/include
, the built library into /home/ubuntu/libs/lib
and also added the freetype-config.cmake
to /home/ubuntu/libs/lib/cmake
.
Now, I am trying to build the freetype-gl library that depends on freetype and has a line
find_package(freetype REQUIRED)
in its CMakeLists.txt.
Typically, when I install the freetype library to a common path like /usr/local/lib
or /usr/lib
, cmake
picks up the *-config.cmake files from the corresponding ./cmake directory. However, when I call it with
cmake -DCMAKE_TOOLCHAIN_FILE=/my/custom/toolchain -DCMAKE_LIBRARY_PATH=/home/ubuntu/libs/lib -DCMAKE_INCLUDE_PATH=/home/ubuntu/libs/include /path/to/freetype-gl
it fails with the following error
CMake Error at CMakeLists.txt:102 (find_package):
By not providing "Findfreetype.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "freetype",
but CMake did not find one.
Could not find a package configuration file provided by "freetype" with any
of the following names:
freetypeConfig.cmake
freetype-config.cmake
Add the installation prefix of "freetype" to CMAKE_PREFIX_PATH or set
"freetype_DIR" to a directory containing one of the above files. If
"freetype" provides a separate development package or SDK, be sure it has
been installed.
What am I doing wrong? How to show the place of "freetype-config.cmake" to cmake.
2
Answers
as you state in your second paragraph:
find_package() in CMake works in a way that it checks the standard system paths on default. If you are using CMake version 3.17 you can (instead of reading the documentation) view these paths simply by adding this line to your CMakeLists.txt
In your case what you need to do is point CMake in the right direction of the cmake file you are looking for. In your case that would be the /home/ubuntu/libs/lib/cmake. So somewhere in the top of your CMakeLists.txt (before you call find_package()) add this line:
Provided that this bash command:
Returns an occurance of freetypeConfig.cmake (you get the drill 🙂 )
You can read about CMAKE_MODULE_PATH variable here: https://cmake.org/cmake/help/latest/variable/CMAKE_MODULE_PATH.html
In short your CMake doesn’t find the config file because it is not in the standard path where it expects to find it.
EDIT: You can ofcourse do the same via these variables as the error suggests – CMAKE_PREFIX_PATH or freetype_DIR
Presumably you also don’t want the libraries you build to find their dependencies installed on our system, if any.
I’ve spent some time investigating how to isolate CMake builds, and my best recipe is below.
First, the terminology:
An installation "prefix" of a library is a directory where the binaries and headers are installed (normally in
include
andlib
subdirectories). I preder distinct prefixes for each library.A "dependency" of a library is any of other library it needs when compiling.
CMake path separator – the character used to separate path lists for CMake. It’s
:
character on Windows and;
on Linux (when cross-compiling, the host system matters, not the target).Yes, it’s the opposite of what the documentation claims.
By Windows I mean MSYS2. If you want to build outside of it, check that
:
is still the right separator.Environment variables for CMake:
PKG_CONFIG_PATH
to empty stringPKG_CONFIG_LIBDIR
to a:
-separated list, for each dependency add<prefix>/lib/pkgconfig
and<prefix>/share/pkgconfig
.(I didn’t need to do it for any library I used, so this is theoretical. But in any case don’t leave this variable unset, at least use an empty string. Otherwise some undesired dependencies from your system might leak in.)
CMake flags:
-DCMAKE_INSTALL_PREFIX=...
– the installation prefix for this library.-DCMAKE_PREFIX_PATH=...
– a path list: the installation prefix, followed by the prefixes of all dependencies. Use the CMake path separator, as described above. All paths here must be absolute.-DCMAKE_FIND_USE_CMAKE_SYSTEM_PATH=OFF
This prevents CMake from finding some system-wide dependencies. If I remember correctly, not doing this makes CMake look for dependencies in directories listed in PATH and their parent directories, which is annoyting.
This has an undesired effect of disabling some
..._SYSTEM_...
CMake variables, so we can’t use those, even though some of them would be more appropriate.-DCMAKE_STAGING_PREFIX=/
. On Windows hosts replace/
with the current drive name, e.g.C:
.This is only useful when cross-compiling, to disable the effects of
CMAKE_FIND_ROOT_PATH
in the toolchain file, which otherwise limits dependency search to that path.This also messes up the installation path that would otherwise be taken from
CMAKE_INSTALL_PREFIX
, the fix is explained below.Only on Windows hosts:
-DCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF
– otherwise CMake tends to look for dependencies in thePATH
and parent directories, which is annoying. This is hardcoded to only happen on Windows hosts, which is nonsense and was reported here.We don’t want to set this unconditionally, because it has a side effect of requiring all your toolchain executables to be in the same directory, which is annoying in general, but IMO tolerable on Windows.
It also prevents CMake from searching for executables in
PATH
, so we also need…-DCMAKE_PROGRAM_PATH=
– set this to the contents ofPATH
, with the original separator replaced with the CMake path separator. At least on MSYS2 the separators are the same, so no modifications are needed.-DCMAKE_MAKE_PROGRAM=ninja -GNinja
– hereCMAKE_MAKE_PROGRAM
is strictly necessary on Windows hosts because ofCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH=OFF
, and doesn’t hurt on other platforms.-G...
is to make sure CMake doesn’t pick a different generator that doesn’t matchCMAKE_MAKE_PROGRAM
. You can use any other generator+program if you wish.Then build with
cmake --build <build_dir> -j<num_threads>
as usual.Install with
cmake --install <build_dir> --prefix <prefix>
. We need to explicitly set prefix because ofCMAKE_STAGING_PREFIX=/
.