Directory Structure for Library CMake Projects - c++

I've an Application project Demo which depends on my Shared library Hello. Library Hello should be redistributable. So I need to distribute the headers of Hello as well as use it in my Demo projects. What directory structure and CMake configuration should I use ? I previously had a flat structure and Hello was a header only subdirectory with no CMakeLists.txt. Now I am planning this directory structure.
Demo
main.cpp
app.h
app.cpp
CMakeLists.txt
Hello
includes
matrix.hpp // header only
diagonal.hpp
point.hpp
store.h
analyzer.h
sources
store.cpp
alanyzer.cpp
CMakeLists.txt
Previously the analyzer was header-only which is now splited in header and source. I am mixing header-only things. Is this a good structure ? But I prefer to use the nice #include <Hallo/matrix.hpp> not the ugly one #include "Hallo/includes/matrix.hpp" or just #include "matrix.hpp". I expect this library Hello will be used for other applications and libraries as well.
Demo/CMakeList.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(Demo)
ADD_SUBDIRECTORY(Demo)
SET(Demo_HEADERS
app.h
)
SET(Demo_SOURCES
app.cpp
main.cpp
)
INCLUDE_DIRECTORIES(${Hello_INCLUDE_DIRS})
# ^^^^ Is this how I need to access the headers ? or just ADD_SUBDIRECTORY() will work
ADD_EXECUTABLE(Demo ${Demo_SOURCES} ${Demo_HEADERS})
TARGET_LINK_LIBRARIES(Demo Hello)
Hello/CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(Hello)
FIND_PACKAGE(Boost COMPONENTS filesystem program_options thread system serialization date_time chrono REQUIRED)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
SET(Hello_SOURCES
store.cpp
analyzer.cpp
)
INCLUDE_DIRECTORIES((${HELLO_SOURCE_DIR}/includes)
# ^^^^ Is this how I need to access the headers ?
ADD_LIBRARY(Hello ${Hello_SOURCES})
TARGET_LINK_LIBRARIES(Hello ${Boost_LIBRARIES})
I am kind of confused with all this as there is no one specific way to do these all.
--- EDIT ---
Should I have this structure ? or Do some other libraries generally use this structure ? or what are the structures generally practiced ?
hallo
includes
hallo
sources

If you want to access your headers like this:
#include <matrix.hpp>
then you need to include directories. I suggest you the next:
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/Hello/includes)
Your mistake is that you never defines Hello_INCLUDE_DIRS variable in global scope, only in local. So your include do nothing. CMAKE_SOURCE_DIR is always defined and safe to use for includes. Thus you need either define Hello_INCLUDE_DIRS in global scope or use INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/Hello/includes).
Usage is up to the developer as always. I prefer the structure:
+ Project Root
+-> Build
+-> Documentation
+-> Include
+-> Source
+-> Test
+ CMakeLists.txt
Then I can preset in root CMakeLists.txt next useful variables:
SET(Project_Include_Dir "${CMAKE_SOURCE_DIR}/Include")
SET(Project_Source_Dir "${CMAKE_SOURCE_DIR}/Source")

Related

CMake: No such file or directory error with a custom library

