What am I doing wrong making SDL2 usable in Clion? [duplicate] - c

I'm looking for the simplest way to compile a c++ program using SDL2 and SDL_image with cmake.
Here is my best attempt, after hours of searching:
CMakeLists.txt
project(shooter-cmake2)
cmake_minimum_required(VERSION 2.8)
set(SOURCES
shooter.cpp
classes.cpp
utils.cpp
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
add_executable(${PROJECT_NAME} ${SOURCES})
INCLUDE(FindPkgConfig)
PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2)
PKG_SEARCH_MODULE(SDL2_image REQUIRED sdl2_image)
INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS} ${SDL2IMAGE_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${SDL2_LIBRARIES} ${SDL2IMAGE_LIBRARY})
I get these errors:
In function `loadTexture(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, SDL_Renderer*)':
undefined reference to `IMG_LoadTexture'
collect2: ld returned 1 exit status
Here is the function call:
#include "SDL.h"
#include "SDL_image.h"
SDL_Texture* loadTexture(const std::string &file, SDL_Renderer *ren){
SDL_Texture *texture = IMG_LoadTexture(ren, file.c_str());
texture != nullptr or die("LoadTexture");
return texture;
}

I think that the following will work, as it finds the libraries on my ubuntu system and the example function you provided can link:
project(shooter-cmake2)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
add_executable(${PROJECT_NAME} src/test.cpp)
INCLUDE(FindPkgConfig)
PKG_SEARCH_MODULE(SDL2 REQUIRED sdl2)
PKG_SEARCH_MODULE(SDL2IMAGE REQUIRED SDL2_image>=2.0.0)
INCLUDE_DIRECTORIES(${SDL2_INCLUDE_DIRS} ${SDL2IMAGE_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${SDL2_LIBRARIES} ${SDL2IMAGE_LIBRARIES})
If cmake is executed with --debug-output it outputs:
-- Found PkgConfig: /usr/bin/pkg-config (found version "0.26")
Called from: [2] /usr/share/cmake-2.8/Modules/FindPkgConfig.cmake
[1] $USER/stack-overflow/cmake-sdl2-image/CMakeLists.txt
-- checking for one of the modules 'sdl2'
Called from: [1] $USER/stack-overflow/cmake-sdl2-image/CMakeLists.txt
-- checking for one of the modules 'SDL2_image>=2.0.0'
Called from: [1] $USER/stack-overflow/cmake-sdl2-image/CMakeLists.txt
This made me check the contents of
/usr/lib/x86_64-linux-gnu/pkgconfig/sdl2.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/SDL2_image.pc
I noticed that SDL2_image.pc contains
Name: SDL2_image
which I assumed should match the third parameter to PKG_SEARCH_MODULE for this library.

There are two blog posts about this here:
Using SDL2 with CMake
Using SDL2_image with CMake
Basically you need a FindSDL2.cmake and FindSDL2_image.cmake module. They can be based of the ones that work for SDL 1.2 which are included in CMake already. Using these Find modules will also work on Windows.
If you are on Linux and only need SDL2 you don't even need the FindSDL2.cmake as the following already works:
cmake_minimum_required(VERSION 3.7)
project(SDL2Test)
find_package(SDL2 REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS})
add_executable(SDL2Test Main.cpp)
target_link_libraries(SDL2Test ${SDL2_LIBRARIES})

I was having trouble with these answers, I think cmake changed the way to import targets. Following #trenki blog post I needed to change my CMakeLists.txt to:
project(SDL2Test)
find_package(SDL2 REQUIRED COMPONENTS SDL2::SDL2)
add_executable(SDL2Test main.cpp)
target_link_libraries(SDL2Test SDL2::SDL2)
Currently this works out of the box on Arch Linux.

I introduced a modern and portable approach for linking to the SDL2, SDL2_image. These SDL2 CMake modules let you build an SDL2 & SDL2_image project as follows :
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/sdl2)
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
target_link_libraries(${PROJECT_NAME} SDL2::Main SDL2::Image)
You should just clone the repo in your project:
git clone https://github.com/aminosbh/sdl2-cmake-modules cmake/sdl2
Note: If CMake didn't find the SDL2/SDL2_image libraries (in Windows), we can specify the CMake options SDL2_PATH and SDL2_IMAGE_PATH as follows:
cmake .. -DSDL2_PATH="/path/to/sdl2" -DSDL2_IMAGE_PATH="/path/to/sdl2-image"
It supports also other related libraries : SDL2_ttf, SDL2_net, SDL2_mixer and SDL2_gfx. For more details, please read the README.md file.
You can find a list of examples/samples and projects that uses these modules here : https://github.com/aminosbh/sdl-samples-and-projects

