Linking two libraries together with CMake - c++

File Structure:
CMakeLists.txt
src/
evolution.cpp
evolution.h
main.cpp
helpers/
disposable.h
engine/
game.h
game.cpp
CMakeLists.txt:
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers
src/helpers/disposable.h)
set_target_properties(helpers PROPERTIES LINKER_LANGUAGE CXX)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)
The Game class (game.h) inherits from Diposable (disposable.h), but I am unable to build the project with a simple #include "disposable.h" in the game.h file.
How do I configure CMake so that the engine library can see the helpers library?
CMake error:
[ 20%] Building CXX object CMakeFiles/engine.dir/src/engine/game.cpp.o
In file included from /home/shane/projects/evolution/src/engine/game.cpp:1:
/home/shane/projects/evolution/src/engine/game.h:4:10: fatal error: disposable.h: No such file or directory
4 | #include "disposable.h"
| ^~~~~~~~~~~~~~
compilation terminated.

Adding headers to a project really only helps IDEs find the headers. It doesn't change the build instructions. Instead you need to use target_include_directories() with a INTERFACE or PUBLIC section to get any libraries that link to this to add the include directories to itself.
Your helpers library is more of an interface for now. To get this minimum example working do this:
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers INTERFACE) # INTERFACE is good for header-only libraries
target_include_directories(helpers INTERFACE src/helpers)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)
Now include with angular brackets: #include <disposable.h>
If your library becomes more complicated (more than just header files), then replace INTERFACE in add_library with your sources. To make include directories available to the helpers library and any library that links to it, change INTERFACE to PUBLIC in target_include_directories.
cmake_minimum_required(VERSION 3.17)
project(evolution)
add_library(helpers src/helpers/helper.cpp)
target_include_directories(helpers PUBLIC src/helpers)
add_library(engine
src/engine/game.h
src/engine/game.cpp)
add_executable(evolution src/main.cpp)
target_link_libraries(evolution engine helpers)

Related

Require including <mylibrary/mylibrary.h> instead of <mylibrary.h> inside Cmake project that links to mylibrary

I have a very simple c++ shared library with a CMakeLists.txt file:
cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 23)
project(mylibrary)
add_library (mylibrary src/mylibrary.h src/mylibrary.cpp)
target_include_directories(mylibrary PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src)
Now in the project that uses this library I link to this library with target_link_libraries(myapp mylibrary) and then I can include the library with #include <mylibrary.h>. However, to visually separate all library includes I want to (have to) use #include <mylibrary/mylibrary.h>, even though mylibrary.h is not inside a folder called mylibrary. Is there a way to achieve this with Cmake?

CMake: Unable to include external library header files in my library's header files that are not included in any source files

I've tried looking for an answer to this question. There are similar questions but none that answer mine.
I am trying to create a library that depends on a couple other external libraries. I have the external libraries as git submodules and compile them myself in CMake using add_subdirectory followed by target_link_library.
After doing that, I am able to use the external libraries and include their header files in any source file in my library that I have added using target_sources and also in any header file that at least one of these source files include.
For example, I have an external library glm and call target_sources(myLib PRIVATE Application.cpp) in my library. The header files in my library are added to the project using target_include_directories.
Now, I can do #include <glm/glm.hpp> in the Application.cpp file with no problems.
I also have an Application.hpp file that is included in the Application.cpp file. Because it is included, that allows me to do #include <glm/glm.hpp> in the Application.hpp file as well.
However, now I also have a Core.hpp file without a corresponding Core.cpp file. Because the Core.hpp file is not included in any source files, doing #include <glm/glm.hpp> throws an error that the file cannot be found.
This is my root CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(Ivory)
set(CMAKE_CXX_STANDARD 20)
add_library(${PROJECT_NAME} SHARED)
# Determine compiler platform (x32 or x64)
math(EXPR PLATFORM_BITS "8*${CMAKE_SIZEOF_VOID_P}")
set(PLATFORM "x${PLATFORM_BITS}")
# Determine target build platform
target_compile_definitions(${PROJECT_NAME}
PUBLIC
IVORY_WINDOWS
PRIVATE
IVORY_BUILD_DLL
)
# Set output directory
set(OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${CMAKE_SYSTEM_NAME}-${CMAKE_BUILD_TYPE}-${PLATFORM})
# Subdirectories
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(executables)
target_include_directories(${PROJECT_NAME} PUBLIC include)
# External Libraries #
set(BUILD_SHARED_LIBS OFF)
# GLM
add_subdirectory(lib/glm)
target_link_libraries(${PROJECT_NAME} PRIVATE glm)
# GLEW
add_subdirectory(lib/glew)
target_link_libraries(${PROJECT_NAME} PRIVATE libglew_static)
# SFML
add_subdirectory(lib/SFML)
target_link_libraries(${PROJECT_NAME} PRIVATE sfml-window sfml-audio)
# SPDLOG
add_subdirectory(lib/spdlog)
target_link_libraries(${PROJECT_NAME} PRIVATE spdlog)
# MinGW
target_link_libraries(${PROJECT_NAME} PRIVATE -static)
# Output Location
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY})
This is the src CMakeLists.txt:
target_sources(${PROJECT_NAME}
PRIVATE
Application.cpp
)
I am using CLion on Windows 10 with MinGW 7.3 compiler (64 bit).
What am I doing wrong?
If the Core.hpp header is meant to be included by clients and glm headers are called from this header the glm dependency in the target_link_libraries command must be PUBLIC not PRIVATE.
For the CMake documentation see here. For a more detailed explanation of the PUBLIC, PRIVATE, and INTERFACE keywords with examples see here.

