Consider this project structure:
Complete example of the project: another-ghasem/CMakePluginProblem
+
|
+-- plugin/
+- plugin_1/
+- plugin_2/
+- plugin_3/
+-- CMakeLists.txt
+-- main.cpp
Those plugins are Shared Libraries created with CMake and will be linked to the root project. But the plugins dependencies are the problem (all the plugins have a Target Alias with BUILD_INTERFACE include path: plugin_2/CMakeLists.txt).
How could we manage the non-generated but linked plugins?
Consider the plugin_1 linked to plugin_2 (plugin_1/CMakeLists.txt#22):
target_link_libraries(${PROJECT_NAME} PRIVATE Project::plugin_2)
Here CMake could somehow handle the build order, but if we remove the plugin_2 CMake will raise an error about it:
Target "plugin_1" links to target "Project::plugin_2" but the target was
not found. Perhaps a find_package() call is missing for an IMPORTED
target, or an ALIAS target is missing?
By the way, we couldn't use an if-statement to check "if we have the needed plugin, then linked and define a macro to notice that we have the plugin". How could we handle these dependencies?
- CMake Version: 3.16
- OS: Fedora 34, Ubuntu 18.04
Related
I created two default projects with QtCreator v6.0.1: MyApp and MyLib for Linux(Ubuntu).
I changed the folders structure to
MyApp
├──build
│ ├──Debug
| └──Release
├──src
├──libs
| └──MyLib
| ├──build
| ├──src
| ├──include
| └──CMakeLists.txt
├──include
├──src
└──CMakeLists.txt
What kind of changes I need to make with both of CMakeLists.txt to make MyLib as shared library and use it in MyApp?
First of all, as already mentioned, you'll need to add the MyLib directory with add_subdirectory in the top-level CMakeLists.txt:
...
add_subdirectory(libs/MyLib)
...
Then, defining a shared/dynamic library with CMake is pretty straight forward. You use add_library providing the name of the library, the source files and some flags. By default it will create a static library, but with the keyword SHARED you can change that:
add_library(MyLib SHARED
MySource1.cpp
MySource2.cpp
...
)
Have a look here: https://cmake.org/cmake/help/latest/command/add_library.html
By the way, all generated code (including the library) will end up in the one and only build directory (which you either specify with cmake -B $BUILD_DIR or which is the working directory for running cmake). So you won't have an additional one in your libs/MyLib folder.
I want to use g2o library in my C++11 project on Ubuntu 18.04, but I cannot make build working. I have all the dependencies. But I cannot link g2o library to my project via CMakeLists.txt
I am a newbie in C++ dependencies.
I've tried cloning https://github.com/RainerKuemmerle/g2o repository and building it with cmake.
The structure is as following:
MY_PROJECT
|__ cmake_modules
|__ project_src
|__ CMakeLists.txt
|__ Thirdparty
|____ g2o
|____ bin
|____ build
|____ cmake_modules # findG2O.cmake
|____ lib # .so shared libraries (all of them, like 20)
|____ g2o
|____ core # headers and source files
|____ solvers
|____ types
|____ CMakeLists.txt
I added cmake_modules from inside g2o to the CMakeLists.txt of my_project
and than try to find it with find_package but it is not found.
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/g2o/cmake_modules)
find_package(G2O REQUIRED)
if(NOT G2O_FOUND)
message(FATAL_ERROR "G2O not found.")
endif()
I left findG2O.cmake untouched as it is in https://github.com/RainerKuemmerle/g2o/blob/master/cmake_modules/FindG2O.cmake
Should I change the findG2O.cmake? I do not really understand what is going on. How should I proceed with building out of the source and linking?
I haven't found precise answer to my problem anywhere on StackOverflow but maybe I just didn't know what I was searching for.
Error message was:
/home/miki/ORB_SLAM2/Thirdparty/g2o/g2o/types/sim3/types_seven_dof_expmap.h:29:10: fatal error: g2o/config.h: No such file or directory #include "g2o/config.h"
When I tried to change to #include "../../config.h" it worked. How can I solve it in CMakeLists so I do not have to change all includes in ThirdParty library?
The config.h is generated after executing the command
cmake ..
in the folder
MY_PROJECT/Thirdparty/g2o/build
, and this file has some information like what type of used floating point or library you try to use. I think such information will be used to modify some code blocks automatically.
By default, the location of file config.h is in the folder
MY_PROJECT/Thirdparty/g2o/build/g2o
Or you can also use the command
make install
to copy this file to the install path.
If your ${CMAKE_PREFIX_INTALL} is /home/user/, then the location of file config.h is in the folder
/home/user/include/g2o
And if you want to find g2o libraries with find_package, then you need to write
set (G2O_ROOT /home/user)
before the find_package.
Finally, add the header path into CMakeLists.txt, like
include_directories(${G2O_INCLUDE_DIR}
I want to build an application under Windows using CMake + Visual Studio with a lot of dependencies, such as zlib. All of them are static libraries.
I've tried ADD_SUBDIRECTORY and this works pretty well but instead of building only depending target (zlibstatic) it builds all of them.
How to remove unused targets (with their solutions) or choose only one?
Mainly I'm searching for feature to define only needed targets.
Part of my CMakeLists.txt:
ADD_SUBDIRECTORY("${CMAKE_CURRENT_SOURCE_DIR}/deps/zlib")
TARGET_INCLUDE_DIRECTORIES(MyProject PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/deps/zlib")
TARGET_LINK_LIBRARIES(MyProject zlibstatic)
I finally figured out how to do it.
MyProject
├───build <- here I call cmake
├───deps
│ └───zlib
│ └───CMakeLists.txt
├───inc
├───src
└───CMakeLists.txt
# Include project but remove all tartgets
ADD_SUBDIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/deps/zlib EXCLUDE_FROM_ALL)
# Use only specific one target
ADD_DEPENDENCIES(MyProject zlibstatic)
# Include dirs from zlib source directory and from output directory becuse it generates some headers
TARGET_INCLUDE_DIRECTORIES(MyProject PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/deps/zlib
${CMAKE_CURRENT_BINARY_DIR}/deps/zlib
)
# Just to create beautiful structure in project tree
SET_PROPERTY(TARGET zlibstatic PROPERTY FOLDER Deps)
# Link after all
TARGET_LINK_LIBRARIES(MyProject zlibstatic)
I suggest you use vcpkg or conan instead to resolve your dependent library issue this is much cleaner and works well except for header only libraries.
You can of cause do that manually but than you loose the nice cmake setup.
I am working on a c++ project using cmake that uses hiredis. The CMake and compilation process do not give any errors. However, when I try to execute my project (from the terminal or from the IDE I'm using [CLion], I get the following error:
dyld: Library not loaded: libhiredis.0.13.dylib
Referenced from: /Users/connorriley/CLionProjects/DispatchingOptimization/bin/dispatch
Reason: image not found
I'm not sure why my project is looking for libhiredis.0.13.dylib because the only hiredis library file I have is libhiredis.dylib.
My project file structure is the following:
.
+-- bin
| +-- dispatch (my executable)
+-- lib
| +-- hiredis
| | +-- libhiredis.dylib
| +-- otherlibs
+-- src
| +-- source code/subfolders with source code
additional info:
compiler: clang
os: macOS 10.12.3
cmake version 3.7.2
Looks like your DYLD_LIBRARY_PATH is not set correctly. You can get more information by setting DYLD_PRINT_LIBRARIES and/or some other environment variables mentioned here
But probably you just need to add your hiredis directory to CMAKE_LIBRARY_PATH like this:
set(CMAKE_LIBRARY_PATH ${CMAKE_LIBRARY_PATH} ${PROJECT_SOURCE_DIR}/lib/hiredis)
I fixed my issue, it was that I went into my hiredis directory and typed:
make
but didn't follow that with
make install
Therefore, the file that my code was looking for was not in my /usr/local/lib
I have several projects (all building with CMake from the same source tree structure) all using their own mix out of dozens of supporting libraries.
So I came about the question how to set up this correctly in CMake. So far I have only found CMake how to correctly create dependencies between targets, but I'm still struggling between setting up everything with global dependencies (the project level does know it all) or with local dependencies (each sub-level target only handles its own dependencies).
Here is a reduced example of my directory structure and what I currently came up with using CMake and local dependencies (the example shows only one executable project, App1, but there are actually more, App2, App3, etc.):
Lib
+-- LibA
+-- Inc
+-- a.h
+-- Src
+-- a.cc
+-- CMakeLists.txt
+-- LibB
+-- Inc
+-- b.h
+-- Src
+-- b.cc
+-- CMakeLists.txt
+-- LibC
+-- Inc
+-- c.h
+-- Src
+-- c.cc
+-- CMakeLists.txt
App1
+-- Src
+-- main.cc
+-- CMakeLists.txt
Lib/LibA/CMakeLists.txt
include_directories(Inc ../LibC/Inc)
add_subdirectory(../LibC LibC)
add_library(LibA Src/a.cc Inc/a.h)
target_link_libraries(LibA LibC)
Lib/LibB/CMakeLists.txt
include_directories(Inc)
add_library(LibB Src/b.cc Inc/b.h)
Lib/LibC/CMakeLists.txt
include_directories(Inc ../LibB/Inc)
add_subdirectory(../LibB LibB)
add_library(LibC Src/c.cc Inc/c.h)
target_link_libraries(LibC LibB)
App1/CMakeLists.txt (for the ease of reproducing it I generate the source/header files here)
cmake_minimum_required(VERSION 2.8)
project(App1 CXX)
file(WRITE "Src/main.cc" "#include \"a.h\"\n#include \"b.h\"\nint main()\n{\na();\nb();\nreturn 0;\n}")
file(WRITE "../Lib/LibA/Inc/a.h" "void a();")
file(WRITE "../Lib/LibA/Src/a.cc" "#include \"c.h\"\nvoid a()\n{\nc();\n}")
file(WRITE "../Lib/LibB/Inc/b.h" "void b();")
file(WRITE "../Lib/LibB/Src/b.cc" "void b() {}")
file(WRITE "../Lib/LibC/Inc/c.h" "void c();")
file(WRITE "../Lib/LibC/Src/c.cc" "#include \"b.h\"\nvoid c()\n{\nb();\n}")
include_directories(
../Lib/LibA/Inc
../Lib/LibB/Inc
)
add_subdirectory(../Lib/LibA LibA)
add_subdirectory(../Lib/LibB LibB)
add_executable(App1 Src/main.cc)
target_link_libraries(App1 LibA LibB)
The library dependencies in the above example do look like this:
App1 -> LibA -> LibC -> LibB
App1 -> LibB
At the moment I prefer the local dependencies variant, because it's easier to use. I just give the dependencies at the source level with include_directories(), at the link level with target_link_libraries() and at the CMake level with add_subdirectory().
With this you don't need to know the dependencies between the supporting libraries and - with the CMake level "includes" - you will only end-up with the targets you really use. Sure enough you could just make all include directories and targets be known globally and let the compiler/linker sort out the rest. But this seems like a kind of bloating to me.
I also tried to have a Lib/CMakeLists.txt to handle all the dependencies in the Lib directory tree, but I ended up having a lot of if ("${PROJECT_NAME}" STREQUAL ...) checks and the problem that I can't create intermediate libraries grouping targets without giving at least one source file.
So the above example is "so far so good", but it throws the following error because you should/can not add a CMakeLists.txt twice:
CMake Error at Lib/LibB/CMakeLists.txt:2 (add_library):
add_library cannot create target "LibB" because another target with the
same name already exists. The existing target is a static library created
in source directory "Lib/LibB".
See documentation for policy CMP0002 for more details.
At the moment I see two solutions for this, but I think I got this way too complicated.
1. Overwriting add_subdirectory() to prevent duplicates
function(add_subdirectory _dir)
get_filename_component(_fullpath ${_dir} REALPATH)
if (EXISTS ${_fullpath} AND EXISTS ${_fullpath}/CMakeLists.txt)
get_property(_included_dirs GLOBAL PROPERTY GlobalAddSubdirectoryOnceIncluded)
list(FIND _included_dirs "${_fullpath}" _used_index)
if (${_used_index} EQUAL -1)
set_property(GLOBAL APPEND PROPERTY GlobalAddSubdirectoryOnceIncluded "${_fullpath}")
_add_subdirectory(${_dir} ${ARGN})
endif()
else()
message(WARNING "add_subdirectory: Can't find ${_fullpath}/CMakeLists.txt")
endif()
endfunction(add_subdirectory _dir)
2. Adding an "include guard" to all sub-level CMakeLists.txts, like:
if (NOT TARGET LibA)
...
endif()
I've been testing the concepts suggested by tamas.kenez and m.s. with some promising results. The summaries can be found in my following answers:
preferred cmake project structure
CMake share library with multiple executables
Making cmake library accessible by other cmake packages automatically
Adding the same subdirectory multiple times is out of question, it's not how CMake is intended to work. There are two main alternatives to do it in a clean way:
Build your libraries in the same project as your app. Prefer this option for libraries you're actively working on (while you're working on the app) so they are likely to be frequently edited and rebuilt. They will also show up in the same IDE project.
Build your libraries in an external project (and I don't mean ExternalProject). Prefer this option for libraries that are just used by your app but you're not working on them. This is the case for most third-party libraries. They will not clutter your IDE workspace, either.
Method #1
your app's CMakeLists.txt adds the subdirectories of the libraries (and your libs' CMakeLists.txt's don't)
your app's CMakeLists.txt is responsible to add all immediate and transitive dependencies and to add them in the proper order
it assumes that adding the subdirectory for libx will create some target (say libx) that can be readily used with target_link_libraries
As a sidenote: for the libraries it's a good practice to create a full-featured library target, that is, one that contains all the information needed to use the library:
add_library(LibB Src/b.cc Inc/b.h)
target_include_directories(LibB PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/Inc>)
So the location of include directories of the library can remain an internal affair of the lib. You will only have to do this;
target_link_libraries(LibC LibB)
then the include dirs of LibB will also be added to the compilation of LibC. Use the PRIVATE modifier if LibB is not used by the public headers of LibC:
target_link_libraries(LibC PRIVATE LibB)
Method #2
Build and install your libraries in seperate CMake projects. Your libraries will install a so-called config-module which describes the locations of the headers and library files and also compile flags. Your app's CMakeList.txt assumes the libraries has already been built and installed and the config-modules can be found by the find_package command. This is a whole another story so I won't go into details here.
A few notes:
You can mix #1 and #2 as in most cases you will have both unchanging, third-party libs and your own libraries under development.
A compromise between #1 and #2 is using the ExternalProject module, preferred by many. It's like including the external projects of your libraries (built in their own build tree) into your app's project. In way it combines the disadvantages of both approaches: you can't use your libraries as targets (because they're in a different project) and you can't call find_package (because the libs are not installed the time your app's CMakeLists is configuring).
A variant of #2 is to build the library in an external project but instead of installing the artifacts use them from their source/build locations. For more about this see the export() command.