How do I create my own cmake target with pkg-config settings? - cmake

My project is shared library, and I would like to create installation target with settings for pkg-config.
Currently it builds by only one, very simple rule:
add_library(mylib SHARED src/mylib.cxx)
And here I'm stuck with further configuration because every installation rule should be dependent on the preconfigured installation paths and flags. To keep it simple, let's say, the target will be installed to include and lib directories and preconfigured .pc rules will be something like -lmylib -I/...include -L/....lib
How can I configure cmake's installation targets with pkg-config support ? I guess it does not have builtin support of pkg-config and I need your help to find a proper solution.

CMake can interoperate with pkg-config in both directions, though it's a little bit clunky.
FindPkgConfig allows you to find and use libraries using their pkg-config files.
To have cmake generate a pkg-config file for your own library, you'll have to use configure_file and have a template pkg-config file.

Related

How to use CMake file provided by a Conan package?

Bret Brown in his talk Modern CMake Modules recommends using Conan (or other package manager) to deliver reusable CMake code.
As instructed by Brett I've created a Conan package that delivers a MyHelpersConfig.cmake CMake file.
(The MyHelpersConfig.cmake file is the content of the package; it is not part of the package build system.)
My Conan package delivers only this one file.
Unfortunately I don't know how to make this line in CMake actually work:
find_package(MyHelpers)
Brett mentions, that when using Conan you need to manually override CMAKE_PREFIX_PATH, but he doesn't go into more detail (link to the relevant portion of his talk: Delivering CMake modules).
Does anyone know what needs to go into the Conan recipe, and how to use the package from CMake, to make it work?
EDIT:
From what I was able to figure out cmake_multi (generator I use when consuming packages) will update CMAKE_PREFIX_PATH, but only if CMAKE_BUILD_TYPE is set (which is rarely the case for multi configuration projects):
if(${CMAKE_BUILD_TYPE} MATCHES "Debug")
set(CMAKE_PREFIX_PATH ${CONAN_CMAKE_MODULE_PATH_DEBUG} ${CMAKE_PREFIX_PATH})
...
We would need to add something like this to CMake (pseudocode):
set(CMAKE_PREFIX_PATH ${CONAN_CMAKE_MODULE_PATH_$<CONFIG>} ${CMAKE_PREFIX_PATH})
But that is impossible.
So my conclusion would be that it should work out of the box for non-multi configuration projects, and can not possibly work for multi configuration projects.
The problem I had was that when consuming a package from CMake Conan was not updating CMAKE_PREFIX_PATH, and therefore MyHelpersConfig.cmake was not found.
This happened when using a cmake_multi generator for the consuming project.
Single-configuration generators should not have this problem, or could be solved easily by adding something like:
set(CMAKE_PREFIX_PATH ${CONAN_CMAKE_MODULE_PATH_<BUILD-MODE-HERE>} ${CMAKE_PREFIX_PATH})
To solve it for multi-config generators you can add the following to CMake in the consuming project:
set(CMAKE_PREFIX_PATH ${CONAN_<YOUR-PACKAGE-NAME>_ROOT_RELEASE} ${CMAKE_PREFIX_PATH})
This will work only under assumption that CMake files you deliver in your Conan package are the same for all build types (Debug, Release...). So it is a viable solution for general-purpose utility functions.
I don't think it is possible solve this situation when CMake files differ between build modes, simply because in multi-config projects build type is known only after all find_package() calls were already evaluated.

CMake: How do I add a function to an installed config?

I am creating a library which I am building and installing with CMake. In the CMakeLists.txt is install(TARGETS mylib ...) to install the library itself and install(EXPORT ...) to create a CMake config. The CMake config means that the library can be found with find_package() by applications wanting to use the library from their own CMakeLists.txt. So far, nothing surprising.
But in addition to that I have useful_fn.cmake that contains a useful CMake function that I want to make available to the applications' CMakeLists.txt. I can install it manually with install install(FILE useful_fn.cmake), but how will the applications know where to find it? Can it be referenced from the config?
Even better, could the CMake config include the installed version directly? So merely running find_package(mylib) provides access to this CMake function? I could do this if I wrote my whole mylib-config.cmake by hand, rather than than getting CMake to generate it like it currently does, but I would really rather not do that just so that I can add one line (include(.../usefulfn.cmake)).
It is misconception that CMake should generate XXXConfig.cmake script. As opposite, intended behavior that CMake generates every other script (names can be any):
XXXConfigTargets.cmake with install(EXPORT)
XXXConfigVersion.cmake with write_basic_package_version_file()
and these scripts are included in the XXXConfig.cmake script written by hands, where you may define additional things:
# File: XXXConfig.cmake
include(${CMAKE_CURRENT_LIST_DIR}/XXXConfigVersion.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/XXXConfigTargets.cmake)
# Here you may provide additional functions and other things.
function(my_func)
...
endfunction()
See more in the CMake packaging documentation.
To clarify further, there is a module that helps your configure valid and relocatable config file.
See macro configure_package_config_file provided by CMakePackageConfigHelpers module.
As mentioned by #Tsyvarev, the XXXConfig.cmake file should still be written by hand but configured with configure_package_config_file instead of configure_file.