Cmake Cannot specify include directories when use target target_include_directories

I'm using the submodule GitHub inside my project and now I want to use the target_include_directories for including the file inside the my project class
This is my cmake configuration
cmake_minimum_required(VERSION 3.9)
project(SpyCBlock)
set(CMAKE_CXX_STANDARD 14)
#bitcoin rpc lib
find_library(bitcoinapi 0.3 REQUIRED)
target_include_directories(rapidjson PUBLIC include/rapidjson/include)
target_include_directories(spycblockrpc PUBLIC include/spycblockrpc)
target_include_directories(btccryptography PUBLIC include/bitcoin-cryptography-library)
add_executable(
${PROJECT_NAME}
#other inclusion file cpp
#cpp-properties file include
include/cpp-properties/src/Properties.cpp
include/cpp-properties/src/PropertiesParser.cpp
include/cpp-properties/src/PropertiesUtils.cpp
#include bitcoin-cryptography-library
include/bitcoin-cryptography-library/cpp/Sha256.cpp
include/bitcoin-cryptography-library/cpp/Sha256Hash.cpp
include/bitcoin-cryptography-library/cpp/Utils.cpp
#include spycblocrpc
include/spycblockrpc/core/graph/TransactionGraph.cpp
include/spycblockrpc/core/graph/WrapperInformations.cpp
include/spycblockrpc/ConfiguratorSingleton.cpp
include/spycblockrpc/commands/DecodeScriptCommand.cpp
include/spycblockrpc/commands/DecodeRawTransaction.cpp
include/spycblockrpc/commands/HeightBlockchainCommand.cpp
include/spycblockrpc/commands/DecodeBlockAtIndexCommand.cpp
)
#bitcoin rpc lib
target_link_libraries(SpyCBlockTests bitcoinapi)
target_link_libraries(${PROJECT_NAME} bitcoinapi)
When run CMake I have this error
Starting to parse CMake project.
CMake Error at CMakeLists.txt:20 (target_include_directories):
Cannot specify include directories for target "rapidjson" which is not
built by this project.
CMake Error at CMakeLists.txt:22 (target_include_directories):
Cannot specify include directories for target "spycblockrpc" which is not
built by this project.
CMake Error at CMakeLists.txt:24 (target_include_directories):
Cannot specify include directories for target "btccryptography" which is
not built by this project.
CMake Error at CMakeLists.txt:26 (target_compile_definitions):
Cannot specify compile definitions for target "cppproperties" which is not
built by this project.
I'm new with the C++ and the cmake and I can't understand what I'm wrong
I want to add the solution to this problem, as suggested in the comments, the code has two problems:
target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/include/rapidjson/include)
The first argument of the target must be the name of the executable, so in this case, is SpyCBlock
The second problem is the definition of the target before the declaration of the target, the target_include_directories(SpyCBlock ...) is defined before the add_executable(${PROJECT_NAME} ...)
A minimal correct example is:
add_executable(
${PROJECT_NAME}
#other inclusion file cpp
#cpp-properties file include
include/cpp-properties/src/Properties.cpp
include/cpp-properties/src/PropertiesParser.cpp
include/cpp-properties/src/PropertiesUtils.cpp
#include bitcoin-cryptography-library
include/bitcoin-cryptography-library/cpp/Sha256.cpp
include/bitcoin-cryptography-library/cpp/Sha256Hash.cpp
include/bitcoin-cryptography-library/cpp/Utils.cpp
#include spycblocrpc
include/spycblockrpc/core/graph/TransactionGraph.cpp
include/spycblockrpc/core/graph/WrapperInformations.cpp
include/spycblockrpc/ConfiguratorSingleton.cpp
include/spycblockrpc/commands/DecodeScriptCommand.cpp
include/spycblockrpc/commands/DecodeRawTransaction.cpp
include/spycblockrpc/commands/HeightBlockchainCommand.cpp
include/spycblockrpc/commands/DecodeBlockAtIndexCommand.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/include/rapidjson/include)
Now I can include the library like this <bitcoin-cryptography-library/Sha256.h>.

