I have a folder structure that is as follows:
|-CMakeLists.txt
|-main.cpp
|-network
---------- CMakeLists.txt
---------- network.h
---------- network.cpp
Where network is a folder containing the last 3 items.
I'm struggling to build this in CMake because the documentation is very strange to me. In my root CMakeLists.txt, it's as follows:
cmake_minimum_required(VERSION 3.11.0)
project(Test)
set(CMAKE_CXX_STANDARD 11)
include_directories ("${PROJECT_SOURCE_DIR}/network")
add_subdirectory (${PROJECT_SOURCE_DIR}/network)
add_executable(server main.cpp)
target_link_libraries (network)
find_package(Boost 1.67 REQUIRED COMPONENTS thread)
# Check for libray, if found print message, include dirs and link libraries.
if(Boost_FOUND)
message("Boost Found")
include_directories(${Boost_INCLUDE_DIRS})
target_link_libraries(server ${Boost_LIBRARIES})
target_link_libraries(server Boost::thread)
elseif(NOT Boost_FOUND)
error("Boost Not Found")
endif()
In the CMakeLists.txt in the network folder it's as follows:
cmake_minimum_required(VERSION 3.11.0)
project(Test)
set(CMAKE_CXX_STANDARD 11)
install(FILES ${MY_HEADER_FILES} DESTINATION ./)
add_executable(network network.cpp)
I made that by myself playing around to see if I can get CMake to add the files in that folder into the root project. Obviously, this is all just failing because I'm struggling to understand CMake from the documentation. My apologies. I get an error due to the implementation in "network.cpp" not being recognized:
main.cpp:(.text+0x409): undefined reference to `Socket::GetThis()'
I'm certain there's nothing wrong with the implementation because it's worked using another round about method but I want to build my project using the previous structure but I can't get my head around how to make the root CMakeLists and the network CMakeLists so that they work together.
How do I design the CMakeLists so that the network header and implementation are included in the root project. Also, the network library will be using Boost as well. Should I find the package in there too?
target_link_libraries (network)
You want to link "server" executable with "network" library. It's like this:
target_link_libraries(server PUBLIC network)
The PUBLIC can be omitted, but I like to specify it everywhere.
Also:
add_executable(network network.cpp)
should network.spp really be an executable? I guess there is no main in network.cpp`. You should:
add_library(network network.cpp)
And I guess the network include path is integral to the network library. So I would inside network/CMakeLists.txt do:
target_include_directories(network PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Also note the target_compile_feature is preferred over set(CMAKE_CXX_STANDARD 11).
Also, there is no error() function. There is message(FATAL_ERROR).
All in all, I would write it like this:
# root/CMakeLists.txt
cmake_minimum_required(VERSION 3.11.0)
project(Test)
# this tells cmake that all c++ files that are in this file
# and all in add_subdirectory projects
# will compile with C++11 (by default)
set(CMAKE_CXX_STANDARD 11)
add_subdirectory(network)
add_executable(server main.cpp)
# tell cmake to link server with network library
# ie. server executable uses network library
target_link_libraries(server PUBLIC network)
find_package(Boost 1.67 REQUIRED COMPONENTS thread)
# Check for libray, if found print message, include dirs and link libraries.
if(Boost_FOUND)
message(STATUS "Boost Found")
target_include_directories(server PUBLIC ${Boost_INCLUDE_DIRS})
target_link_libraries(server PUBLIC ${Boost_LIBRARIES} Boost::thread)
elseif(NOT Boost_FOUND)
message(FATAL_ERROR "Boost Not Found")
endif()
and:
# network/CMakeLists.txt
add_libraries(network network.cpp)
# tell cmake, that all targets that link with network library
# will have include path added
target_include_directories(network PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
I link only server executable with boost. I have no idea if your network library needs to link with boost too, if so, move the boost info netowrk/CMakeLists.txt and target_link_libraries(network PUBLIC ${Boost_LIBRARIES})
I think you have to change line
add_executable(server main.cpp)
to
add_executable(server main.cpp network.cpp)
P.S I personally prefer to use this construction:
SET(PROJECT_NAME "MyProject")
...
file(GLOB SRC_FILES *.cpp)
...
add_executable("${PROJECT_NAME}" "${SRC_FILES}")
Related
I try to add the library spdlog to a dll (.so file). The spdlog is just a git submodule from the spdlog library. Looking at the documentation, it's recommended to use it as a static library. So i think i have a problem trying to compile it inside a .so file.
To get a clear view of what i'm doing, here is a pic of my system:
My root CMakeLists.txt is :
cmake_minimum_required(VERSION 3.23)
# set the project name
project(Test VERSION "0.1.0" LANGUAGES CXX)
configure_file(config/config.h.in config.h)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -O3")
# Set location for .so files
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}")
# Set location for executables
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
add_subdirectory(Engine)
list(APPEND EXTRA_LIBS Engine)
add_subdirectory(Game)
target_link_libraries(Test PUBLIC ${EXTRA_LIBS})
target_include_directories(Test PUBLIC
"${PROJECT_BINARY_DIR}"
)
And inside the Engine folder:
message(STATUS "BUILD Engine shared library File")
add_subdirectory(spdlog)
add_library(Engine SHARED Log.cpp Log.h)
target_include_directories(Engine
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
target_link_libraries(Engine
spdlog
)
target_include_directories(Engine
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/spdlog/include
)
Inside the Game (not relevant at my opinion)
message(STATUS "BUILD .exe File")
# add the executable
add_executable(Test main.cpp)
But currently, if i try to use the spdlog inside my Log file, i have this cryptic error:
[build] /usr/bin/ld: spdlog/libspdlogd.a(spdlog.cpp.o): relocation R_X86_64_TPOFF32 against `_ZGVZN6spdlog7details2os9thread_idEvE3tid' can not be used when making a shared object; recompile with -fPIC
Does anyone have an idea?
Thanks to fabian in the comments, I add
set(CMAKE_POSITION_INDEPENDENT_CODE 1)
Just before adding the spdlog subdirectory and it just works fine.
|---Engine
|----CMakeList.txt
|----Engine.cpp
|----Engine.h
|---Models
|----CMakeList.txt
|----Snake.cpp
|----Snake.hpp
|---Type
|----CMakeList.txt
|----Point.hpp
|---CMakeList.txt
|---main.cpp
I just can't tell the main sheet that I want to add a directory with files to it ...
Each time, errors of the following type appear:
CMake Error at CMakeLists.txt: 12 (target_include_directories):
Cannot specify include directories for target "Snake" which is not built by
this project.
CMake Error at CMakeLists.txt: 13 (target_link_directories):
Cannot specify link directories for target "Snake" which is not built by
this project.
CMake Error at Engine / CMakeLists.txt: 8 (target_include_directories):
Cannot specify include directories for target "Snake" which is not built by
this project.
CMake Error at CMakeLists.txt: 17 (target_link_libraries):
Cannot specify link libraries for target "Snake" which is not built by this
project.
- Configuring incomplete, errors occurred!
Which, for several hours of intensified attempts, are not corrected in any way. Can anyone help with this?
CMakeLists.txt from Engine folder:
set(HEADERS
Engine.h)
set(SOURCES
Engine.cpp)
add_library(Engine ${HEADERS} ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
Main CMakeList.txt:
cmake_minimum_required(VERSION 3.16.3)
project(Snake)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(PROJECT_SOURCES
main.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC Engine)
target_link_directories(${PROJECT_NAME} PUBLIC Engine)
add_subdirectory(Engine)
target_link_libraries(${PROJECT_NAME} Engine)
add_executable(${PROJECT_NAME}
${PROJECT_SOURCES}
)
find_package(SFML 2.5.1 COMPONENTS graphics audio REQUIRED)
include_directories(${SFML_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} sfml-graphics sfml-audio)
set(SFML_STATIC_LIBRARIES FALSE)
There are two errors. The first one is to call a PROJECT_NAME that hasn't been built yet. add_executable(${PROJECT_NAME} ...) and add_library(${PROJECT_NAME ...) should be used before the target_include_directories and target_link_directories that refers to it. Because, as #Stephen Newell noted, otherwise you will be using a PROJECT NAME that hasn't been declared/built yet.
The second error is that you are calling a PROJECT_NAME inside Engine/CMakeLists. Maybe you are missing a project(...) inside of it.
Maybe you should move set(SFML_STATIC_LIBRARIES FALSE) before linking it, as well.
I want to make a small application using imgui
To run the test window I use the opengl glfw backend
The problem is that the files in the lib/ imgui_gl directory of my project can't access the headers that the file at the root of the project has access to
This is what my CmakeList file looks like
cmake_minimum_required(VERSION 3.17)
project(boardserver)
set(CMAKE_CXX_STANDARD 20)
set(LIB_FOLDER ${CMAKE_CURRENT_SOURCE_DIR}/lib) # Lib folder
add_executable(boardserver main.cpp)
find_package(imgui CONFIG REQUIRED)
find_package(GLEW REQUIRED)
find_package(OpenGL REQUIRED)
find_package(SDL2 REQUIRED)
find_package(glfw3 REQUIRED)
## Imgui opengl glfw backend lib
set(imgui-gl_Includes "${LIB_FOLDER}/imgui_gl/")
add_library(imgui-gl STATIC
${LIB_FOLDER}/imgui_gl/imgui_impl_glfw.cpp ${LIB_FOLDER}/imgui_gl/imgui_impl_opengl3.cpp )
include_directories(${imgui-gl_Includes})
target_link_libraries(boardserver PRIVATE imgui::imgui GLEW::GLEW OpenGL::GL SDL2::SDL2 glfw imgui-gl)
You need to tell CMake to link imgui-gl with the imgui::imgui target so it knows where to find imgui.h too:
target_link_libraries(imgui-gl PUBLIC imgui::imgui)
As modern CMake best practice, you may also want to make its include directory part of the interface:
target_include_directories(imgui-gl PUBLIC "${LIB_FOLDER}/imgui_gl")
Together, these statements ensure that any target that links to imgui-gl sees both the correct headers and knows what to link to.
I'm trying to build a C++ application which uses the library libpamg0-dev.
I installed it with the following command on my elementaryOS VM.
apt-get install libpam0g-dev
When I try to compile the application, the compiler spits out the following errors:
undefined reference to `pam_start`
undefined reference to `pam_authenticate`
undefined reference to `pam_end`
My CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.10)
project(application)
set(CMAKE_CXX_STANDARD 11)
INCLUDE_DIRECTORIES(/home/dnagl/dev/libs/restbed/distribution/include /usr/include/security)
LINK_DIRECTORIES(/home/dnagl/dev/libs/restbed/distribution/library /usr/lib/x86_64-linux-gnu)
add_executable(application main.cpp Utils/Json/Json.cpp Utils/Json/Json.h Utils/Stringhelper/Stringhelper.cpp Utils/Stringhelper/Stringhelper.h Utils/File/Filehelper.cpp Utils/File/Filehelper.h Utils/System/SystemHelper.cpp Utils/System/SystemHelper.h Controller/Info/InfoController.cpp Controller/Info/InfoController.h Rest/ResourceHandler/ResourceHandler.cpp Rest/ResourceHandler/ResourceHandler.h Controller/System/SystemController.cpp Controller/System/SystemController.h Rest/Log/RequestLogger.cpp Rest/Log/RequestLogger.h Controller/Authentication/AuthenticationController.cpp Controller/Authentication/AuthenticationController.h Controller/Log/LogController.cpp Controller/Log/LogController.h)
target_link_libraries(application restbed)
Maybe one of you knows how to link the library in the right way.
I have found a nice solution with find_package option from CMake. CMake provides a way to find packages/libraries with specified FindModule.cmake file.
A really good news is that there are a lot of existing module files. You can use this version to find PAM package on Linux. Put it to cmake/modules/ in your project folder and update your CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(restbed)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# Notify CMake that we have module files to find packages/libs.
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
find_package(PAM REQUIRED)
# Check if we found PAM.
if (NOT PAM_FOUND)
message(FATAL_ERROR "PAM library was not found.")
endif ()
# Source configuration.
include_directories(
${PAM_INCLUDE_DIR}
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
set(EXECUTABLE_NAME "application")
# Add sources to this project's executable.
add_executable(${EXECUTABLE_NAME}
"main.cpp"
"Utils/Json/Json.cpp"
"Utils/Json/Json.h"
"Utils/Stringhelper/Stringhelper.cpp"
"Utils/Stringhelper/Stringhelper.h"
"Utils/File/Filehelper.cpp"
"Utils/File/Filehelper.h"
"Utils/System/SystemHelper.cpp"
"Utils/System/SystemHelper.h"
"Controller/Info/InfoController.cpp"
"Controller/Info/InfoController.h"
"Rest/ResourceHandler/ResourceHandler.cpp"
"Rest/ResourceHandler/ResourceHandler.h"
"Controller/System/SystemController.cpp"
"Controller/System/SystemController.h"
"Rest/Log/RequestLogger.cpp"
"Rest/Log/RequestLogger.h"
"Controller/Authentication/AuthenticationController.cpp"
"Controller/Authentication/AuthenticationController.h"
"Controller/Log/LogController.cpp"
"Controller/Log/LogController.h"
)
target_link_libraries(${EXECUTABLE_NAME}
${PAM_LIBRARIES}
)
set_target_properties(${EXECUTABLE_NAME} PROPERTIES LINKER_LANGUAGE CXX)
Hope this helps!
I'm trying to learn cmake and have started converting an old make project over to cmake. Here is a simplified version of the directory structure I now have:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
core/
CMakeLists.txt
/sourcecode, other cmakes, etc.
test/
CMakeLists.txt
someTest.cpp
Currently, in my root CMakeLists.txt file I simply have this:
cmake_minimum_required(VERSION 2.8)
project(all)
add_subdirectory(src)
add_subdirectory(test)
What I wanted to do, was have a library created by core/CMakeLists.txt that can be used by both src/CMakeLists.txt to build the main executable, but also loaded by test/CMakeLists to build the unit tests.
So my src/core/CMakeLists.txt file currently looks sort of like this:
cmake_minimum_required(VERSION 2.8)
project(core)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wpedantic -Wreorder -DBOOST_TEST_DYN_LINK -DBOOST_LOG_DYN_LINK ")
#some other directories in my core code:
add_subdirectory(display)
add_subdirectory(training)
add_subdirectory(utility)
#some packages I use...
find_package(Boost 1.55.0
COMPONENTS
log
program_options
serialization
thread
system
filesystem
REQUIRED)
find_package(GLUT REQUIRED)
find_package(OpenGL REQUIRED)
find_package(Eigen3 REQUIRED)
include_directories(
${PROJECT_SOURCE_DIR}
${EIGEN3_INCLUDE_DIR})
target_link_libraries(core
display
training
utility
${Boost_LIBRARIES}
${OPENGL_LIBRARIES}
${GLUT_LIBRARY}
${OpenMP_LIBRARIES})
So the idea is that I now have a core target I can simply link against to run my tests, and everything should work. However, when I try to build main, for example, I get:
Cannot specify link libraries for target "core" which is not built by this
project.
I thought this might be because core doesn't have a add_library command, but if I add add_library(core) I get this error:
You have called ADD_LIBRARY for library core without any source files. This typically indicates a problem with your CMakeLists.txt file
But I don't want to add any source files; I just want this target to link the targets in the core directory and produce a target I can link against from test.
Clearly I'm missing some core knowledge here, either with cmake or the toolchain itself. Help is appreciated :)
If you only want to create a core target without source files, you need to declare it like an INTERFACE target. So, try to add the following code to your src/core/CMakeLists.txt:
cmake_minimum_required(VERSION 3.0) # REQUIRED 3.x.x version
project(core)
...
# Here declare your core_interface target
add_library(core_interface INTERFACE)
target_link_libraries(core_interface INTERFACE
display
training
utility
${Boost_LIBRARIES}
${OPENGL_LIBRARIES}
${GLUT_LIBRARY}
${OpenMP_LIBRARIES})
As you can see, if you make this, you'll need to upgrade your CMake installed version.
Then, you'll build your tests or any executable, linking with this interface target directly:
add_executable(main main.cpp)
target_link_libraries(main core_interface)