Make a library with cmake that use the SDL - c++

I am trying to create a library on the top of SDL2. For the compilation I'm using cmake.
First I had this CMakeLists.txt for the library :
cmake_minimum_required(VERSION 3.10)
project(SquareEngine)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
include_directories(${SDL2_IMAGE_INCLUDE_DIRS})
set (SRCS Main.cpp
Rectangle.cpp
Scene.cpp
SquareEngine.cpp)
set (HEADERS Rectangle.hpp
Scene.hpp
SquareEngine.hpp
utils/Color.hpp
utils/Vector.hpp)
add_library(SquareEngine ${SRCS} ${HEADERS} ${SDL} ${SDL_SRC})
target_link_libraries(SquareEngine ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES})
To include the SDL2 and SDL2 image I follow this instructions.
When I try to build it's work perfectly.
Now I try to use my library in a project. I create my own project and I link my librairy that is located in a subfolder /SquareEngine in my project. For the project I use this CMakeLists.txt :
cmake_minimum_required(VERSION 3.10)
project(Demo)
set (SRCS Main.cpp)
add_subdirectory(SquareEngine)
add_executable(Demo ${SRCS})
target_link_libraries(Demo PUBLIC SquareEngine)
target_include_directories(Demo PUBLIC SquareEngine)
When I try to build the project I got an error like this :
Cannot open include file: 'SDL.h': No such file or directory
I try to figure out for long time and I don't have any clue why.
Maybe it will be better to use the SDL in static rather than shared ?

I think you need to add the SDL include dirs to the SquareEngine library:
target_include_directories(SquareEngine PUBLIC ${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS})

The most recent SDL2 releases provide SDL2::* CMake targets such that you don't need to fiddle with CMake variables anymore.
So there's no more need to ship your custom FindSDL2.cmake and/or FindSDL2_image.cmake modules.
With those, you can rewrite your cmake script as:
cmake_minimum_required(VERSION 3.10)
project(SquareEngine)
find_package(SDL2 REQUIRED CONFIG)
find_package(SDL2_image REQUIRED CONFIG)
set (SRCS
Main.cpp
Rectangle.cpp
Scene.cpp
SquareEngine.cpp
)
set (HEADERS
Rectangle.hpp
Scene.hpp
SquareEngine.hpp
utils/Color.hpp
utils/Vector.hpp
)
add_library(SquareEngine ${SRCS} ${HEADERS})
target_link_libraries(SquareEngine PRIVATE SDL2::SDL2 SDL2_image::SDL2_image)
target_include_directories(SquareEngine
PUBLIC
$<TARGET_PROPERTY:SDL2::SDL2,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:SDL2_image::SDL2_image,INTERFACE_INCLUDE_DIRECTORIES>
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
)
It can then be used in your game as:
cmake_minimum_required(VERSION 3.10)
project(Demo)
set (SRCS Main.cpp)
add_subdirectory(SquareEngine)
add_executable(Demo ${SRCS})
target_link_libraries(Demo PUBLIC SquareEngine)

Related

Cannot build cmake project with including directories in cmake project

|---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.

Make it possible to use imports of the whole project in the catalog CMake

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.

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 build other folders in CMake

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}")

CLion/CMake can find SDL in one project, but not another

I have two C++ projects in SDL, both using SDL. For whatever reason, one of these projects can find SDL just fine. For the other, I can write code as if SDL was found- with autocompletion and everything- but when it comes to building the project, I am informed that fatal error: 'SDL2/SDL.h' file not found.
The CMakeLists.txt files of both projects are basically identical.
CMakeLists.txt for the project that doesn't work:
cmake_minimum_required(VERSION 3.12)
project(Snake)
set(CMAKE_CXX_STANDARD 11)
include_directories(.)
find_package(SDL2 REQUIRED)
add_executable(${PROJECT_NAME}
main.cpp
SnakeBlock.cpp
SnakeBlock.h
SnakeGame.cpp
SnakeGame.h
SnakeBoard.cpp
SnakeBoard.h)
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARY})
And CMakeLists.txt for the project that does work:
cmake_minimum_required(VERSION 3.12)
project(Tetris)
set(CMAKE_CXX_STANDARD 11)
include_directories(.)
find_package(SDL2 REQUIRED)
add_executable(${PROJECT_NAME}
Game.cpp
Game.hpp
main.cpp
Playfield.cpp
Playfield.hpp
Tetromino.cpp
Tetromino.hpp)
target_link_libraries(${PROJECT_NAME} ${SDL2_LIBRARY})
And for both projects, SDL2 appears under the "External Libraries" section on the right sidebar, under Header Search Paths.
What gives?