How to install your custom CMake-Find module - cmake

I configure and package my library using CMake and CPack. I have written my own find-module: FindMyLib.cmake.
How do I tell CMake/CPack to add this file to the CMake module directory, so that future developers can simply specify FIND_PACKAGE(MyLib) to use my library?

You can set CMAKE_MODULE_PATH and distribute your custom FindFoo.cmake with your project. For example:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")

The CMake module directory is part of the install tree of CMake itself, and as such you shouldn't be trying to add anything there.
The CMake module directory contains modules which have been written or at least reviewed by Kitware, and adding your own there would give the impression to users of your project that this was the case for your project also.
You'd be better to just install FindMyLib.cmake to one of the places searched by find_package:
<prefix>/ (Windows)
<prefix>/(cmake|CMake)/ (Windows)
<prefix>/<name>*/ (Windows)
<prefix>/<name>*/(cmake|CMake)/ (Windows)
<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/ (Unix)
<prefix>/(lib/<arch>|lib|share)/<name>*/ (Unix)
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/ (Unix)
<prefix>/<name>.framework/Resources/ (Apple)
<prefix>/<name>.framework/Resources/CMake/ (Apple)
<prefix>/<name>.framework/Versions/*/Resources/ (Apple)
<prefix>/<name>.framework/Versions/*/Resources/CMake/ (Apple)
<prefix>/<name>.app/Contents/Resources/ (Apple)
<prefix>/<name>.app/Contents/Resources/CMake/ (Apple)
See the documentation for find_package for the full details of how find_package searches. Also the CMake packaging tutorial is useful in this case.

The best way to allow
future developers can simply specify FIND_PACKAGE(MyLib) to use my library
is to write a package config file (-config.cmake) , not a Find module.
The package config file should then be installed in one of the folders where the FindPackage module looks for (something like /lib/package/ or /lib/cmake/package the second being preferred)
The FindPackage module will automatically load the config file if it can find it there.
The CMake wiki has more detailed instructions at https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/Packaging

Related

How to set up libusb dependency with CMake?

I am trying to develop an application using GreatScottGadget's Ubertooth One. To start, I need to be able to use the libusb library. I'm working with Ubuntu 20.04.
I have a simple CMakeLists.txt file that sets the module path to a path in my project that contains all the Find*.cmake files that I stole from the ubertooth repository here. I include libusb like so:
find_package(USB1 REQUIRED)
When I run CMake, this is the error I get:
Could not find package configuration file provided by "USB1" with any of the following names:
USB1Config.cmake
usb1-config.cmake
Add the installation prefix of "USB1" to CMAKE_PREFIX_PATH or set
"USB1_DIR" to a directory containing one of the above files. If "USB1"
provides a separate development package or SDK, be sure that it has been
installed.
As far as I can tell, I have libusb already installed. apt list --installed | grep libusb shows libusb-1.0.0-dev/focal,now 2:1.0.23-2build1 amd64 [installed] (among others). I can see the shared object in /usr/lib/x86_64-linux-gnu
$ ls /usr/lib/x86_64-linux-gnu | grep libusb
libusb-0.1.so.4
libusb-0.1.so.4.4.4
libusb-1.0.a
libusb-1.0.so
libusb-1.0.so.0
libusb-1.0.so.0.2.0
libusbmuxd.so.6
libusbmuxd.so.6.0.0
Additionally, I can build the host code provided in the ubertooth repository just fine. In the CMake output, I see the following:
-- Checking for module 'libusb-1.0'
-- Found libusb-1.0, version 1.0.23
-- Found LIBUSB: /usr/lib/x86_64-linux-gnu/libusb-1.0.so
Looking through the ubertooth repository, I don't see anything special they are doing to find the package. The host project adds libubertooth as a subdirectory, in in its CMakeLists.txt, it uses the same method I have to find the library. I'm not seeing any other differences.
Maybe I'm misunderstanding and the libubertooth subdirectory isn't where the library is being found. Maybe there's some global config that I'm not setting. I haven't managed to find whatever it is.
I checked the libusb homepage and downloaded the source, but I didn't find any USB1Config.cmake files, so I'm not sure how this is supposed to work.
What am I missing to be able to find the library and use it in my project?
This is because you don't have a FindUSB1.cmake in you project. You can find it on ubertooth/host/cmake/modules/FindUSB1.cmake.
BTW, don't use stole, you can find ubertooth's license, it's GPL-2.0

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.

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")

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

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.

CMake package configuration files for upstream projects using Qt5 problems

I am working on a larger C++ library that is using CMake and depends on Qt.
We moved from Qt4 to Qt5 and now I encounter a problem when using our lib
in an upstream project. As a minimal working example demonstrating the problem please have a look at this repo:
https://github.com/philthiel/cmake_qt5_upstream
It contains two separate CMake projects:
MyLIB: a tiny library that uses QString from Qt5::Core.
It generates and installs package configuration files
MyLIBConfig.cmake, MyLIBConfigVersion.cmake, and MyLIBTargets.cmake
in order to be searchable by CMake find_package()
MyAPP: a tiny executable depending on MyLIB
The project uses find_package(MyLIB) and creates an executable that uses MyLIB
The problem is that CMake gives me the following error message when configuring the MyAPP project:
CMake Error at CMakeLists.txt:11 (add_executable):
Target "MyAPP" links to target "Qt5::Core" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
The reason for this behaviour is that in the automatically generated MyLIBTargets.cmake file the INTERFACE_LINK_LIBRARIES entry for Qt5 Core is the Qt5::Core symbol. Using Qt4, the absolute path to the Qt core lib was specified here.
Now, I simply can resolve this by using
find_package(Qt5Core 5.X REQUIRED)
in the MyAPP project.
However, I would like to know if this is the intended/generic way to go, i.e. requesting upstream projects of our lib to search for the required transitive Qt5 dependencies themselves, or if I probably misuse CMake here and need to change my configuration procedure?
The CMake docu on package file generation
https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
mentions that macros can be provided by the package configuration files to upstream. Maybe this would be the correct place to search for imported targets like Qt5 and break upstream configuration runs when these dependencies are not found?
Best,
Philipp
[edit of the edit] Full Source Example
You need to deliver a CMake config file for your project, and probably the ConfigFile should be generated via CMake itself (because you cannot know for shure where the user will install your software).
Tip, use the ECM cmake modules to ease the creation of that:
find_package(ECM REQUIRED NO_MODULE)
include(CMakePackageConfigHelpers)
ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX ATCORE
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfigVersion.cmake"
SOVERSION 1
)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5AtCoreConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
and the KF5AtCoreConfig.cmake.in:
#PACKAGE_INIT#
find_dependency(Qt5Widgets "#REQUIRED_QT_VERSION#")
find_dependency(Qt5SerialPort "#REQUIRED_QT_VERSION#")
find_dependency(KF5Solid "#KF5_DEP_VERSION#")
include("${CMAKE_CURRENT_LIST_DIR}/KF5AtCoreTargets.cmake")
This will generate the correct FindYourSortware.cmake with all your dependencies.
[edit] Better explanation on what's going on.
If you are providing a library that will use Qt, and that would also need to find the Qt5 library before compilling the user's source, you need to provide yourself a FindYourLibrary.cmake code, that would call
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Whatever)
Now, if it's your executable that needs to be linked, use the Components instead of the way you are doing it now.
find_package(Qt5 REQUIRED COMPONENTS Core)
then you link your library with
target_link_libraries(YourTarget Qt5::Core)