CMAKE library / application structure

I have the following project structure:
root/
CMakeLists.txt
src/
CMakeLists.txt
engine/
CMakeLists.txt
*.h
*.cpp
console/
CMakeLists.txt
*.h
*.cpp
Now in src/engine/CMakeLists.txt I call add_library(engine ${SOURCES}) and it works out fine, compiles and everything. Now over in console, I would like my includes to the engine be #include "engine/foo.h" and not just #include "foo.h".
Now the question is, are there any elegant way to add the includes so I have to prepend engine to my includes in the console project?
Currently what I do is have the following in src/console/CMakeLists.txt:
add_executable(console ${SOURCES})
target_include_directories(console PUBLIC ${lib_incl_path})
target_link_libraries(console PRIVATE engine)
and then define set(lib_incl_path ${CMAKE_CURRENT_SOURCE_DIR}) in src/CMakeLists.txt. But that seems overkill (and hacky), to add the entire src folder to the includes.
The answer is to use
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/..)
See CMake how to correctly create dependencies between targets

Nested CMake projects multiple definition error when adding header-only library

I have a C++ library organized like:
Library/
CMakeLists.txt
main.cpp
src/
file1.cpp
include/
file1.h
Domains/
CMakeLists.txt
BlackJack/
CMakeLists.txt
src/
foo1.cpp
include/
foo1.h
...
libs/
tapkee/
CMakeLists.txt
include/
foo.hpp
....
Each library(i.e. Domains) contains linking and simple code for organizational purposes:
project(Domains)
cmake_minimum_required(VERSION 2.8)
add_subdirectory(IDomain)
add_subdirectory(Blackjack)
add_library(Domains STATIC)
target_link_libraries(Domains IDomain BLACKJACK)
Each sub-library (i.e. Blackjack) has a really simple CMakeLists.txt that just compiles the library (add_library).
This has been working just fine, until now.
I'm adding a third-party library (http://tapkee.lisitsyn.me/). This is a header-only library. It looks like CMake doesn't support this, but I found some work-arounds. I create a empty dummy.cpp file. Here is the CMakeLists for the third-party library:
project (TAPKEE)
file(GLOB TAPKEE_INCLUDE
"include/tapkee/*.hpp"
"include/tapkee/callbacks/*.hpp"
"include/tapkee/defines/*.hpp"
"include/tapkee/external/*.hpp"
"include/tapkee/neighbors/*.hpp"
"include/tapkee/parameters/*.hpp"
"include/tapkee/routines/*.hpp"
"include/tapkee/traits/*.hpp"
"include/tapkee/utils/*.hpp"
)
add_library(${PROJECT_NAME} header_only_BS.cpp ${TAPKEE_INCLUDE})
Here is the weird thing: My main.cpp and anything in the root src directory can include this tapkee library just fine, but none of the sub-libraries can (i.e. BlackJack). I get thousands of redefinition linker errors for the functions within tapkee.
Here is an example of the top-level CMakeLists:
project(ManifoldLearning)
#Root
set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
#Domains
set(BLACKJACK_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Domains/Blackjack/include)
set(TAPKEE_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libs/tapkee/include/)
include_directories(${INCLUDE_DIR} ${SRC_DIR})
include_directories(${TAPKEE_INCLUDE_DIR})
include_directories(${BLACKJACK_INCLUDE_DIR})
add_subdirectory(Domains)
#add_subdirectory(libs/tapkee)
add_executable(${PROJECT_NAME} ${SRC_LIST} ${HEADER_LIST})
target_link_libraries(${PROJECT_NAME} Domains)
I've been stuck on this for days, and any help/advice would be appreciated.
Update: I've removed the inclusion of the tapkee CMakeLists.txt (add_subdirectory) as per Antonio's direction. I still get redefinition errors, which I find strange. It's now not compiled anywhere and only included in BlackJack/src/foo1.cpp