I'm currently transforming my C++ project from simply using a Makefile to using CMake. As I'm unfamiliar with CMake, I try and avoid learning "old" CMake and stick to "modern CMake" best practices, e.g. described here.
However, I could not figure out how to include a simple, header-only, third party library without getting bothered with warnings about that library.
Say I have a project structure like this:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
third-party-lib/
foo/
foo.h
Say main.cpp uses foo: #include <foo.h>
The problem is, I use a bunch of warning flags and foo.h introduces some warnings that I don't care about, as I'm not the author and it's nothing serious.
In a classic Makefile I would just have written -isystem third-party-lib/foo somewhere appropriate and be done.
In CMake, I achieved this by a include_directories(SYSTEM PRIVATE third-party-lib/foo) in the top-level CMakeLists.txt.
Now, according to the link above, I should keep my hands off include_directories() to avoid hidden dependencies and I think that this is a good idea. I'd rather specify for each target that actually needs foo to include that library and treat it as 'don't warn me here'. As I understand it, the approach would be:
find foo target in top-level CMakeLists.txt
target_link_libraries(main PRIVATE foo) or so in src/CMakeLists.txt
How would I achieve that, i.e. what is the command for finding, and where to specify the SYSTEM property? Or any other suggestions for how to approach this?
To add a header-only library in modern CMake, you can use target_include_directories with SYSTEM INTERFACE. You can place this in your top-level CMake file, before processing the src/CMakeLists.txt file:
add_library(foo INTERFACE)
target_include_directories(foo SYSTEM INTERFACE
${CMAKE_SOURCE_DIR}/third-party-lib/foo
)
Your friend is target_include_directories. It works like include_directories but on a per-target basis.
add_executable(foo foo.c)
target_include_directories(foo SYSTEM
PRIVATE sys_inc
)
Related
This question may be partly duplicate, e.g. this question, but is more about what if any are better solutions. Since this question ended up rather long, I marked specific questions with "+Q+" in bold italic.
I have the situation that I wrote a small library B that depends on some other huge project A split into many libraries A1, A2, ..., An, some of which my library depends on and some on which it doesn't. It was a bit of a pain to do the proper linking. The library is starting to be used by others and I would like to avoid everyone having to go through this awful linking process, i.e. I want to compile all the external libraries of A into my B. Assume A is completely external, i.e. that I have no way to recompile A (in this case I do, but it is complicated and I would like to know options for the case that I don't).
I imagine this must be a very standard thing to do, I have used other popular libraries and never did I have to link all the other libraries that they transitively depend on .. ? So I started looking for solutions, and while I found working ones, most solutions seem like a big mess and I wonder if this is really done in practice or if there is some idiomatic way for this.
To avoid more eventual headaches if I ever need a different case, I want to consider all combinations of static/shared libraries, i.e.
A & B are static
A is static, B is shared
A is shared, B is static
A & B are shared
To give some MWE of the code setup (the variables LIB1_ROOT and LIB2_ROOT in the CMakeLists.txt files are A/ and B/ respectively):
A/include/lib1.hh
struct Lib1 { void run() const; };
A/src/lib1.cc
#include <iostream>
#include <lib1.hh>
void Lib1::run() const { std::cout << "Hello from lib1\n"; }
A/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(A)
include_directories(include)
add_library(lib1 src/lib1.cc)
install(TARGETS lib1 DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/lib")
B/include/lib2.hh
class Lib2 {
class Implementation;
Implementation* impl;
public:
Lib2();
~Lib2();
void run() const;
};
B/src/lib2.cc
#include <iostream>
#include <lib1.hh>
#include <lib2.hh>
class Lib2::Implementation {
const Lib1 m_lib1{};
public:
void run() const { std::cout << "using lib1 from lib2: "; m_lib1.run(); }
};
Lib2::Lib2() : impl{new Implementation} {}
Lib2::~Lib2() { delete impl; };
void Lib2::run() const { impl->run(); }
App/src/app.cc
#include <lib2.hh>
int main() { Lib2 l; l.run(); }
App/CMakeLists.cc
cmake_minimum_required(VERSION 3.14)
project(App)
include_directories(include "${LIB2_ROOT}/include")
find_library(LIB2 lib2 "${LIB2_ROOT}/lib")
add_executable(app src/main.cc)
target_link_libraries(app "${LIB2}")
install(TARGETS app DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/bin")
I used the pImpl pattern for B since what is the point of hiding link dependencies when I then make the user of my library dig out all the headers anyway.
Finally B/CMakeLists.txt (for my library) depends on the cases I mentioned above:
A & B static
B/CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
project(B)
include_directories(include "${LIB1_ROOT}/include")
find_library(LIB1 lib1 "${LIB1_ROOT}/lib")
add_library(lib2_dependent src/lib2.cc)
add_custom_target(lib2 ALL
COMMAND ar -x "${LIB1}"
COMMAND ar -x "$<TARGET_FILE:lib2_dependent>"
COMMAND ar -qcs "${CMAKE_STATIC_LIBRARY_PREFIX}lib2${CMAKE_STATIC_LIBRARY_SUFFIX}" *.o
COMMAND rm *.o
DEPENDS lib2_dependent
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/lib"
)
This solution is from the question I linked at the start. There was also an in my opinion much better version in this answer using
ar -M <<EOM
CREATE lib2.a
ADDLIB lib1.a
ADDLIB lib2_dependent.a
SAVE
END
EOM
but I could not get to work the here-document inside CMakeLists.txt ... ? There was an additional answer providing what I think was a CMake function to do this, but it was a huge block of code which I found a bit ridiculous for something that should be simple / standard practice / integrated into CMake ?
The custom_target solution I wrote here also works, but as mentioned in other answers as well, it unpacks object files which lie around and have to be removed again, for each library I want to compile this way.
And still in both cases, I can only wonder what is the point of using CMake then if I have to use ar manually anyhow. +Q+ Is there no better / CMake-integrated way to "compile-in" transitive dependencies / combine static libraries?
A static, B shared
As far as I found in this case, I'm out of luck if I cannot recomple A and it is not compiled as position independent code. The next best thing to make it work was to do just that by adding set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") to A/CMakeLists.txt. Again, there seemed to be better alternatives: set(CMAKE_POSITION_INDEPENDENT_CODE ON) or set_property(TARGET lib1 PROPERTY POSITION_INDEPENDENT_CODE ON) from here, which were complete ignored in my case .. (compiling with VERBOSE=1, there was no -fPIC flag to be seen anywhere and B did not compile)
The B/CMakeLists.txt was easy in this case
cmake_minimum_required(VERSION 3.14)
project(B)
include_directories(include "${LIB1_ROOT}/include")
find_library(LIB1 lib1 "${LIB1_ROOT}/lib")
add_library(lib2 SHARED src/lib2.cc)
target_link_libraries(lib2 "${LIB1}")
install(TARGETS lib2 DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/lib")
and while I don't find anything wrong with this solution, according to answers I found I should need to set additional flags like set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--export-all-symbols") in order for the symbols in the static library to be found. However the above works just fine, compiles, and App runs without issues? +Q+ Am I doing anything wrong here? Or is it maybe due to some update to CMake since these older answers?
A shared, B static or both shared
According to what I found here, this is basically impossible, because shared libraries are "final" in some sense. I find this very strange, surely there are many libraries that do not require a project that uses them to link every single dependency of that library that happens to be a shared library? +Q+ Are there really no options in these cases?
Yep, you're doing wrong :)
The CMake-way is to use packages. Once you've made the LibA package, you just do find_package(LibA) in your B/CMakeLists.txt and also the generated LibBConfig.cmake (the package config file, so your clients would need just find_package(libB) in their App/CMakeLists.txt) ought to find (that is questionable IMHO, but currently its CMake way) its dependency the same way (using or not the CMake's helper find_dependency).
The whole process gets much simpler that way:
you have/give the full control on how to build (including what version, library type static/dynamic, &etc) and where to install the libA on your developer's host and customer's machine (so dependent projects could find it)
same for libB and App
you and any customer of your library(ies) use the well known CMake way to find dependencies and have full control over this process
and the most important let CMake do complicated things instead of you that keeps your build logic much simpler in CMakeLists.txt of all involved projects
I have a c++ project with several subdirectories, e.g.
src/
CMakeLists.txt
main.cpp
module1/
CMakeLists.txt
code.cpp
code.h
module2/
CMakeLists.txt
code2.cpp
It seems that the two ways to deal with this in cmake is to either use add_subdirectory(module1) or include(module1) in my src/CMakeLists.txt. Somewhere I read, that the include use is regarded legacy/deprecated. My src/module1/CMakeLists.txt looks like this:
include_directories(${CMAKE_CURRENT_LIST_DIR})
set( SRCS
${SRCS}
${CMAKE_CURRENT_LIST_DIR}/code.cpp
)
set( QT_FILE_HEADERS
${QT_FILE_HEADERS} code.h
)
If I try to use the add_subdirectory method and want to usecode.h in main.cpp I have to write #include "module1/code.h". If I do the include method of adding module1, I can simply write #include "code.h". I would prefer not to specify the relative path of the include files when I use them somewhere else, is there a way to achieve this using the add_subdirectory method? I thought the include_directories line should have taken care of that.
This is not how you should make modules -- sure you can do it this way, it works, but it is not very useful. Given your layout, simply reference module1/code.cpp in the main CMakeLists.txt file.
However, if you want to use modules, make each one a separate static library. This will really simplify things!
In src/CMakeLists.txt write:
add_subdirectory(module1)
add_executable(myprogram main.cpp)
target_link_libraries(myprogram module1)
In src/module1/CMakeLists.txt write:
add_library(module1 STATIC code.cpp)
target_include_directories(module1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
This way, you are only passing one single thing back from the module1 CMake script: the module1 target. Your main doesn't need to know anything about what happens inside there. If the code in module1 requires specific external libraries, link them there, the main CMake script won't need to know about it. Simply by linking to module1, all the magic will happen behind the scenes, your program will be compiled with the right include directories and linked to the right libraries.
I am currently simply trying to add a library to one of the example for VTK.
So let's imagine we have this scenario in which I want to redefine the behavior or the trackball. What I did in that is to create my own trackball (based on the model provided by vtkInteractorStyleTrackballCamera). So I created two files: InteractorStyleTrackballCamera.cpp and InteractorStyleTrackballCamera.h
When I CMake, everything is just fine. However when I open the solution with Visual Studio 2013 and try to build the all_build target I get an error stating:
InteractorStyleTrackballCamera.h no such file or directory.
I know of course what it means, however I cannot understand why I get this error. It may be that my CMakeLists.txt is kind of broken (it is the only thing I can think of), so here it is:
cmake_minimum_required(VERSION 2.8)
PROJECT(TrackballCamera)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
add_executable(TrackballCamera MACOSX_BUNDLE TrackballCamera)
add_library(InteractorStyleTrackballCamera InteractorStyleTrackballCamera.cpp InteractorStyleTrackballCamera.h)
if(VTK_LIBRARIES)
target_link_libraries(TrackballCamera ${VTK_LIBRARIES})
else()
target_link_libraries(TrackballCamera vtkHybrid vtkWidgets InteractorStyleTrackballCamera)
endif()
When I look at my solution explorer in VS13 I can clearly see 4 solutions, ALL_BUILD, InteractorStyleTrackballCamera (with the header and cpp) TrackballCamera and ZERO_CHECK. So that's what is puzzling me. Isn't it right that if the header is included in my solution explorer it should be found when I try to build ?
Oh and if you wonder what's inside my InteractorStyleTrackballCamera (not sure this is really relevant for that problem) I simply copied/pasted the content of vtkInteractorStyleTrackballCamera and replaced all the vtkInteractorStyleTrackballCamera by InteractorStyleTrackballCamera
Thanks in advance for the help.
EDIT: The error does not come from the file InteractorStyleTrackballCamera.cpp but from the file TrackballCamera.cxx when I try to include my header.
Basically the line is:
#include <InteractorStyleTrackballCamera.h>
I see the question has been answered. In addition, have a read of the documentation of
target_include_directories
https://cmake.org/cmake/help/v3.3/command/target_include_directories.html#command:target_include_directories
In CMAKE, you can imbue a target with properties that it carries forward into targets that depend on it. One such properties is the "include directories". This property is different in the following 3 scenarios:
Your target is itself being built
Your target is in the same project as the dependency
Your target has been installed and is being picked up with find_package
target_include_directories allows you to set the correct paths in all 3 cases.
see also target_link_libraries which can be used to ensure that libraries that your library depends on are pulled into any dependent target.
Confused yet? It took me months to get my head around this. Once I did, I realised how incredibly powerful CMAKE is.
#include <...> should only be used for including library headers. If you want to include a header file from your source directory, use #include "...".
With most compilers, the difference is that #include "..." also searches the source file's directory for the file to include, while #include <...> only searches include directories specified on the compiler's command-line (plus possibly some default ones).
Unrelated to the original question, but it seems to me you should link InteractorStyleTrackballCamera even when VTK_LIBRARIES is defined:
if(VTK_LIBRARIES)
target_link_libraries(TrackballCamera InteractorStyleTrackballCamera ${VTK_LIBRARIES})
else()
target_link_libraries(TrackballCamera vtkHybrid vtkWidgets InteractorStyleTrackballCamera)
endif()
I'm trying to migrate from Visual Studio towards Jetbrains' (awesome) CLion IDE which uses CMake to organize the projects.
Until now, the transition has been smooth: creating CMake projects and importing them into CLion is easy, and I can begin coding on one plateform then continue on another one without problems.
However, one aspect of Visual Studio that I couldn't find an equivalent to in CMake is property sheets: I use them mainly for holding the include directories' paths and the linking libs for libraries (i.e. one .vsprops file for each library, e.g. OpenCV.vsprops, Boost.vsprops, etc.).
This way, in VS, I could share a library's .vsprops file between different projects without having to configure the paths/libs each time.
Does CMake have a similar mechanism to Visual Studio's property sheets ? How is it possible to store a library's includes/libs in a CMake-parsable file then "import" it in CMakeLists.txt in order to link against the library ?
Basically, what I want to do is:
Create a "cmake property sheet" (for lack of a better name) for a given library.
Then, in CMakeLists.txt, write something like link_target_to_libs(myTarget "path/to/propertySheet1" "path/to/propertySheet2" ...) .
In CMake, libraries can export a package with IMPORTED targets which other buildsystems import using find_package:
http://www.cmake.org/cmake/help/v3.1/manual/cmake-packages.7.html
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html#imported-targets
Instead of 'linking to property sheets', you link to the IMPORTED targets.
target_link_libraries(myTarget Dep1::Dep1 Dep2::Dep2)
Not all libraries create IMPORTED targets, and not all provide cmake config-file packages. In those cases (including OpenCV and Boost), CMake provides find modules:
http://www.cmake.org/cmake/help/v3.0/manual/cmake-developer.7.html#find-modules
which you use with find_package and link to the contents of variables.
Since I really want to make the libraries' inclusion/linking into a one-line command, and as far as my (basic) knowledge of CMake goes, I think that some compromise should be made -- mainly sharing the target name's variable between CMakeLists.txt and the "property sheets". So this is my solution... until someone proposes a simpler/cleaner one:
A CMake property sheet is a .cmake text file,
A well-known variable name --TARGET-- designates the target (i.e. the first argument of add_executable()),
Aside from library-specific commands, a .cmake file contains a call to target_include_directories(${TARGET} PRIVATE ${PATH_TO_INCLUDE_DIR}) and target_link_libraries(${TARGET} ${LIST_OF_LIBS}),
In order to use/link against a library, call include("path/to/.cmake") in CMakeLists.txt.
I have successfully built and executed a simple program that uses X11 and OpenCV with the following files:
x11.cmake
target_include_directories(${TARGET} PRIVATE "/usr/include/X11")
target_link_libraries(${TARGET} "/usr/lib/x86_64-linux-gnu/libX11.so")
opencv.cmake
# OpenCV-specific stuff
set(OpenCV_DIR "/PATH/TO/OPENCV/INSTALL/DIR/share/OpenCV") # path to OpenCVConfig.cmake
find_package(OpenCV REQUIRED)
# include path
target_include_directories(${TARGET} PRIVATE ${OpenCV_INCLUDE_DIRS})
# linking libs
target_link_libraries(${TARGET} opencv_world opencv_ts)
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.4)
project(hello_clion)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
## hello-clion ##############################
# make a new target name
set(TARGET hello-clion)
# find sources
file(GLOB_RECURSE SOURCE_FILES "src/*.cpp" "src/*.hpp")
# declare a target
add_executable(${TARGET} ${SOURCE_FILES})
# link the libraries (to the last-declared ${TARGET}, which should be the last-added executable)
include("x11.cmake")
include("opencv.cmake")
#############################################
main.cpp
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <thread>
#include <opencv2/opencv.hpp>
#include <Xlib.h>
int main_x11()
{
// adapted from: http://rosettacode.org/wiki/Window_creation/X11#Xlib
}
int main_ocv()
{
// adapted from: http://docs.opencv.org/doc/tutorials/introduction/display_image/display_image.html#source-code
}
int main()
{
using namespace std;
thread tocv(main_ocv);
thread tx11(main_x11);
tocv.join();
tx11.join();
return 0;
}
Now, each time I want to use OpenCV in a project/program, I just have to put include("opencv.cmake") in the corresponding CMakeLists.txt.
This seems to work great, but there could certainly be problems I haven't discovered. (I was worried multiple macros adding the same target_link_libraries would cause "already defined" linking errors , but at least g++ 5.1.0 handles being given the same library name multiple times without error.)
In root CMakeLists.txt, BEFORE add_subdirectory() calls or globs, include:
macro(USES_WX)
include_directories(SYSTEM /usr/local/include/wx-3.0)
include_directories(SYSTEM /usr/local/lib/wx/include/gtk3-unicode-3.0)
link_directories(/usr/local/lib)
add_definitions(-D_FILE_OFFSET_BITS=64 -DWXUSINGDLL -D__WXGTK__ -pthread)
target_link_libraries(${TARGET} pthread wx_gtk3u_xrc-3.0 wx_gtk3u_html-3.0 wx_gtk3u_qa-3.0 wx_gtk3u_adv-3.0 wx_gtk3u_core-3.0 wx_baseu_xml-3.0 wx_baseu_net-3.0 wx_baseu-3.0)
endmacro()
(You can make the macro more fancy, like checking for if CMAKE_BUILD_TYPE is "Debug" or "Release" to link to the appropriate libraries, vary preprocessor definitions, etc. See http://www.cmake.org/cmake/help/v3.0/command/if.html)
And have your project's CMakeLists.txt be like this:
set(TARGET myProgramName)
add_executable(${TARGET} myProgramName.cpp)
USES_WX()
^^ The macro call MUST be after add_executable()
And, if you want multiple target support, modify the line in the root CMakeLists.txt section shown above to:
...
target_link_libraries(${ARGV0} pthread wx_gtk3u_xrc-3.0 ...)
...
And have your project's CMakeLists.txt be like this (less lines, but more chance for error):
add_executable(myProgramName myProgramName.cpp)
USES_WX(myProgramName)
In essence I want to be able to moc header files that are not part of any target in cmake with the additional difficulty that I don't know the filenames of those headers.
The actual project is quite complex and part of an automated build system. The following is an easy example.
Consider a project structured like this:
CMakeLists.txt
src/lib/source.cpp
src/lib/CMakeLists.txt
src/include/some_header.hpp # which is included in source.cpp
Content of main CMakeLists.txt:
cmake_mimimum_required(VERSION 2.8.6)
project("automoctest")
add_subdirectory(src/lib)
Content of src/lib/CMakeLists.txt:
include_directories(${CMAKE_HOME_DIRECTORY}/src/include)
find_package(Qt4 4.8 REQUIRED QtCore)
include(UseQt4)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_library(foo SHARED source.cpp)
target_link_libraries(foo ${QT_LIBRARIES})
set_target_properties(foo PROPERTIES AUTOMOC true)
Inside source.cpp the file some_header.hpp is included like this:
#include "some_header.hpp"
The Problem:
The file some_header.hpp includes a Q_OBJECT and has some signals, so moc needs to work its magic. But as the header is not inside the actual project the header will not get mocked. I don't even know the filename of some_header.hpp so I can't add it specifically to be mocked. Obviously AUTOMOC does not check the include_directories for mockable files even when a source file includes one of them.
What I tried (unsuccessfully):
use #include moc_some_header.cpp in source.cpp as it is described in the cmake documentation. This leads to an error in which cmake complains that it could not find some_header{.h,.hpp,.hxx,.H}
setting CMAKE_AUTOMOC_RELAXED_MODE to true. Even though it's not clear from the doc what this actually does. Made no difference anyway.
setting AUTOMOC_MOC_OPTIONS to -Isrc/include or -I/path/to/project/src/include or -I${CMAKE_HOME_DIRECTORY}/src/include Doesn't do anything that I could see.
The great thing about AUTOMOC is that I don't need to know which files actually need to be mocked. In this case however I would need to know all the headers that might have a Q_OBJECT inside, that are included by my source files.
Is there a way to tell AUTOMOC where exactly to look for mockable files?
Did you truly set AUTOMOC_MOC_OPTIONS to -Isrc/include, or to -I/path/to/myproject/src/include? The former probably doesn't exist.
I have always used the MOC macros; it looks like AUTOMOC is something new that is built into CMake.
I usually include all headers when creating a library or executable - i.e.
add_library(foo SHARED source.cpp ../include/some_header.hpp )
I assume that this will allow AUTOMOC to work. It will have the added benefit of causing make to work as expected - rebuilding your library when the header changes.
If you are truly unable to add the file to the add_library command ahead of time, then I think you'll have to write a cmake function to search for #include statements within source.cpp, locate those files, and search them for Q_OBJECT. If they match, add them to a variable - perhaps EXTRA_MOCS. Then, the add_library line becomes
add_library(foo SHARED source.cpp ${EXTRA_MOCS} )