What is the recommended way of using GLib2 with CMake - cmake

Id like to use GLib in my C application which uses CMake as the build system.
Now, I'm somehow confused how I should enable GLib in my CMakeLists.txt. Basically, you add libraries in cmake using the find_package command, so I tried, according to this bugreport
find_package(GLib2)
But nothing is found. In the GLib documentation it is suggested to use pkg-config, on the other hand.
What is the recommended way of enabling glib in a cmake-based project?

Since CMake 3.6 (released in July 2016), pkg_check_modules supports IMPORTED_TARGET argument, reducing the dependency configuration to a single target_link_libraries statement, which will take care of all required compiler and linker options:
find_package(PkgConfig REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET glib-2.0)
target_link_libraries(target PkgConfig::deps)
(above I used the name deps because one can list multiple dependencies with a single pkg_check_modules statement)

In your CMakeLists.txt:
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
target_include_directories(mytarget PRIVATE ${GLIB_INCLUDE_DIRS})
target_link_libraries(mytarget INTERFACE ${GLIB_LDFLAGS})

Give a look at my answer on using CMake with GTK
It's pretty much the same with GLib.

GLib (and various other C libraries using autotools) provide a pkg-config file for declaring:
compiler flags
linker flags
build-time variables
dependencies
The appropriate way to discover where these libraries are with CMake is to use the FindPkgConfig CMake module:
https://cmake.org/cmake/help/v3.0/module/FindPkgConfig.html

yet another version, combination of multiple answers and what actually worked for me (on Linux)!
cmake_minimum_required(VERSION 2.6.4)
project(my_proj)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
include_directories(${GLIB_INCLUDE_DIRS})
link_directories(${GLIB_LIBRARY_DIRS})
add_executable(my_proj main.c)
add_definitions(${GLIB_CFLAGS_OTHER})
target_link_libraries(my_proj ${GLIB_LIBRARIES})

I've been working on some CMake modules for GNOME (including one for GLib) which you might want to try. Basically, just find_package(GLib), then you can use the glib-2.0 imported target to link to it.

Related

Check Eigen version in cmake with header only

I want to use Eigen in one of my projects.
The user directly decides to turn Eigen ON/OFF and configures the path to the includes. So far, CMakeLists.txt looks like:
set(EIGEN_MODULE "OFF" CACHE BOOL "Enabled EIGEN MODULE ?")
if (EIGEN_MODULE)
include_directories(${EIGEN_INCLUDE_DIR})
set(EIGEN_INCLUDE_DIR /usr/local CACHE PATH "eigen include dir")
if(NOT EXISTS ${EIGEN_INCLUDE_DIR})
message(FATAL_ERROR "Bad eigen include dir")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DEIGEN_MODULE")
include_directories(${EIGEN_INCLUDE_DIR})
endif(EIGEN_MODULE)
However, I don't know how to check the version of Eigen (I need to ensure 3.4.0 at least), knowing that I want to avoid find_package (Eigen3 3.4 REQUIRED NO_MODULE) which would require the user to compile Eigen.
Is there any way to do that ?
First a comment about your question: Eigen is a header only library, it means that the user will have to compile the library, no matter what.
Then, to answer your question: you shouldn't be scared to use find_package(Eigen3), actually the documentation of Eigen specifically recommends to use find_package before performing a target_link_libraries. So you can validate that Eigen has the proper version with find_package (Eigen3 3.4 REQUIRED), this is the best way to do it. find_package will read the file Eigen3Config.cmake found in the CMAKE_PREFIX_PATH, and that will contain the proper version.
It can seem a little confusing to use target_link_libraries to compile Eigen, since it is header-only (you could think that all you have to do is to include the directories, since Eigen is merely composed of header files, like you have done in your example). The reason is that CMake supports what is called interface library, and this is what is recommended by Eigen.

Make FetchContent compatible with find_package

I try to add all dependencies needed for my project to compile over CMake. This should reduce the overhead others will have when they want to compile the project for the first time.
To achive this, I tried to use FetchContent. So far so good, when I link the generated targets its not a problem at all. But now I have a library depending itself on annother lib which isn't included as submodule. The lib tries to find the dependency over find_package. How can I get find_package to find the library?
What I tried so far:
adding an alias target and defined all variables set by find_package
Setting the LIB_DIR to the build directory and called find_package
Here a minimal snipped of my CMake code of the later:
cmake_minimum_required(VERSION 3.14)
find_package(ZLIB)
if (NOT ZLIB_FOUND)
FetchContent_Declare(zlib_fetch
GIT_REPOSITORY https://github.com/madler/zlib.git
GIT_TAG cacf7f1d4e3d44d871b605da3b647f07d718623f
)
FetchContent_MakeAvailable(zlib_fetch)
set(ZLIB_DIR ${zlib_fetch_BINARY_DIR})
message(${zlib_fetch_BINARY_DIR})
#simulates the call in the other library:
find_package(ZLIB REQUIRED)
endif (NOT ZLIB_FOUND)
Starting with CMake 3.24, FetchContent_Declare has OVERRIDE_FIND_PACKAGE option which, when specified, makes CMake redirect the subsequent calls to find_package(<name>) so that FetchContent_Declare(<name> ...) satisfies the dependency (note that <name> must stay the same here).