I am trying to make a library using CMake.
I would like the library to work as many library widely being used,
so I mimicked several structures of CMake files in the internet and finally made a structure described below, if possible.
Also, I want to use the #includes as shown in the code snippet.
However, I get a fatal error from lib1.cpp which says "lib1.hpp: no such file or directory".
I am pretty sure this error is not the only error I will get, after fixing the current error.
What am I doing wrong?
Here are the list of directories, CMake files, and sources.
LIB_ROOT
CMakeLists.txt // mainCMake
+ lib
| CMakeLists.hpp // libCMake
| mainlib.hpp
| + include
| | lib1.hpp
| | lib2.hpp
| | ...
| + src
| | lib1.cpp
| | lib2.cpp
| | ...
+ test
| CMakeLists.txt // testCMake
| test.cpp
mainCMake:
cmake_minimum_required(VERSION 3.10)
project(LIB)
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
set(CMAKE_CXX_STANDARD 20)
add_subdirectory(lib)
add_subdirectory(test)
libCMake:
add_library(LIB
mainlib.hpp
#include
include/lib1.hpp
include/lib2.hpp
...
#src
src/lib1.cpp
src/lib2.cpp
...
)
target_include_directories(LIB PUBLIC ${CMAKE_CURRENT_DIR}/include ${CMAKE_CURRENT_DIR}/src)
testCMake:
add_executable(Test test.cc)
target_link_libraries(Test LINK_PUBLIC LIB)
lib1.hpp
#ifndef lib1
#define lib1
namespace lib {}
#endif
lib1.cpp
#include "lib1.hpp"
mainlib.hpp
#include <include/lib1.hpp>
test.cpp
#include <mainlib.hpp>
int main() {}
There is no such variable as ${CMAKE_CURRENT_DIR}. You surely mean ${CMAKE_CURRENT_SOURCE_DIR}. Please see the documentation for the list of CMake variables, here: https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html
For CMAKE_CURRENT_SOURCE_DIR, the documentation is here: https://cmake.org/cmake/help/latest/variable/CMAKE_CURRENT_SOURCE_DIR.html
There is also no such argument as LINK_PUBLIC, as in here:
# WRONG
target_link_libraries(Test LINK_PUBLIC LIB)
The line you meant to write was
target_link_libraries(Test PRIVATE LIB)
There is a PUBLIC keyword, but it makes no sense on executables since you can't link to an executable*. There are three visibility specifiers in CMake: PRIVATE, INTERFACE, and PUBLIC. PUBLIC is exactly the same as both PRIVATE and INTERFACE. PRIVATE means that the property is only relevant to the target; INTERFACE means that the property is only relevant to targets linking to this target. So you want PRIVATE here.
* sort of... there's a whole ENABLE_EXPORTS thing that's used for writing plugins, but it is relatively rare.
Also, this line makes no sense:
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR})
Unless you have custom CMake modules in the root of your project, this is pointless and overrides a user's ability to set CMAKE_MODULE_PATH themselves. Something like
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
is a bit more common, but still pointless unless you actually do have custom modules.
I am trying to make a library using CMake. I would like the library to work as many library widely being used, so I mimicked several structures of CMake files in the internet
I'm sorry to be the one to let you know, but imitating existing CMake builds is a terrible approach. Many of them were written in the CMake stone age (versions less than 3.14... you should use the newest one for new code) and use bad or out of date practices. Look for talks at CppCon and Meeting C++ by Craig Scott and Deniz Bahadir for better advice. Craig Scott's book, "Professional CMake", while not free, is the most comprehensive resource there is at the moment. I highly recommend it.

CMake: Can we specify include directories for a specific set of files not forming an executable or lib?

