How to Create Packages with CMake - c++

.
+-- MyPack
| +-- Lib1
| | +-- include
| | | +-- Lib1.h
| | +-- src
| | | +-- Lib2.cpp
| | +-- CMakeLists.txt
| +-- Lib2
| | +-- include
| | | +-- Lib2.h
| | +-- src
| | | +-- Lib2.cpp
| | +-- CMakeLists.txt
| +-- CMakeLists.txt
+-- SubProject1
| +-- CMakeLists.txt
+-- SubProject2
| +-- CMakeLists.txt
+-- CMakeLists.txt
Hi all.
I'm new to CMake and I'm trying to obtain something like the following.
Considering the above directory tree of my C++ project:
I have a directory (let's say "MyPack") that contains several subdirectories (Lib1, Lib2...) and each one represents a C++ Library that I wrote.
How can I setup everything so I can write find_package(MyPack)in the other subprojects?
Every subproject is a stand-alone project, and does not depend on other subprojects, but just on libraries in "MyPack".

Your drawing is a bit confusing because there is a CMakeLists.txt after Lib2 which belongs to no folder...
Anyway : is MyPack
Lib1 and Lib2 ?
Lib1/Lib2/Subproj1/Subproj2 ?
in the 2nd case :
The top directory CMakeLists.txt gives you access to targets of Lib1 and Lib2 that you can use in SubProject1 and SubProject2 if you have something like this :
project(MyPack)
add_subdirectory(Lib1) # Building Lib1
add_subdirectory(Lib2) # Building Lib2
add_subdirectory(SubProject1) # you can use Lib1 & Lib2 targets here
add_subdirectory(SubProject2) # you can use Lib1 & Lib2 targets here
If it is the 1st case, MyPack is only Lib1 and Lib2 :
Using find_package(MyPack) means that you need to create a Config file and install() your project:
project(MyPack)
add_subdirectory(Lib1)
add_subdirectory(Lib2)
in Lib1/CMakeLists.txt :
add_library(lib1 "")
add_library(MyPack::lib1 ALIAS lib1)
[...]
include(GNUInstallDirs)
install(
TARGET lib1
EXPORT MyPackTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
in Lib2/CMakeLists.txt :
add_library(lib2 "")
add_library(MyPack::lib2 ALIAS lib2)
[...]
include(GNUInstallDirs)
install(
TARGET lib2
EXPORT MyPackTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
Now you have lib1 and lib2 in the export MyPackTargets. You have to install that export as well.
anywhere after above :
install(
EXPORT MyPackTargets
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyPack
NAMESPACE MyPack::
FILE MyPackTargets.cmake # Not sure if this is still needed
)
include(CMakePackageConfigHelpers)
configure_package_config_file(
"Config.cmake.in"
"MyPackConfig.cmake"
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyPack
PATH_VARS
CMAKE_INSTALL_LIBDIR
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/MyPackConfigVersion.cmake
VERSION 1.0.0
COMPATIBILITY SameMajorVersion
)
### Install Config and ConfigVersion files
install(
FILES "${CMAKE_CURRENT_BINARY_DIR}/MyPackConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/MyPackConfigVersion.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/MyPack"
)
create a file Config.cmake.in with :
#PACKAGE_INIT#
include( "${CMAKE_CURRENT_LIST_DIR}/MyPackTargets.cmake" )
Now if you build and install your project MyPack, find_package(MyPack) from other project should find it and import the targets you've created.
Here is some documentation :
https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html
https://blog.kitware.com/cmake-superbuilds-git-submodules/
Hope that helps

Related

Building with CMake adds prefix "OFF" to the tests. How to get rid of that?

I have a CMake project with following structure:
project
|- src
| |- plugins
| | |- class1
| | | |- class1.hpp
| | | |- class1.cpp
| | | |- CMakeLists.txt
| | |- class2
| | |- class2.hpp
| | |- class2.cpp
| | |- CMakeLists.txt
| |- tests
| |- CMakeLists.txt
| |- test_1
| | |- test.cpp
| | |- CMakeLists.txt
| |- test_2
| |- test.cpp
| |- CMakeLists.txt
|- CMakeLists.txt
The contents of the CMakeLists is as follows:
project/CMakeLists:
cmake_minimum_required (VERSION 3.7)
project(project-name)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
add_subdirectory(src/plugins/class1)
add_subdirectory(src/plugins/class2)
## Tests
option(CMAKE_BUILD_TESTS "Build tests" ON)
if(CMAKE_BUILD_TESTS)
enable_testing()
add_subdirectory(src/tests)
endif()
project/src/plugins/class1/CMakeLists.txt (similarly for class2):
project(plugin_1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
add_library(class1 SHARED class1.cpp class1.hpp)
target_compile_options(class1 PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall>)
install(TARGETS class1
COMPONENT bin
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
project/src/tests/CMakeLists.txt:
cmake_minimum_required (VERSION 3.7)
project(unit-tests)
add_subdirectory(test_1)
add_test(NAME test_1 COMMAND test_1)
add_subdirectory(test_2)
add_test(NAME test_2 COMMAND test_2)
project/src/tests/test_1/CMakeLists.txt (similarly for test_2):
cmake_minimum_required (VERSION 3.7)
project(test_1)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include_directories(${CMAKE_SOURCE_DIR}/src/plugins/class1)
add_executable(test_1 test.cpp)
target_compile_definitions(test_1 PUBLIC UNIT_TESTS)
target_link_libraries(test_1 class1)
install(TARGETS test_1
COMPONENT bin
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
I am building the project as follows:
$ mkdir build && cd build
$ cmake -DCMAKE_BUILD_TESTS=ON ..
$ make && make install
Question:
Whilst building the project, it builds the tests as: OFFtest_1 and OFFtest_2. How to get rid if the 'OFF' prefix? Where is it coming from?

Create CMakeLists library with subdirectory sources

project
|
|----- src <-- Needs to be a library
| |
| |--- dir1 <-- Need not create a library
| | |--- dir1_1.cpp
| | |--- dir1_2.cpp
| | |--- CMakeLists.txt
| |
| |
| | --- dir2 <-- has an executable for testing and needs to be a library
| | |--- dir2.cpp
| | |--- dir2.h
| | |--- CMakeLists.txt
| |
| |
| | --- CMakeLists.txt
|
|
|
|----- CMakeLists.txt
How do I create CMakeLists in src such that it includes files from dir1 and dir2, such that only dir2 is a sub-project. I want to use add_subdirectory in src/CMakeLists.txt to add source files from dir1 and dir2. This way it will be easier to add more folders in the future.
I saw the use of PARENT_SCOPE but it also has some drawbacks. Is there a better solution? Maybe by using target_sources or something?
First of all, you should reconsider not making those subdirs self-contained modules, as modularity helps keep your projects cleaned.
Having said that, you can include in any variable defined in ./src/CMakeLists.txt any variable that's defined by ./src/dir1/CMakeLists.txt or ./src/dir2/CMakeLists.txt. Here's an example:
Here are the contents of ./src/dir1/CMakeLists.txt:
set(dir1_SOURCES
dir1/dir1_1.cpp
dir1/dir1_2.cpp
)
Here are the contents of ./src/CMakeLists.txt:
add_subdirectory(dir1)
set(src_SOURCES
${dir1_SOURCES}
)
You can create a library, then later add its source files in a subdirectory using target_sources. This gives you the flexibility to add more sources to MyLib or add more sub-projects later on, via additional calls to add_subdirectory.
It might look something like this:
src/CMakeLists.txt:
# Create a library
add_library(MyLib SHARED)
# Traverse to the 'dir1' subdirectory to populate the sources for MyLib.
add_subdirectory(dir1)
# Traverse to 'dir2' to create a sub-project.
add_subdirectory(dir2)
dir1/src/CMakeLists.txt:
target_sources(MyLib PUBLIC
dir1_1.cpp
dir1_2.cpp
)
# Add any headers from this directory.
target_include_directories(MyLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
dir2/src/CMakeLists.txt:
project(MySubProject)
add_library(MyLib2 SHARED
dir2.cpp
)
# Add any headers from this directory.
target_include_directories(MyLib2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
add_executable(MyExe ...)
...

Some headers-only files in my project cannot include "SFML/Graphics.hpp" using CMake and Vscode

I'm new to C++ and CMake and started a big project. Im using VScode as my text editor and CMake as my build tool.
The problem is that i can include "SFML/Graphics.hpp in all my header files that has a source file with the same name, but in header-only files if i include "SFML/Graphics.hpp" or any other file that include "SFML/Graphics" cmake won't build and returns an error.
Here's is my code
Project Directory Tree
Game|> (root)
|- CMakeLists.txt
|> include
| |- BaseComponent.hpp (Header-only)
| |- TransformComponent.hpp (Header-only)
| |- CombatComponent.hpp (Header-only)
| |- MovementComponent.hpp (Header-only)
| |- Constants.hpp (Header-only)
| |- TimeUtils.hpp (Header-only)
| |- EcsManager.hpp
| |- EntityManager.hpp
| |- Game.hpp
| |- GameContext.hpp (Header-only)
| |- Scene.hpp (Header-only)
| |- GameScene.hpp
| |- System.hpp
| |- Input.hpp
| |- MovementSystem.hpp
| |- RenderableSystem.hpp
|> src
| |- CMakeLists.txt
| |- main.cpp
| |- Game.cpp
| |- EntityManager.cpp
| |- SceneManager.cpp
| |- Input.cpp
| |- GameScene.cpp
| |> Ecs
| |- CMakeLists.txt
| |- EcsManager.cpp
| |- System.cpp
| |> Systems
| |- CMakeLists.txt
| |- MovementSystem.cpp
| |- RenderableSystem.cpp
|
|> bin
|> build
CMakeLists.txt - Root
project(RPG)
set(CMAKE_TOOLCHAIN_FILE
"C:/Users/dante/vcpkg/scripts/buildsystems/vcpkg.cmake")
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/bin")
set(SOURCES src/EntityManager.cpp src/Game.cpp src/GameScene.cpp
src/main.cpp src/SceneManager.cpp src/Input.cpp)
include_directories("${PROJECT_SOURCE_DIR}/include")
add_subdirectory(src)
find_package(SFML 2.5.1 COMPONENTS REQUIRED graphics window system network
audio)
find_package(nlohmann_json 3.2.0 REQUIRED)
add_executable(RPG ${SOURCES})
target_link_libraries(RPG sfml-graphics sfml-window sfml-system sfml-
network sfml-audio)
target_link_libraries(RPG nlohmann_json::nlohmann_json)
target_link_libraries(RPG ECS)
CMakeLists.txt - src
add_subdirectory(Ecs)
CMakeLists.txt - Ecs
add_subdirectory(Systems)
add_library(ECS EcsManager.cpp System.cpp )
target_link_libraries(ECS ECS_SYSTEMS)
CMakeLists.txt - Systems
add_library(ECS_SYSTEMS MovementSystem.cpp RenderableSystem.cpp)
The erro that Cmake outputs is : 'SFML/Graphics.hpp': No such file or directory MSVC(C1083)
If i include "SFML/Graphics.hpp" in any "Any"Component Class it gives error
If i include "SFML/Graphics.hpp" in a .hpp file that have a .cpp file associated with it and include that class in "Any"Component Class (or any other header-only) it gives error.
I can't find any solution to that in stackoverflow.
Don't judge my folder structure it was different when the error first came up... than i changed to that to see if the CMake would build.
You need to add the SFML include directory to the list of include directories.
After
find_package(SFML 2.5.1 COMPONENTS REQUIRED graphics window system network audio)
add the line
include_directories(${SFML_INCLUDE_DIR})

CMake: Why is an added_subdirectory not visible to other subdirectories

I have the following project structure:
project
- CMakeLists.txt
- src
- LibA
- CMakeLists.txt
- LibB
- CMakeLists.txt
The root CMakeLists.txt looks kind of like this:
add_subdirectory(LibA)
add_subdirectory(LibB)
add_executable(foo src/main.cpp)
target_link_libraries(foo LibA LibB)
However, LibB actually wants to use some functionality from LibA as well. However, I cannot access LibA from within LibB. But I can't add it as a subdirectory either. This is a real problem for me. How can I best solve it?
Thanks in advance.
The solution is a bit complex to tell, but I wish to explain it in a simplified way...
The project structure should be:
/src
|
+-- /lib-a
| +-- /includes
| +-- /sources
| +-- LibAConfig.cmake
| \-- CMakeLists.txt
+-- /lib-b
| +-- /includes
| +-- /sources
| +-- LibBConfig.cmake
| \-- CMakeLists.txt
\-- /main
| +-- /includes
| +-- /sources
| \-- CMakeLists.txt
\-- CMakeLists.txt
/src/lib-a/LibAConfig.cmake should be:
# Debug
MESSAGE ("-- Library A configuration...")
# Headers
include_directories(${CMAKE_CURRENT_LIST_DIR}/includes)
/src/lib-a/CMakeLists.txt should be:
# Define project
project(LibA CXX)
# Debug
message("-- Working on \"${CMAKE_CURRENT_SOURCE_DIR}\"...")
# Package registration
set(LibA_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "")
# Project files
include_directories(includes)
file(GLOB _SOURCES sources/*.cpp)
# Go on with your module setup...
/src/lib-b/LibBConfig.cmake should be:
# Debug
MESSAGE ("-- Library B configuration...")
# Headers
include_directories(${CMAKE_CURRENT_LIST_DIR}/includes)
/src/lib-b/CMakeLists.txt should be:
# Define project
project(LibB CXX)
# Debug
message("-- Working on \"${CMAKE_CURRENT_SOURCE_DIR}\"...")
# Package registration
set(LibB_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "")
# Project files
include_directories(includes)
file(GLOB _SOURCES sources/*.cpp)
# Reference/Link to LIB-A
find_package(LibA)
# Go on with your module setup...
/src/main/CMakeLists.txt should be:
# Define project
project(MainApp CXX)
# Debug
message("-- Working on \"${CMAKE_CURRENT_SOURCE_DIR}\"...")
# Project files
include_directories(includes)
file(GLOB _SOURCES sources/*.cpp)
# Reference/Link to LIB-A and LIB-B
find_package(LibA)
find_package(LibB)
# Go on with your module setup...
/src/CMakeLists.txt should be:
# Define project
project(MyProject CXX)
# Debug
message("-- Working on \"${CMAKE_CURRENT_SOURCE_DIR}\"...")
add_subdirectory(lib-a)
add_subdirectory(lib-b)
add_subdirectory(main)
# Go on with your module setup...
I have taken the above example from a project of mine...

CMake with include and source paths - basic setup

I'm trying to set up a test project looking like my own project just to get things working first and it looks like this:
/MainProject/inc/main.h
/MainProject/src/main.cpp
/LibProject/inc/test.h
/LibProject/src/test.cpp
I've found some tutorials, but I cant find out how to set up this when I have the inc and src folder? How would the CMakeLists.txt files look? Would I have one in /, one in each of the project folders? It seems like I dont need to have one in the inc and src folders?
You need a CMakeLists.txt for each source subdirectory. Your structure should look something like this:
root
|-MainProject
| |-inc
| | '-main.h
| |-src
| | |-main.cpp
| | '-CMakeLists.txt
| '-CMakeLists.txt
|-LibProject
| |-inc
| | '-test.h
| |-src
| | |-test.cpp
| | '-CMakeLists.txt
| '-CMakeLists.txt
'-CMakeLists.txt
Content of root/CMakeLists.txt:
project(MyProject)
add_subdirectory(MainProject)
add_subdirectory(LibProject)
Content of LibProject/CMakeLists.txt and MainProject/CMakeLists.txt:
add_subdirectory(src)
Content of LibProject/src/CMakeLists.txt:
# Notice name prefix of this variable, set by CMake according
# to value given with "project()" in the root CMakeLists.txt.
include_directories(${MyProject_SOURCE_DIR}/LibProject/inc)
add_library(LibProject test.cpp)
Content of MainProject/src/CMakeLists.txt:
include_directories(${MyProject_SOURCE_DIR}/MainProject/inc)
# I assume you want to use LibProject as a library in MainProject.
include_directories(${MyProject_SOURCE_DIR}/LibProject/inc)
link_directories(${MyProject_SOURCE_DIR}/LibProject/src)
add_executable(MainProject main.cpp)
target_link_libraries(MainProject LibProject)
Then configure and build with:
$ cd root
$ mkdir build
$ cd build
$ cmake ..
$ make
You could do it like following.
CMakeLists.txt in your MainProject directory:
project(MainProject)
add_subdirectory(LibProject/src)
add_subdirectory(MainProject/src)
CMakeLists.txt in your LibProject/src directory:
include_directories(${PROJECT_SOURCE_DIR}/LibProject/inc/)
add_library(LibProject test.cpp)
CMakeLists.txt in your MainProject/src directory:
include_directories(${PROJECT_SOURCE_DIR}/MainProject/inc/)
add_executable(MainProject main.cpp)
target_link_libraries(MainProject LibProject)
In my case I wanted to do it with a single CMakeList. And it worked for me. I add my solution in case it serves to anyone.
This is what I did in my case:
My structure:
Project
|CMakeLists.txt
|-src
| |*.cpp
| |*.c
|-include
| |*.hpp
| |*.h
My CMakeLists.txt have to main parts:
include_directories(
${PROJECT_SOURCE_DIR}/include
${PROJECT_SOURCE_DIR}/src
)
^ Enables .cpp files to add headers in the include folder.
file(GLOB all_SRCS
"${PROJECT_SOURCE_DIR}/include/*.h"
"${PROJECT_SOURCE_DIR}/include/*.hpp"
"${PROJECT_SOURCE_DIR}/src/*.cpp"
"${PROJECT_SOURCE_DIR}/src/*.c"
)
^ Just add whatever is in those folders.
add_executable(MyTarget ${all_SRCS})
^ Build the target from the list of all sources
PS: if you want to see the full CMakeLists.txt go the the project link NEGU93/ForbiddenDesert.