Add FreeType dependency with cmake supporting all vcpkg/apt-get/brew

I have a project which depends on FreeType, and uses CMake as build system. CMake has a FindFreeType built-in module which is supposed to be used like this, see for example this other SO question:
find_package(Freetype REQUIRED)
target_link_libraries(mylib ${FREETYPE_LIBRARIES})
target_include_directories(mylib PRIVATE ${FREETYPE_INCLUDE_DIRS})
Since CMake 3.10, there is also the Freetype::Freetype imported target so we can avoid the target_include_directories:
find_package(Freetype REQUIRED)
target_link_libraries(mylib Freetype::Freetype)
This worked great on Ubuntu 18.04 with FreeType installed via apt install libfreetype6-dev. I assume it also works on macOS when the package is installed via homebrew (I haven't tested yet).
However, on Windows, I wish to allow developers to depend on a vcpkg-installed FreeType:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg integrate install
.\vcpkg install freetype:x64-windows
Which they would target by running the following CMake command:
cmake .. -G "Visual Studio 15 2017" -A x64 -DCMAKE_TOOLCHAIN_FILE=C:/Users/Boris/vcpkg/scripts/buildsystems/vcpkg.cmake
Unfortunately, the above CMake command won't work with any of the two CMakeLists.txt at the beginning of this question, because the proper way to find and link to FreeType when it is installed via vcpkg is the following:
find_package(freetype CONFIG REQUIRED) # `Freetype` works too, but vcpkg doc recommends `freetype`
target_link_libraries(mylib freetype) # Here, all-lowercase is required
In particular, the freetype-config.cmake config file provided by vcpkg defines the target freetype (not Freetype::Freetype like the builtin find module), and doesn't define any of the FREETYPE_LIBRARIES or FREETYPE_INCLUDE_DIRS variables.
What would be a proper way to keep my CMakeLists.txt compatible with both "traditional" ways of finding FreeType, but also vcpkg?
Assuming pre-CMake 3.10, I'm thinking of something along the lines of:
if(DEFINED VCPKG_TARGET_TRIPLET)
find_package(freetype CONFIG REQUIRED)
set(FREETYPE_LIBRARIES freetype)
set(FREETYPE_INCLUDE_DIRS "")
else()
find_package(Freetype REQUIRED)
endif()
target_link_libraries(mylib ${FREETYPE_LIBRARIES})
target_include_directories(mylib PRIVATE ${FREETYPE_INCLUDE_DIRS})
Would that seem like good practice? Any better idea?
It feels ugly, and besides, there is always the possibility of a developer wanting to use vcpkg for some other dependencies but not for FreeType (e.g., explicitly providing FREETYPE_DIR instead), so this trick wouldn't even be enough in all situations, and we would need another CMake option like MYLIB_IGNORE_VCPKG_FREETYPE which starts to be even uglier.
Would that seem like good practice? Any better idea?
No be agnostic about a possible package manager.
Do the following:
find_package(Freetype CONFIG) # should find freetype-config.cmake if available
find_package(Freetype REQUIRED) # Will not be executed if Freetype_FOUND ist already set
# if you do not want two find_package calls consider using CMAKE_FIND_PACKAGE_PREFER_CONFIG
Then test if the target Freetype::Freetype or freetype exists
if(TARGET freetype AND NOT TARGET Freetype::Freetype)
add_library(Freetype::Freetype ALIAS freetype) # target freetype is defined by freetype-targets.cmake
# might need to add freetype to global scope if cmake errors here
# alternativly if the above does not work for you you can use
# add_library(Freetype::Freetype INTERFACE IMPORTED)
# target_link_libraries(Freetype::Freetype INTERFACE freetype)
endif()
if(NOT TARGET Freetype::Freetype)
# insert error here
# or create the target correctly (see cmakes newer FindFreetype.cmake)
endif()
target_link_libraries(mylib PRIVATE Freetype::Freetype)
if you don't want to alias the target you could also define a variable called FREETYPE_TARGET and set it to the correct target for linking against.
In older versions of vcpkg (< Jan 2020, see vcpkg#9311), there used to be the following message when installing Freetype:
The package freetype is compatible with built-in CMake targets:
find_package(Freetype REQUIRED)
target_link_libraries(main PRIVATE Freetype::Freetype)
In current versions, they instead recommend find_package(freetype CONFIG REQUIRED), which ensures that the config package vcpkg/<...>/freetype-config.cmake takes precedence over the CMake's built-in module package FindFreetype.cmake.
However, using the built-in module package still works correctly: it will find the vcpkg-installed library, and will define a Freetype::Freetype target (if CMake >= 3.10) rather than a freetype target.
Note that by default, find_package(Freetype REQUIRED) searches first for module packages, then for config packages. However, users can sets CMAKE_FIND_PACKAGE_PREFER_CONFIG, which would use the config package instead. Therefore, a robust approach to ensure that Freetype::Freetype is defined is to do the following:
find_package(Freetype MODULE REQUIRED)
target_link_libraries(mylib Freetype::Freetype)
However, if CMake < 3.10, this still doesn't define a Freetype::Freetype target. One option in this case is to vendor a copy of a more recent version of FindFreetype.cmake in your CMAKE_MODULE_PATH.
For even more robustness, you could even call it Find<Mylib>Freetype.cmake, in the unlikely case where your CMakeLists.txt is used as a subdirectory of another project which also modifies CMAKE_MODULE_PATH and provides an incompatible FindFreetype.cmake.

How would I build and link an external library using CMake?

To start off, I should say that I've seen the answers on questions that were similar to mine, yet none of them seem to make sense to me. Here goes:
Say I have the following simple CMakeLists:
cmake_minimum_required (VERSION 2.8)
project (Example)
add_executable (Example Main.cpp)
I would then like to link a library that already has its own CMakeLists (for example, glfw) against Example. Of course, this brings into question how to properly set up the build order.
How would I go about doing this?
First let me describe what to do for GLFW. See the notes below for variations.
Build GLFW. As the official GLFW head's CMake support is currently broken, use this shaxbee fork:
git clone https://github.com/shaxbee/glfw.git
cmake -Hglfw -Bbuild/glfw -DCMAKE_INSTALL_PREFIX=inst -DCMAKE_BUILD_TYPE=Release
cmake --build build/glfw --target install --config Release
This install step installs inst/lib/cmake/glfw3/glfw3Config.cmake, the glfw3 config-module which will be used by client projects to find GLFW.
Your project should look like this:
cmake_minimum_required(VERSION 2.8)
project(Example)
find_package(glfw3 REQUIRED)
add_executable(Example Main.cpp)
target_link_libraries(Example glfw3)
The find_package command finds the glfw3Config.cmake which creates an IMPORTED library, a CMake target, which incorporates all the information needed to use GLFW in your project.
The target_link_libraries command tells CMake not only to link to GLFW but to use its include directories and compile flags, too.
Configure your project with -DCMAKE_PREFIX_PATH=inst (use full path if necessary)
Note: Other config-modules or find-modules may not provide IMPORTED targets. See the actual config or find-module for help. They usually provide <PACKAGE>_INCLUDE_DIRS and <PACKAGE>_LIBRARIES variables which should be added to the appropriate settings of your target:
target_include_directories(mytarget ${ZLIB_INCLUDE_DIRS})
or
include_directories(${ZLIB_INCLUDE_DIRS})
Same for target_link_libraries / link_libraries.
Build the external dependency first.
add a function call to find your external library. That can either be FindGLFW.cmake with find_package if you can find that or write it yourself using find_library et al. More information about including external libraries can be found in the CMake wiki
Add the includes and libraries to your Example executable.
This is how CMake should be used, I don't see why is not answered in the sources in the Internet.

Specifying libraries for cmake to link to from command line

I have a huge project managed with CMake and this project has hundreds of components each of them having own source files and each of them linking to a list of libraries, specified with target_link_libraries(${project} some_libraries, some_other_libraries)
Now, what I am aiming for is that:
Without actually modifying any of the CMakeLists.txt I want ALL the projects's target executable to link to some specific libraries.
Is there a way of achieving this? Since this is a one time trial, I don't want to manually hunt down all the CMakeLists.txt files and modify them (yes, this is the other alternative). Just a note, I compile the entire project from command line, using cmake (no cmake gui).
This is kind of a hack, but for a C++ project, you can use CMAKE_CXX_STANDARD_LIBRARIES. For a C project, I think you would use CMAKE_C_STANDARD_LIRBARIES.
Example for C++ that links to libbar and libfoo:
cmake ... -DCMAKE_CXX_STANDARD_LIBRARIES="-lbar -lfoo"
See the documentation here:
https://cmake.org/cmake/help/v3.6/variable/CMAKE_LANG_STANDARD_LIBRARIES.html
This won't be available for older versions of CMake; it was added some time after version 3.0.
This is a dirty, dirty hack, so please only use it for testing.
You can actually overload the add_executable command by defining a function of the same name. Do this close to the top of the top-level CMakeLists.txt:
function (add_executable name)
message("Added executable: " ${name})
_add_executable(${name} ${ARGN})
target_link_libraries(${name$} your_additional_lib)
endfunction()
Note that _add_executable is an internal CMake name that may break in future CMake versions. As of now (version 3.0) it seems to work with all versions though.
You can overload add_library the same way if required.
For more fine-grained control over what is linked, instead of calling target_link_libraries you can also mess with the LINK_LIBRARIES and INTERFACE_LINK_LIBRARIES target properties directly.