CMake - dependencies (headers) between apps/libraries in same project - c++

I have the following project structure:
CMakeLists.txt
lib1/CMakeLists.txt and all cpp and header files of the lib
lib2/CMakeLists.txt and all cpp and header files of the lib
app/CMakeLists.txt and all cpp and header files of the app
The main CMakeLists.txt looks like:
PROJECT( ${PROJECT_NAME} )
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(app)
The lib1/CMakeLists.txt looks eg like (stripped):
SET(SOURCE
file.cpp
)
SET(HEADERS
some_lib_header.h
)
add_library( lib1 ${SOURCE} ${HEADERS} )
and the one for the app looks the same except of ADD_EXECUTABLE:
SET(SOURCE
main.cpp
)
SET(HEADERS
some_header.h
)
add_library( lib1 ${SOURCE} ${HEADERS} )
ADD_EXECUTABLE( app ${SOURCE} ${HEADERS} )
I found the setup working well this way because out of this, I can generate one Visual Studio solution file which contains all those three projects. But my problem is that my app includes header files of lib1 (and also of lib2, which depends on lib1). When I do
$mkdir build
$cd build
$cmake -C ..\myproject
it generates out-of-source VS .sln file as I want it, but the app doesn't compile because it can't find the header files of lib1 (obviously).
Now I read and tried many things, like TARGET_LINK_LIBRARIES( app lib1 ) (which got the app to link with the lib1, but not solve the header include issue), and things like add_subdirectory( ../lib1 ) in various variants in the CMakeLists.txt of app (which all throwed errors that I couldn't fix), and also find_package (which I guess is the wrong approach).
So how can I solve this (I guess simple...) problem?

Here's one possible solution:
Root CMakeLists.txt:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(${PROJECT_NAME})
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(app)
lib1/CMakeLists.txt:
project(Lib1)
add_library(lib1 lib1.cpp lib1.h)
lib2/CMakeLists.txt:
project(Lib2)
add_library(lib2 lib2.cpp lib2.h)
# Add /lib1 to #include search path
include_directories(${Lib1_SOURCE_DIR})
# Specify lib2's dependency on lib1
target_link_libraries(lib2 lib1)
app/CMakeLists.txt:
project(App)
add_executable(app main.cpp some_header.h)
# Add /lib1 and /lib2 to #include search path
include_directories(${Lib1_SOURCE_DIR} ${Lib2_SOURCE_DIR})
# Specify app's dependency on lib2.
# lib2's dependency on lib1 is automatically added.
target_link_libraries(app lib2)
There are plenty of different ways to achieve the same end result here. For a relatively small project, I'd probably just use a single CMakeLists.txt:
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(Test)
add_library(lib1 lib1/lib1.cpp lib1/lib1.h)
add_library(lib2 lib2/lib2.cpp lib2/lib2.h)
add_executable(app app/main.cpp app/some_header.h)
include_directories(${CMAKE_SOURCE_DIR}/lib1 ${CMAKE_SOURCE_DIR}/lib2)
target_link_libraries(lib2 lib1)
target_link_libraries(app lib2)
For further info on the relevant commands and their rationale, run:
cmake --help-command add_subdirectory
cmake --help-command include_directories
cmake --help-command target_link_libraries

Project
CMakeLists.txt
\-lib1
CMakeLists.txt
\- include \ lib1
\- src
\-lib2
CMakeLists.txt
\- include \ lib2
\- src
\-app
CMakeLists.txt
\- src
Suppose dependencies as follow:
lib1 ---> lib2 ---> app
\--------------> app
Something like this:
CMakeLists.txt:
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(app)
lib1/CMakeLists.txt:
file(GLOB_RECURSE _HDRS "include/*.hpp")
file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
add_library(lib1 ${_HDRS} ${_SRCS})
#target_link_libraries(lib1)
target_include_directories(lib1 PUBLIC include)
install(TARGETS lib1 DESTINATION lib)
install(FILES ${_HDRS} DESTINATION include/lib1)
lib2/CMakeLists.txt:
file(GLOB_RECURSE _HDRS "include/*.hpp")
file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
add_library(lib2 ${_HDRS} ${_SRCS})
target_link_libraries(lib2 lib1)
target_include_directories(lib2 PUBLIC include)
install(TARGETS lib2 DESTINATION lib)
install(FILES ${_HDRS} DESTINATION include/lib2)
so in lib2/src/file.cpp you could do #include <lib1/header.hpp>
app/CMakeLists.txt:
file(GLOB_RECURSE _SRCS "src/*.[hc]pp")
add_executable(app ${_SRCS})
target_link_libraries(app lib1 lib2)
install(TARGETS app DESTINATION bin)
so in app/src/file.cpp you could do #include <lib1/header.hpp> and #include <lib2/header.hpp>
The magic is target_include_directories which attach the "include" directory to the target, so when linking with it you pull the include directory also ;)

