Home > Net >  Custom library directory for cmake
Custom library directory for cmake

Time:12-15

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.

CodePudding user response:

as you state in your second paragraph:

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.

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

SET(CMAKE_FIND_DEBUG_MODE TRUE) 

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:

LIST(APPEND CMAKE_MODULE_PATH "/home/ubuntu/libs/lib/cmake")

Provided that this bash command:

ls /home/ubuntu/libs/lib/cmake | grep "*.cmake" 

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

CodePudding user response:

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 and lib 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 string
  • PKG_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 the PATH 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 of PATH, 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 - here CMAKE_MAKE_PROGRAM is strictly necessary on Windows hosts because of CMAKE_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 match CMAKE_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 of CMAKE_STAGING_PREFIX=/.

  • Related