Since 2.6 version, SDL2_image installation is shipped with CMake config script SDL2_imageConfig.cmake/SDL2_image-config.cmake.
So find_package(SDL2_image) works without any additional FindSDL2_image.cmake module, and creates IMPORTED target SDL2_image::SDL2_image:
find_package(SDL2_image REQUIRED)
target_link_libraries(<executable-target> SDL2_image::SDL2_image)
Note, that variables like SDL2_IMAGE_LIBRARIES or SDL2_IMAGE_INCLUDE_DIRS are NOT set in this case, so using them is meaningless.

The following commands works fine for me:
set(SDL_INCLUDE_DIR "/usr/include/SDL2")
set(SDL_LIBRARY "SDL2")
include(FindSDL)
if(SDL_FOUND)
message(STATUS "SDL FOUND")
endif()

Related

CMAKE generate a static library that depends on shared libraries

First of all, I am learning and I am very new to CMake, so please, have mercy. I have done some research about this but I have not found anything that actually works for me. I have made many changes to the CMakeLists.txt but I will try to show you summarize what I am trying to do and how I am trying to achieve that.
I have a project folder tree like this:
Mainfolder/:
CMakeLists.txt (CMakeLists1.txt to identify it better)
lib1:
source files (.h .c)
CMakeLists.txt (CMakeLists2.txt)
lib2:
source files (.h .c)
CMakeLists.txt (CMakeLists3.txt)
executable:
source files (.h .c)
CMakeLists.txt (CMakeLists4.txt)
Once this has been said, lib1 and lib2 are meant to be built as static libraries and depends on "rt" and "pthread" shared libs for example. Besides, lib2 depends on lib1.
I am crosscompiling, so I load the environment using and script and all the variables seem to be recognized properly by CMake (I have printed them and I verified the crosscompilation by compiling a Hello world example that ran properly on the target).
The CMakeLists1.txt serves as an entry point:
project(
MainApp
VERSION 0.1
DESCRIPTION "Main Application CMake compilation project"
LANGUAGES C)
add_subdirectory(lib1)
add_subdirectory(lib2)
add_subdirectory(executable)
How do I compile lib1 or lib2? Using the following CMakeLists2.txt:
cmake_minimum_required(VERSION 3.14...3.16)
project(
lib1
VERSION 0.1
DESCRIPTION "lib1 library"
LANGUAGES C)
find_library(RT_LIBRARY rt)
find_library(PTHREAD_LIBRARY pthread)
list(APPEND SRCS
source1.c
source2.c)
find_library(RT_LIBRARY rt)
find_library(PTHREAD_LIBRARY pthread)
add_library(lib1 ${SRCS})
# Include libraries required
target_link_libraries(lib1 ${PTHREAD_LIBRARY} ${RT_LIBRARY})
CMakelists3.txt is the same as CMakelists2.txt but including the lib1 dependencies:
find_library(LIB1_LIBRARY lib1)
add_library(lib2 ${SRCS})
target_link_libraries(lib2 ${PTHREAD_LIBRARY} ${RT_LIBRARY} ${LIB1_LIBRARY})
target_include_directories (lib2 PUBLIC {CMAKE_CURRENT_SOURCE_DIR}/../lib1)
I have to say I also tried to include the lib1 dependency using ${CMAKE_CURRENT_SOURCE_DIR}/../lib1/liblib1.a but it did not work either.
These seem to compile well and I see many "U" undefined symbols that I guess will be obtained from the shared library (sorry, I am doubting here and I am not sure if it should be considered as a fail already). In any case, I am not sure if the lib1 is linked to the lib2, and the same occurs with the shared libraries (rt and pthread).
And finally, CMakeLists4.txt which aims to put everything together and generate the executable:
cmake_minimum_required(VERSION 3.14...3.16)
project(
Execuable
VERSION 0.1
DESCRIPTION "MainApp library"
LANGUAGES C)
list(APPEND SRCS
source1.c
source2.c)
find_library(RT_LIBRARY rt)
find_library(PTHREAD_LIBRARY pthread)
find_library(RT_LIBRARY rt)
find_library(LIB1_LIBRARY lib1)
find_library(LIB2_LIBRARY lib2)
add_executable(Executable ${SRCS})
target_include_directories (Executable PUBLIC {CMAKE_CURRENT_SOURCE_DIR}/../lib1 {CMAKE_CURRENT_SOURCE_DIR}/../lib2)
target_link_libraries(Executable ${RT_LIBRARY} ${PTHREAD_LIBRARY} ${LIB1_LIBRARY} ${LIB2_LIBRARY})
If I compile each of the libraries separately, they seem to generate properly .a files, but as I try to execute the CMakeLists1.txt, it fails during the linking, showing undefined references in the lib1.a about, for example, shm_open (I found it is related to "rt" shared lib). So, I am not sure how to solve this situation.
Any help will be more than welcome.
Best regards,
Fulgo.
Tsyvarev gave me the answer. I had to avoid using find_library for the libraries built in the same CMake project. This allowed me to compile the project properly.