CMake include path of installed libraries

Suppose your project has multiple authors and depends on some libraries that must be installed on your system - you don't ship them with the project.
Some people have installed that libraries in /usr, /usr/local/, /opt or /opt/local.
What is the best practice to add them to the include path, without messing up CMakeLists.txt with all possible paths?
I am aware of xxx_ROOT variables like BOOST_ROOT, but not all library detections based on such a variable.
Teach your users / co-authors to use custom CMAKE_PREFIX_PATH which they can pass to their CMake call:
cmake -DCMAKE_PREFIX_PATH=/opt/local;/home/brandstifter/boost-1.70/ ..
For each find command, CMake will also search within the paths from CMAKE_PREFIX_PATH. See its documentation.

Why won't find_library find libgmp

I'm trying to build a cmake project, and the repo I have been given has the lines
find_library(gmp gmp)
if(NOT gmp)
message(FATAL_ERROR "gmp not found")
endif()
which cause CMake configuration to fail.
I have been told this CMake works on Redhat Enterprise Linux 7.3.
I have also been told this repo should build in any Linux environment with the correct libraries installed, and an Ubuntu environment has been specifically referenced.
I am building in Debian 9.4.0, I have installed gmp, libgmp.so is located at /usr/lib/x86_64-linux-gnu/openssl-1.0.2/engines/libgmp.so
and I also have a libgmp.so.10 at /usr/lib/x86_64-linux-gnu/libgmp.so.10.
So, to recap, I have been handed a repo I have been told builds, but it does not build, it fails at this specific step, and I can't get google to give me any relevant results on how to fix the issue/what I am doing wrong.
libgmp is installed, but the development libraries are not.
Cmake find_libraries looks for the files required for software development, and while the libgmp package is installed, the libgmp-dev package is not.
Install libgmp-dev.
CMake doesn't search "so-version" files:
If find_library is called for "gmp" library name, CMake searches libgmp.so file, but not libgmp.so.10 one.
Normally, the library file without so-version is just a soft link to the newest so-version file. If your Linux distro doesn't create such link, you may create it manually:
ln -s libgmp.so libgmp.so.10
If you want CMake to find /usr/lib/x86_64-linux-gnu/openssl-1.0.2/engines/libgmp.so file, which is not under directory normally searched by CMake, you need to hint CMake about it. E.g. with PATHS option:
find_library(gmp gmp PATHS "/usr/lib/x86_64-linux-gnu/openssl-1.0.2/engines")

llvm's cmake integration

I'm currently building a compiler/interpreter in C/C++.
When I noticed LLVM I thought it would fit greatly to what I needed and so I'm trying to integrate LLVM in my existing build system (I use CMake).
I read this bout integration of LLVM in CMake. I copy and pasted the example CMakeLists.txt, changed the LLVM_ROOT to ~/.llvm/ (that's where I downloaded and build LLVM and clang) and it says it isn't a valid LLVM-install. Best result I could achieve was the error message "Can't find LLVMConfig" by changing LLVM_ROOT to ~/.llvm/llvm.
My ~/.llvm/ folder looks like this:
~/.llvm/llvm # this folder contains source files
~/.llvm/build # this folder contains object, executable and library files
I downloaded LLVM and clang via SVN. I did not build it with CMake.
Is it just me or is something wrong with the CMakeLists.txt?
This CMake documentation page got rotted, but setting up CMake for LLVM developing isn't different from any other project. If your headers/libs are installed into non-standard prefix, there is no way for CMake to guess it.
You need to set CMAKE_PREFIX_PATH to the LLVM installation prefix or CMAKE_MODULE_PATH to prefix/share/llvm/cmake to make it work.
And yes, use the second code snippet from documentation (under Alternativaly, you can utilize CMake’s find_package functionality. line).