I'm trying to create an imported target in CMake and specify a compiler option to use with my target from any downstream project. It looks similar to the snippet below (-O3 is just an example, the use case is a bit more sophisticated):
add_library(Foo::Foo UNKNOWN IMPORTED)
set_target_properties(Foo::Foo
INTERFACE_COMPILE_OPTIONS "-O3")
The issue is that this isn't supported by CMake versions older than 2.8.12.
Is there a way to implement this mechanism in the older versions or are there any reasonable alternatives?
Related
If you build C++14 code with G++ and libstdc++, there's a library named libstdc++fs, which is separate from the rest of libstdc++, and contains the code for std::experimental::filesystem. If you don't link against it, you'll get undefined references.
The "trick" I'm using for overcoming this right now is:
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
set(CXX_FILESYSTEM_LIBRARIES "stdc++fs")
endif()
and later:
target_link_libraries(my_target PUBLIC ${CXX_FILESYSTEM_LIBRARIES})
but - I don't like having to place this code in every project I work on. Is there a simpler or more standard idiom I could use? Some way this will all happen implicitly perhaps, with some CMake behind-the-scences magic?
tl;dr: Nothing right now, wait for a newer CMake version
As #Pedro graciously points out, this is a known problem, and there is an open issue about it at KitWare's GitLab site for CMake:
Portable linking for C++17 std::filesystem
If using CMAKE_CXX_STANDARD=17 and std::filesystem, GCC requires linking of an extra library: stdc++fs. ... If C++17 is enabled, would it be worth automatically linking to stdc++fs for GCC versions which require this? Likewise for any quirks in other compilers or libraries.
The KitWare issue is about C++17, for which apparently you still need the separate extra library (i.e. it's not just because of the "experimentality" in C++14). Hopefully we'll see some traction on this matter - but
Note: If you're experiencing this problem with C++17's std::filesystem, you're in luck - that code is built into libstdc++ beginning with GCC 9, so if you're using g++ 9 or later, and std::filesystem, you should no longer experience this problem.
I'm updating a (very old) find-module of a library. So the situation is an existing shared library which uses CMake itself. Users might already have this installed somewhere, in package repos or whatever.
Now they want to use this. The good way would be
find_package(Foo REQUIRED)
target_link_libraries(MyProject Foo::Foo)
So thats the goal.
The question is: How would a good find_package-Config or -Module look like which allows this 2-liner to work? It should meet these 2 requirements:
Allow a CMake version to use the library older than the one used to build it
Enforce e.g C++11 mode. In a Find-Module one can set the C++11 requirement based on the version (cxx_std_11 (CMake 3.8+), cxx_alias_templates (CMake 3.1+), check_cxx_source_compiles with C++11 code and a warning for older CMakes)
There are 2 ways of doing that:
Update the find-module to define an imported library Foo::Foo and set it up correctly (using properties) and be nice to also set FOO_INCLUDE_DIR and FOO_LIBRARIES for old CMake w/o targets.
This is pretty easy: Just use find_path and find_library, set up the imported target and be done. Works forwards and backwards compatible so even the old versions would be found.
Usage:
The user copies (the most recent) FindFoo.cmake to its project into e.g. cmake/Modules and points CMAKE_MODULE_PATH to it, or copy FindFoo.cmake to some CMake default path.
Listening to Daniel Pfeiffer and Modern CMake which says If you are the library author, don't make a Find<mypackage>.cmake script! So we export and install targets.
This is a bit messy. Following changes are required:
Add EXPORTS FooTargets and INCLUDES DESTINATION include to install(TARGETS (see Pfeiffer #24) which basically just defines an export. (I don't really see, why I would want to create an extra name for something that already has a name. Why can't the below command not simply refer to a target?)
Add install(EXPORT FooTargets NAMESPACE Foo:: DESTINATION lib/cmake/Foo) which would create a FooTargets.cmake in <CMAKE_INSTALL_PREFIX>/lib/cmake/Foo that defines a target Foo::Foo with (hopefully) all its dependencies
Add "something" creating FooConfigVersion.cmake possibly by using write_basic_package_version_file that, to my understanding, hard-codes the version to that file
Create a FooConfig.cmake that may use find_dependency to search for libraries that Foo depends on and includes FooTargets.cmake
Install FooConfig.cmake and FooConfigVersion.cmake to lib/cmake/Foo
modify target_include_directories to use separate BUILD_INTERFACE and INSTALL_INTERFACE paths
Usage:
find_package automatically finds the FooConfig.cmake and FooConfigVersion.cmake when Foo is searched for.
So the Config-Module should be preferred but problems I see are:
The process looks more complicated
It cannot be used to enable users to find older versions of the library (that did not use this approach)
It excludes all (library-)users with older CMake (2.8.11 is probably the minimum required here)
It requires a newer CMake version to build the library itself
The C++11 requirement seems to be very hard to encode
So can we solve the requirements with a CMake-Config? An answer should provide a solution or at least a well grounded "impossible". It should also address the problems outlined at the end.
Final Note: I guess this makes a nice wiki-entry if it doesn't exist.
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.
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.
My project depends on GLEW and is built with CMake, so i took the FindGLEW.cmake from here http://code.google.com/p/nvidia-texture-tools/source/browse/trunk/cmake/FindGLEW.cmake?r=96 and wrote find_package(GLEW REQUIRED) in my CMakeLists.txt. Problem is that i am working on a cluster PC were several versions of GLEW are available. One version is stored in /usr/lib which is not the latest. the latest version is stored in /opt/local/lib64. this is the version i want to link against. so i added the path to the FindGLEW.cmake under the GLEW_LIBRARY paths. the problem is that the makefile always links against the older version, but i need the newest version (1.7) for using stuff like GL_PATCHES, GL_PATCH_PARAMETERS and so on. can i some how force CMake to use the newer version like it is the case with FindBoost.cmake. one solution is to erase the older one's but this is not an option. i also changed the order of the paths in the GLEW_LIBRARY list, but without success.
in my old Makefile i just wrote LDDFLAGS = -L/opt/local/lib64 -lGLEW so the path is absolutely clear, but now with CMake i want to use the find feature, but want to prefer a specific version.
I use this to link statically to a custom compiled GLEW lib at a specific location:
#GLEW libraries
add_library(glew_static STATIC IMPORTED)
set_target_properties(glew_static PROPERTIES
IMPORTED_LOCATION /home/ryan/DevLibrary/glew-1.9.0/lib/libGLEW.a)
target_link_libraries(smolder glew_static)
With this in place you can remove
find_package(GLEW REQUIRED)
You can use this with shared libraries as well, simply remove the STATIC keyword from add_library.