CLion finds a problem with CMakeLists.txt for importing a library but it works well by command line

When I use CMake with the terminal, I have no problems at all.
However, when I try to use CLion, SDL_image isn't found anymore...
Here is the error message of CLion:
CMake Error at
/Applications/CLion.app/Contents/bin/cmake/mac/share/cmake-3.17/Modules/FindPackageHandleStandardArgs.cmake:164
(message): Could NOT find SDL2_image (missing: SDL2_IMAGE_LIBRARIES
SDL2_IMAGE_INCLUDE_DIRS)
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(ProjectName C)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)
include_directories(${SDL2_INCLUDE_DIRS} ${SDL2_IMAGE_INCLUDE_DIRS})
add_executable(main.c)
target_link_libraries(main ${SDL2_LIBRARIES} ${SDL2_IMAGE_LIBRARIES})
#include "SDL.h"
#include "SDL_image.h"
int main(void) {
return 0;
}
Maybe CLion uses different values for CMake variables ?
I finally found the problem !
CLion uses a different version of CMake (3.17), however I use the version 3.19.
I changed the CLion CMake executable in the preferences (Build, Exec... -> Toolchains).
A warning tells me that CMake versions beyond 3.17.x are not supported. But it seems to work well.

Linker cannot find library from another project

guys,
I am relatively new to CMake and now I have a bug that I don't understand. Actually I thought I had no problems understanding the terms static and shared library and the functions of CMake. But currently...
So in my project projB I wanna use a static_library from project projA. ProjA is already compiled, linked, installed and used on my board. For ProjB the linker cannot find the library "example".
My issue: for me, i doesn't make sense why projA can find the shared library, projB not.
The error code:
Linking main ....
ld: cannot find -lexample
error: ld returned 1 exit status
My folder structure of projA:
include/ ... *.h (e. g. file.h)
src/ ... *.c (e. g. file.c)
CMakeFiles.txt
The CMakeLists.txt-File of projA:
cmake_minimum_required(VERSION 3.7)
PROJECT(projA)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_definitions(-g -O)
include_directories (include)
file (GLOB SOURCE_FILES src/*.c)
add_library (example STATIC ${SOURCE_FILES})
target_include_directories(example PUBLIC ${SOURCE_DIR}/include)
install(TARGETS example ARCHIVE DESTINATION usr/lib)
So projA will be later a library-component which can be used in many other projects. That's the reason why the created library is not part of projB and why I wanna import/include the created example.a file in a lot of other projects. The static library example.a should be stored in usr/lib.
In my projB the folder structure looks like:
CMakeFiles.txt
main.c
.... *.c
In my main.c-File I try to include the library with #<file.h> which is a part of my created library example.
The CMakeFiles.text of ProjB containing following Code:
cmake_minimum_required(VERSION 3.7)
PROJECT(projB)
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set (CMAKE_C_STANDARD 99)
set (CMAKE_CXX_STANDARD 14)
add_definitions(-g -O -fpermissive)
# build executable
file (GLOB SOURCES *.c )
add_executable (exe ${SOURCES})
# target_include_directories(exe PUBLIC ${CMAKE_SOURCE_DIR}/usr/lib)
# add_library(example SHARED IMPORTED)
# set_property(TARGET example PROPERTY IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/usr/libexample.a)
target_link_libraries (exe example pthread)
install (TARGETS exe RUNTIME DESTINATION usr/sbin)
An attempt to find the error is commented out. I also worked with find_library(), but the library "example" could not be found. Of course I also built the library example as a shared_library and searched for a .so, etc.
As you can see from my example, this is not real code (used in production), but a simplified description of my problem. I am more interested in the systematic. Wrong thinking?
Does anyone have any idea what else I can try or why it doesn't work?
Is it because they are different projects? I mean, the file exists on my system, but is not found ...
Thanks a lot for your help!
Greetings
Matthias

Debug postfix messes up linking SDL2 with CMake

I am trying to set up a project with the SDL2 library using CMake. When i compile for release everything works fine. However when setting the build type to debug compilation fails with the following error:
*** No rule to make target 'Lib/SDL2/libSDL2d.a', needed by '../Bin/Template'. Stop.
It seems like SDL2 adds a postfix for debug builds and that messes things up.
This is the CMakeLists.txt im using:
cmake_minimum_required(VERSION 3.2.0)
project(Template)
add_subdirectory(Lib/SDL2)
# C Standard
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
# compile with debug info
set(CMAKE_BUILD_TYPE Debug)
# output directories
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/Bin)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/Bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/Bin)
# build directory
set(CMAKE_BUILD_DIRECTORY ${CMAKE_SOURCE_DIR}/Build)
include_directories(
Source
Lib/SDL2/include
)
set(SOURCES
Source/main.c
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} SDL2-static)
I don't want to use find_packge and include the SDL2 source code directly into my project.
What do i need to change to be able to compile for debug?
The SDL2 code should add the postfix d to the built library name when CMAKE_BUILD_TYPE is set to Debug (see the SDL2 code snippet here). What appears to be the issue here is the placement of the line:
set(CMAKE_BUILD_TYPE Debug)
in your CMake file. You probably initially built this in the Release configuration. But when switching it to Debug, the change is not applied to SDL2 because CMAKE_BUILD_TYPE is set after traversing to the Lib/SDL2 directory. You can correct this by moving the set() command before the call to add_subdirectory():
# Set the build type first!
set(CMAKE_BUILD_TYPE Debug)
add_subdirectory(Lib/SDL2)
You can avoid these issues by setting the build configuration at the command line instead, which is the more common and accepted CMake convention:
cmake -DCMAKE_BUILD_TYPE=Debug ..

Building a dynamic/shared library for a libclang project (LLVM) using CMake

I am trying to generate a dynamic(shared) library for a single C file, which uses LibClang (LLVM)
Here's are the imports of that file.
#include <clang-c/Index.h>
#include <stdio.h>
#include <stdlib.h>
I am struggling with building a dynamic library for this file using CMake
Currently, I am building it using clang compiler itself with this command, but I want to use CMake to be able to build it for other platforms with ease
clang -I/usr/lib/llvm-10/include/ -lclang -shared -fpic wrapper.c -o libwrapped_clang.so
Here's my CMakeLists.txt
but this gives "undefined function clang_..." errors
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
project(wrapped_libclang VERSION 1.0.0 LANGUAGES C)
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "LLVM_INCLUDE_DIRS: ${LLVM_INCLUDE_DIRS}")
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
add_library(wrapped_libclang SHARED wrapper.c)
add_executable(wrapped_clang_test wrapper.c)
llvm_map_components_to_libnames(llvm_libs support core irreader)
# Link against LLVM libraries
target_link_libraries(wrapped_clang_test ${llvm_libs})
set_target_properties(wrapped_libclang PROPERTIES
PUBLIC_HEADER wrapper.c
VERSION ${PROJECT_VERSION}
SOVERSION 1
OUTPUT_NAME "wrapped_clang"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Hex_Identity_ID_Goes_Here"
)
Any help is appreciated :/
====================== EDIT 1 =============================
Tried this, it partially worked,
The dynamic library created now has all symbols from my wrapper.c file, but doesn't have any of the functions in libClang
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
project(wrapped_libclang LANGUAGES C)
find_package(Clang REQUIRED)
# Add path to LLVM modules
set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH}
"${LLVM_CMAKE_DIR}"
)
include(AddLLVM)
include_directories(${LLVM_INCLUDE_DIRS})
include_directories(${CLANG_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
add_definitions(${CLANG_DEFINITIONS})
add_llvm_library(wrapped_libclang SHARED wrapper.c)
set_target_properties(wrapped_libclang PROPERTIES
PUBLIC_HEADER wrapper.c
OUTPUT_NAME "wrapped_clang"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "Hex_Identity_ID_Goes_Here"
)

Resources