CMake subdir library and main project - c

This is an example, I googled a lot for this today but I cannot find a good way for have this thing done.
For example I followed what's written in this link: http://mirkokiefer.com/blog/2013/03/cmake-by-example/
I have
/Build
/Src
=> main.c
/Lib
=> File.c
=> File.h
I have a CMakeLists.txt in the Src dir
SET(SOURCES
main.c
)
add_subdirectory(Lib)
ADD_EXECUTABLE(${PROJECT_NAME} ${SOURCES})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} lib)
and in the Lib dir:
set(LibSrc
File.c
)
set(LibHead
File.h
)
add_library(lib STATIC ${LibSrc} ${LibHead})
target_include_directories(lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
When I compile the project everything compile corretly, but when the gcc links the library with the rest of the project I receive an error like:
main.cpp:(.text+0x10): undefined reference to `test()`
It is driving me crazy... Any hints on where I'm doing it wrong? Thank you

It looks like your target_link_libraries command is missing the list of dependencies. I guess in your case, you just want to link "lib", so you need to change this to:
target_link_libraries(${PROJECT_NAME} lib)
As an aside, you're missing a $ before {CMAKE_CURRENT_SOURCE_DIR} in the line
target_include_directories(lib PUBLIC {CMAKE_CURRENT_SOURCE_DIR})

Related

Trying to use Paho C client library for MQTT with Cmake

I have a simple test project to try and include the mqtt library but cant seem to get it working.
Here's my directory structure:
test/
build/
paho.mqtt.c/
CMakeLists.txt
main.c
Here's my CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
# set the project name
project(mqtt)
add_executable(${PROJECT_NAME} main.c)
add_subdirectory(paho.mqtt.c)
target_include_directories(
${PROJECT_NAME}
PUBLIC paho.mqtt.c/src
)
target_link_directories(
${PROJECT_NAME}
PUBLIC paho.mqtt.c/src
)
target_link_libraries(${PROJECT_NAME}
paho.mqtt.c
)
When I try and include MQTTAsync.h into main.c the output from my terminal reads
/usr/bin/ld: cannot find -lpaho.mqtt.c
If anyone can help it would be greatly appreciated. I'm new with CMake and C programming so forgive me for being a noob.

CMake and issues with header files in subfolders

I'm trying to set up a project where header files can be found by the subfolder libraries src code as well as the src code in the top level using Cmake. Currently i am getting an error stating that the header file can not be found. The structure of my project looks like this:
root/
src/
CMakeLists.txt #(top level)
main.c
lib/
lib1.c
CMakeLists.txt #(lower level)
headers/
lib1.h
build/
My top level CMakeLists.txt looks like this:
cmake_minimum_required(VERSION 3.13.4)
project(CmakeTUT_Proj)
add_executable(${PROJECT_NAME} main.c)
target_include_directories(${PROJECT_NAME} PUBLIC Lib/headers/)
add_subdirectory(Lib/)
target_link_directories(${PROJECT_NAME} PRIVATE Lib/headers/)
target_link_libraries(${PROJECT_NAME} name_of_lib)
My lower level CMakeLists.txt looks like:
add_library(name_of_lib adder.c)
My main.c and my lib1.c programs include the library as #include "lib1.h", cmake runs fine without any errors but when i build the project with make i get an error like:
root/src/Lib/lib1.c:2:10: fatal error: lib1.h: No such file or directory
#include "lib1.h"
I want to structure my project so that main.c and lib1.c have access to lib1.h. Any ideas? Thank you.
As the name implies, target_include_directories only affects one target. So when you set target_include_directories(${PROJECT_NAME} PUBLIC Lib/headers/), this adds to the include path for the executable target named ${PROJECT_NAME} but not to the include path for the library name_of_lib.
To fix this, you can add the include path for your library in the lower level CMakeLists.txt:
target_include_directories(name_of_lib PUBLIC headers)
As a bonus, because it's PUBLIC, this path is also automatically added to any target that depends on name_of_lib. So in the top-level CMakeLists.txt, you can remove this line:
target_include_directories(${PROJECT_NAME} PUBLIC Lib/headers/)
Aside, this line looks useless and can probably be removed as well:
target_link_directories(${PROJECT_NAME} PRIVATE Lib/headers/)
Link libraries are not usually placed in headers directories.

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

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

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()

Cannot find API header file for shared library with cmake

I am building a shared library in one project and using it in another. They share a prefix, but I'm not building them together (e.g., <prefix>/mylib and <prefix>/myproject). Both mylib and myproject have src and include directories.
The CMakeList.txt for the shared library:
cmake_minimum_required(VERSION 3.5)
project(mylib)
add_library(mylib SHARED
src/mylib.c
)
target_include_directories(mylib PRIVATE include)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)
install(TARGETS
mylib
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include
RUNTIME DESTINATION bin)
This results in mylib.so being installed in install/mylib/lib/mylib.so and mylib.h being installed in install/mylib/include/mylib.h, which is what I intended.
I then want to build a project that uses mylib:
#include "mylib.h"
int main(void)
{
// use some functions in mylib
}
The associated CMakeList.txt file for main.c:
cmake_minimum_required(VERSION 3.5)
project(myproject)
find_package(mylib REQUIRED)
add_executable(myproject src/main.c)
target_link_libraries(myproject mylib)
install(TARGETS
myproject
DESTINATION lib/${PROJECT_NAME})
This produces:
main.c: fatal error: mylib.h: No such file or directory
#include "mylib.h"
^~~~~~~~~
If I change CMakeList.txt to include the following:
find_path(MYLIB_INCLUDE_DIR mylib.h)
...
target_include_directories(myproject PUBLIC ${MYLIB_INCLUDE_DIR})
Then it finds the header, but not the library. I get a linker error:
/usr/bin/ld: cannot find -lmylib
If I change CMakeList.txt to include the following:
find_library(MYLIB_LIB mylib)
...
target_link_libraries(myproject ${MYLIB_LIB})
Then it builds.
I (think I) understand why finding the library and include files manually works, but that seems to be the wrong way to go about things...
find_package(mylib) does seem to find the mylib package (I can print cmake cache variables and mylib_FOUND=1), but doesn't find the library and header in such a way that they are built with myproject.
You need to specify include directories for both "build" and "install" variants in target_include_directories in your library project:
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> # build variant
$<INSTALL_INTERFACE:include> # install variant
)
BTW, such example is provided in documentation for target_include_directories command.
Additionally, you need to EXPORT the library during installation:
install(
TARGETS mylib
EXPORT mylib
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include
RUNTIME DESTINATION bin)
See this answer for a tutorial on exporting libraries with cmake.

Resources