Related

CMake Library issue for header-only library [duplicate]

How to make a project in cmake that collects all c++ files into one header?
I have this project structure.
/
project/
folder1/
file.cpp
file.hpp
folder2/
...etc
CMakeLists.txt
tests/
test.cpp
CMakeLists.txt
CMakeList.txt
root cmakelists.txt
cmake_minimum_required (VERSION 3.8)
project ("CMakeProject"
LANGUAGES C CXX)
set(CMAKE_EXECUTABLE_SUFFIX ".exe")
include(GNUInstallDirs)
add_subdirectory ("project")
option(ENABLE_TESTING OFF)
if (ENABLE_TESTING)
enable_testing()
add_subdirectory("tests")
endif()
CMakeLists.txt in project
cmake_minimum_required (VERSION 3.8)
file(GLOB projectSRC
"*/*.cpp"
"*/*.hpp"
"*.cpp"
"*.hpp"
)
add_library(project INTERFACE)
message(STATUS "CMake inatall directory: " ${CMAKE_INSTALL_INCLUDEDIR})
target_include_directories(project
INTERFACE
$<BUILD_INTERFACE:${PROJECT_INCLUDE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
and test cmakelist.txt
cmake_minimum_required (VERSION 3.8)
# install Catch2 testing library
# (https://github.com/catchorg/Catch2/blob/master/docs/cmake-integration.md#installing-catch2-from-git-repository or use packet manager)
find_package(Catch2 REQUIRED)
file(GLOB testSRC
"*.cpp"
)
add_executable(tests ${testSRC})
target_link_libraries(tests
Catch2::Catch2
project)
include(CTest)
include(Catch)
catch_discover_tests(tests)
How to generate one header and use it (in tests or other projects) or make this library able to have templates? The first is better.
How to make a header-only library with cmake?
Like this:
add_library(project INTERFACE)
target_include_directories(project INTERFACE .)
Then in the target that uses the library:
target_link_libraries(dependee
PUBLIC/INTERFACE/PRIVATE # pick one
project)
and include the header like this:
#include <project/folder1/file.hpp>

How To Include External Libraries in CMake Project

I am confused on how to statically include the source code of SDL2. I am trying to do this to make a library I am working on more portable.
When I was setting this up as executable the library was compiled with it fine, but when I changed it to a library it wouldn't include the library.
Currently, when I try to include my library in another project it says "Cannot open include file: 'SDL2/SDL.h': No such file or directory". So it leads me to think that the cause of the error is that the include directories aren't exported with the static library.
My Filesystem:
include
--Header Files
src
--Source Files
extern
--SDL2
build
Here is an example of the file causing the error:
#include <iostream>
#include <SDL.h> //Error
using namespace std;
/* The code */
Here is an example of my main CMakeLists.txt:
cmake_minimum_required(VERSION 3.7)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
project(MyProject VERSION 1.0.0)
set(SDL2_SOURCE_DIR “${CMAKE_SOURCE_DIR}/extern/SDL2”)
add_subdirectory(extern/SDL2)
add_subdirectory(src)
Here is an example of my src CMakeLists.txt:
set(PROJECT_NAME MyProject)
file(GLOB HEADER_FILES "${CMAKE_SOURCE_DIR}/include/*.h")
file(GLOB SOURCES "*.cpp")
add_library(${PROJECT_NAME} ${SOURCES} ${HEADER_FILES})
target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_SOURCE_DIR}/include" PUBLIC "${CMAKE_SOURCE_DIR}/extern/SDL2/include")
target_link_libraries(${PROJECT_NAME} PRIVATE SDL2main SDL2-static)
set_target_properties( ${PROJECT_NAME}
PROPERTIES
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/lib"
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin"
)
From sdl2 CMakeLists.txt try:
set(SDL_STATIC 1)
add_subdirectory(extern/SDL2) # And I recommend EXCLUDE_FROM_ALL
Also to be sure add a check:
foreach(i IN ITEMS SDL2main SDL2-static)
if(NOT TARGET ${i})
message(FATAL_ERROR "${i} is not a target")
endif()
endif()
target_link_libraries(${PROJECT_NAME} PRIVATE SDL2main SDL2-static)

How to make a header-only library with cmake?

How to make a project in cmake that collects all c++ files into one header?
I have this project structure.
/
project/
folder1/
file.cpp
file.hpp
folder2/
...etc
CMakeLists.txt
tests/
test.cpp
CMakeLists.txt
CMakeList.txt
root cmakelists.txt
cmake_minimum_required (VERSION 3.8)
project ("CMakeProject"
LANGUAGES C CXX)
set(CMAKE_EXECUTABLE_SUFFIX ".exe")
include(GNUInstallDirs)
add_subdirectory ("project")
option(ENABLE_TESTING OFF)
if (ENABLE_TESTING)
enable_testing()
add_subdirectory("tests")
endif()
CMakeLists.txt in project
cmake_minimum_required (VERSION 3.8)
file(GLOB projectSRC
"*/*.cpp"
"*/*.hpp"
"*.cpp"
"*.hpp"
)
add_library(project INTERFACE)
message(STATUS "CMake inatall directory: " ${CMAKE_INSTALL_INCLUDEDIR})
target_include_directories(project
INTERFACE
$<BUILD_INTERFACE:${PROJECT_INCLUDE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
and test cmakelist.txt
cmake_minimum_required (VERSION 3.8)
# install Catch2 testing library
# (https://github.com/catchorg/Catch2/blob/master/docs/cmake-integration.md#installing-catch2-from-git-repository or use packet manager)
find_package(Catch2 REQUIRED)
file(GLOB testSRC
"*.cpp"
)
add_executable(tests ${testSRC})
target_link_libraries(tests
Catch2::Catch2
project)
include(CTest)
include(Catch)
catch_discover_tests(tests)
How to generate one header and use it (in tests or other projects) or make this library able to have templates? The first is better.
How to make a header-only library with cmake?
Like this:
add_library(project INTERFACE)
target_include_directories(project INTERFACE .)
Then in the target that uses the library:
target_link_libraries(dependee
PUBLIC/INTERFACE/PRIVATE # pick one
project)
and include the header like this:
#include <project/folder1/file.hpp>

CMake can't find include file from subfolder

I want to add to my CMake project some subfolder which contains some additional functionality. MyProject is a shared library. Ideally it will be fine to just include files from subfolder and to compile all them together. But so far I've found a way only to include that as a static library that suits me too. So my files structure should look like the following:
MyProject
src
main.cpp
include
main.h
CMakeLists.txt
3dparty
SomeFolder
src
file.cpp
include
file.h
CMakeLists.txt
MyProject/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(MyProject)
file(GLOB SRC . src/*.cpp)
file(GLOB INC . include/*.h)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin)
add_library(${PROJECT_NAME} SHARED ${SRC} ${INC})
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
add_subdirectory(3dparty/SomeFolder)
and 3dparty/SomeFolder/CMakeLists.txt:
project (SomeFolder)
file(GLOB SRC . src/*.cpp)
file(GLOB INC . include/*.h)
add_library(${PROJECT_NAME} STATIC ${SRC} ${INC})
target_include_directories(${PROJECT_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
I can compile the project and I see that compiler produses SomeFolder.a so it looks good. But for some reason I can't include files from 3dparty/SomeFolder/include in main.*. So far I've tried:
#include "file.h"
#include "3dparty/SomeFolder/file.h"
but nothing works. I get error: 'file.h' file not found.
What I did wrong? How can I include files from subproject?
Because you forgot to link the sublibrary to your main library. Usr target_link_libraries()

cmake only sub directories based library

I am trying to figure out to create a small cmake file. The directory struture includes 4 sub folders and which has src and header files. There is no src or header file at root. All I want is to create a Shared library using cmake by compiling these four folders.
CMakeLists.txt at root
cmake_minimum_required (VERSION 2.8.7)
Project(NEWPROJ)
set(${PROJECT_NAME}_MAJOR_VERSION 00)
set(${PROJECT_NAME}_MINOR_VERSION 01)
set(${PROJECT_NAME} 0)
set(${PROJECT_NAME}_VERSION
${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION})
set(${PROJECT_NAME}_SOVERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION})
Message ( Root )
include_directories("${PROJECT_SOURCE_DIR}/Folder1/include")
include_directories("${PROJECT_SOURCE_DIR}/Folder2/include")
include_directories("${PROJECT_SOURCE_DIR}/Folder3/include")
include_directories("${PROJECT_SOURCE_DIR}/Folder4/include")
add_subdirectory ("${PROJECT_SOURCE_DIR}/Folder1")
add_subdirectory ("${PROJECT_SOURCE_DIR}/Folder2")
add_subdirectory ("${PROJECT_SOURCE_DIR}/Folder3")
add_subdirectory ("${PROJECT_SOURCE_DIR}/Folder4")
add_library( ${PROJECT_NAME} SHARED ${SOURCE} ${HEADERS})
CMakeLists.txt in Folder1
MESSAGE(Folder1)
set(SOURCE
${SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/src/file1.cc
${CMAKE_CURRENT_SOURCE_DIR}/src/file2.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/file3.cc
PARENT_SCOPE
)
set(HEADERS
${HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/include/file1.h
${CMAKE_CURRENT_SOURCE_DIR}/include/file2.h
${CMAKE_CURRENT_SOURCE_DIR}/include/file3.h
${CMAKE_CURRENT_SOURCE_DIR}/include/file4.h
PARENT_SCOPE
)
cmake .. successful
make folder1/src/file1.cc:1:20: fatal error: file1.h: No such file or directory
file1.cc
#include "file1.h"
...