If I have this source tree:
C:\app:
src:
CMakeLists.txt
main.cpp --> #include "acme/header_only_lib/api.h"
D:\3rdparty\acme\header_only_lib:
api.h --> #include "detail.h"
detail.h
Without using symlink tricks, and without adding files to the 3rdparty folders, if I must retain #include "acme/header_only_lib/api.h" in main.cpp, how should I specify the include directories in CMake such that api.h can see detail.h, without adding global include directory of D:\3rdparty\acme\header_only_lib? The header-only-lib is not an executable nor library target, and its code is not modifiable by me. I also don't want to pollute my global include directories by adding D:\3rdparty\acme\header_only_lib because the filenames inside there are too common and will easily clash with other libraries/future code.
Is there a CMake mechanism where I can say:
Only for D:\3rdparty\acme\header_only_lib\api.h, add D:\3rdparty\acme\header_only_lib as the include directory?
To add a directory to the global list of include directories, you use e.g.
include_directories( ${CMAKE_SOURCE_DIR}/3rdparty )
Note that you should not hardcode absolute paths (like D:\) into your CMakeLists.txt as that makes it impossible to build your project in any other location. CMake offers variables like ${CMAKE_SOURCE_DIR} and ${CMAKE_BINARY_DIR} for just that purpose.
If you want to add a directory to the list of include directories for a specific part of your build only, you use e.g.
target_include_directories( app PRIVATE ${CMAKE_SOURCE_DIR}/3rdparty )
This adds the directory only for the target (executable / library) app.
Note that, if your acme/header_only_lib is supposed to be installed alongside with the app binaries, this approach won't work, as your acme headers would need to "see" each other on the client's machine, which is unlikely if they reside in the acme/header_only_lib subdirectory but address each other without subdirs. That would require your client (who isn't using your CMakeLists.txt for his builds) to add acme/header_only_lib to the include paths for your header lib to work -- you should not do that.
Use include_directories or target_include_directories:
include_directories("D:\3rdparty")
OR with target_include_directories if you want to make this change only for the main target:
add_executable(main main.cpp)
target_include_directories(main PUBLIC "D:\3rdparty")
Then you can just #include "acme/header_only_lib/api.h" or #include <acme/header_only_lib/api.h>
Header only lib
If you want to do this for header-only-lib only, you need to do this in it's CMake file. First add the library as INTERFACE with no source files:
add_library(header-only INTERFACE)
Then include directories for it:
target_include_directories(header-only INTERFACE include-dir-for-header-only)
Then link it to the main target
find_library(HeaderOnly
NAMES header-only
HINTS "D:\3rdparty\path-to-lib"
)
target_link_libraries(main header-only)

CMake: Include vs add_subdirectory: Relative header file path

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.

CMake's equivalent to Visual Studio's Property Sheets (.vsprops)

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)

CMake and handling subfolder header files

I'm trying to set up my project to build several dynamic libraries that encompass its complete functionality. There are subfolders for each library. The subfolder libraries are dependent on each other, so they must reference functions from each other. I seem to have managed to get CMake to run without errors on the project, but when I go to build, I have trouble with my headers finding each other. It seems at build time, the include path isn't set up correctly. How can I fix this? Are there additional steps I need to take to set up the include path correctly?
The structure looks something like this
root
CMakeLists.txt
bin
lib
lib0
CMakeLists.txt
lib0.h
lib0.cpp
lib1
CMakeLists.txt
lib1.h
lib1.cpp
...
In the CMakeLists.txt for the root directory I have declarations like this:
set(ROOT /blah/blah/root)
include_directories(${ROOT}/lib0)
include_directories(${ROOT}/lib1)
add_subdirectory(lib0)
add_subdirectory(lib1)
In the CMakeLists.txt for the subfolders, I have:
set(lib0_SOURCES "")
list(APPEND lib0_SOURCES lib0.cpp)
add_library(lib0_lib ${lib0_SOURCES})
And my headers for the libraries look like (suppose this is lib0.h):
#include "lib1/lib1.h"
...
CMake runs fine with no errors, but when I go to compile, I get an error like:
In file included from /blah/blah/root/lib0/lib0.cpp:1:0:
/blah/blah/root/lib0/lib0.h:1:30: fatal error: lib1/lib1.h: No such file or directory
You told GCC to #include the file "lib1/lib1.h". When you build, CMake will ask to look for extra headers in "${ROOT}/lib0" and "${ROOT}/lib1"
So, GCC is trying "${ROOT}/lib0/lib1/lib1.h" and "${ROOT}/lib1/lib1/lib1.h" Yup, cant work.
To fix it:
you can use in your root CMakeLists.txt : include_directories(".")
keep your CMakeLists but #include the file "lib1.h"
remove the include_directories in CMakeLists and #include the file "../lib1/lib1.h"
IMO, I'd go for the first option!
You need to use the double naming scheme or specify the base directory as the include path:
root
CMakeLists.txt
bin
lib
lib0
CMakeLists.txt
lib0.cpp
lib0
lib0.h
lib1
CMakeLists.txt
lib1.cpp
lib1
lib1.h
...
I would ask CMake to just consider the ROOT directory for C/C++ include look-ups:
set(ROOT /blah/blah/root)
include_directories(${ROOT})
add_subdirectory(lib0)
add_subdirectory(lib1)
Then, in C/C++, use angle braquets ('<' and '>') rather than double quotes ('"'):
#include <lib1/lib1.h>