Cmake add include_dirs to a target, then link target to a executable - cmake

How do I set the include dirs of a target, then include that target in my executable the current project folder looks like this:
├── CMakeLists.txt
├── libs
│ ├── CMakeLists.txt
│ └── libs.h
├── src
│ ├── CMakeLists.txt
│ └── main.cpp
└── tests
└── tests.cpp
So I would like to puts the .h files of the libs on the libs folder and make that a target which I can link to, I currently have something like this:
CMakeLists.txt:
cmake_minimum_required(VERSION 3.20.0)
project("Project")
add_subdirectory(libs)
add_subdirectory(src)
src/CMakeLists.txt:
add_executable(main main.cpp)
target_link_libraries(main libs)
libs/CMakeLists.txt:
add_custom_target(libs PUBLIC)
target_include_directories(libs ${CMAKE_CURRENT_SOURCE_DIR})

Related

How to properly use CMake to create a complex project with dependencies on custom libraries

I'm trying to create a complex project that becomes a single executable file that uses the following libraries: two libraries BHV and HAL that use one interface library.
I have this project structure:
.
├── BHV
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libBHV_Library.so
│   ├── Makefile
│   └── sources
├── HAL
│   ├── check_libraries.cmake
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libHAL_Library.so
│   ├── Makefile
│   └── sources
├── Interface
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libInterface_Library.a
│   ├── Makefile
│   └── sources
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── main.cpp
├── Makefile
├── README.md
Unfortunately, I can't connect the individual libraries to each other.
In Interface_lib CMakeList.txt I have this:
cmake_minimum_required(VERSION 3.10)
project(Interface_Library)
#requires at least C++17
set(CMAKE_CXX_STANDARD 17)
# Add all .cpp files from sources folder
file(GLOB SOURCES "sources/*.cpp")
# Add all .h files from include folder
file(GLOB HEADERS "include/*.h")
# Add main.cpp to the project
add_library(Interface_Library STATIC ${SOURCES} ${HEADERS})
In HAL_lib CMakeList.txt I have this:
cmake_minimum_required(VERSION 3.10)
project(HAL_Library)
# requires at least C++17
set(CMAKE_CXX_STANDARD 17)
################################### DIR_MANAGMENT #########################################
# Get the parent directory
get_filename_component(PARENT_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)
#Set the directory of the parent file as the current directory
set(CMAKE_CURRENT_LIST_DIR ${PARENT_DIR})
message("MYPROJECT_DIR directory: ${CMAKE_CURRENT_LIST_DIR}")
################################### HAL_LIB #########################################
# Add all .cpp files from sources folder
file(GLOB SOURCES "sources/*.cpp")
# Add all .h files from include folder
file(GLOB HEADERS "include/*.h")
# Add main.cpp to the project
add_library(HAL_Library SHARED ${SOURCES} ${HEADERS})
################################### INTERFACE_LIB #########################################
target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Interface)
# Link the Interface_Library into the HAL_Library
target_link_libraries(HAL_Library Interface_Library)
# check if libraries were included
set(TARGET_NAME HAL_Library)
include(check_libraries.cmake)
this is the code i use to check_libraries.cmake (from the internet)
# Get a list of referenced libraries
get_target_property(LINK_LIBS ${TARGET_NAME} LINK_LIBRARIES)
# Print the list of referenced libraries
message("Odkazované knihovny: ${LINK_LIBS}")
# Verify that libraries are available on the system
foreach(LIB ${LINK_LIBS})
execute_process(COMMAND ldd $<TARGET_FILE:${TARGET_NAME}> | grep ${LIB}
RESULT_VARIABLE res
OUTPUT_QUIET ERROR_QUIET)
if(res EQUAL "0")
message("Library ${LIB} was successfully linked with ${TARGET_NAME}")
else()
message(FATAL_ERROR "Error: Library ${LIB} not found.")
endif()
endforeach()
As an output I keep getting the library not found. What am I doing wrong?
And is my approach to project structure correct?
Thank you.
Typically you do:
# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(Interface_Library)
add_subdirectory(HAL)
add_subdirectory(Interface)
# HAL/CMakeListst.txt
file(srcs GLOB sources/*.c include/*.h)
add_library(HAL ${srcs})
target_include_directories(HAL PUBLIC include)
target_link_libraries(HAL PUBLIC Interface)
# Interface/CMakeLists.txt
file(srcs GLOB source/*.c include/*.h)
add_library(Interface ${srcs})
target_include_directories(HAL PUBLIC include)
That's all. Only one project() call, in the root. Note the target_include_directories missing in your code. Note the main root CMakeLists.txt that includes all. I find HEADERS and SOURCES separately confusing, I would also use lowercase everything. No target_link_directories, CMake will find everything. Also, everything is compiled as one big project, not separately.

Multiple undefined reference during linking of a CMake project using ARM toolchain

I'm developing a build system using CMake to build applications using the arm-none-eabi toolchain.
This is my folder structure:
project/
├── apps/
│ ├── test_app
│ │ ├── inc/
│ │ ├── src/
│ │ ├── CMakeLists.txt
├── arch/
│ ├── CMSIS/
│ ├── include/
│ ├── startup/
│ ├── CMakeLists.txt
├── cmake/
│ ├── toolchain-samd51.cmake
├── CMakeLists.txt
This is my top level CMakeLists.txt:
cmake_minimum_required(VERSION 3.17)
project(SMALL-FW LANGUAGES C)
add_subdirectory(arch)
add_subdirectory(apps/test_app)
This is the toolchain cmake file:
# Set target architecture
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)
# Set compiler to use
set(CMAKE_C_COMPILER "arm-none-eabi-gcc")
#set(CMAKE_LINKER "arm-none-eabi-ld")
# Clear default compiler and linker flags.
set(CMAKE_C_FLAGS "")
set(CMAKE_C_LINK_FLAGS "")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# FIX - Bypass compiler check
set(CMAKE_C_COMPILER_FORCED TRUE)
# Define common compiler and linker flags
set(ARM_OPTIONS
-mthumb
-mabi=aapcs-linux
-mcpu=cortex-m4
-mfpu=fpv4-sp-d16
-mfloat-abi=softfp
--specs=nano.specs
-mlong-calls
-DSAMD51
)
# Define compiler specific flags
add_compile_options(
${ARM_OPTIONS}
-D__SAMD51J19A__
-ffunction-sections
-Wall
)
# Define linker specific flags
add_link_options(
${ARM_OPTIONS}
#--specs=nano.specs
LINKER:--gc-sections
)
This is the CMakeList.txt inside the arch folder:
add_library(asf OBJECT
startup/startup_samd51.c
startup/system_samd51.c
)
# Every target that links against asf needs to know where the ASF headers are.
target_include_directories(asf PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/CMSIS/Include
${CMAKE_CURRENT_SOURCE_DIR}/include
)
# Use the custom linker script provided with ASF.
target_link_options(asf PUBLIC
-T${CMAKE_CURRENT_SOURCE_DIR}/startup/samd51j19a_flash.ld
)
And this is the app CMakeLists.txt:
add_executable(APP)
target_sources(APP PRIVATE src/main.c src/module.c)
target_include_directories(APP PRIVATE inc/)
target_link_libraries(APP asf)
CMake is running fine when the CMAKE_C_COMPILER_FORCED options is set to true, but when I try to make the project it fails with multiple undefined references errors like the next one:
/build/arm-none-eabi-newlib/src/build-nano/arm-none-eabi/thumb/v7e-m+fp/softfp/newlib/libc/reent/../../../../../../../../newlib-4.2.0.20211231/newlib/libc/reent/sbrkr.c:51: undefined reference to _sbrk'`
I have tried using nosys.specs flag but similar errors occurs.
Try this, it looks like typo
# Define linker specific flags
add_link_options(
${ARM_OPTIONS}
--specs=nano.specs
--gc-sections
)

Library linking not working when CMake single build

using CMake I want to build in each directory A, B, and C.
The project structure is as follows:
.
├── A
│   ├── CMakeLists.txt
│   └── src
│   └── a.cpp
├── B
│   ├── CMakeLists.txt
│   └── src
│   └── b.cpp
├── common
│   ├── CMakeLists.txt
│   ├── include
│   │   ├── common.h
│   └── src
│   └── common.cpp
└── C
├── CMakeLists.txt
└── src
└── c.cpp
Create a library in the Common directory and install the created library.
common/CmakeLists.txt :
set(COMMON_LIB_NAME CommonTemp)
set(SRC_CODE
${CMAKE_CURRENT_SOURCE_DIR}/include/common.h
${CMAKE_CURRENT_SOURCE_DIR}/src/common.cpp
)
add_library (${COMMON_LIB_NAME} SHARED ${SRC_CODE})
install(TARGETS ${COMMON_LIB_NAME} DESTINATION ~/tempDir/lib)
I want to link the generated library to directory A.
a.cpp requires common.h.
A/CMakeLists.txt:
ADD_EXECUTABLE(ServiceA src/a.cpp)
target_include_directories (
ServiceA PUBLIC
include
)
target_sources (
ServiceA PRIVATE
src/a.cpp
)
target_link_libraries(
ServiceA PUBLIC
${COMMON_LIB_NAME} #### Location considered to be a problem
)
install(TARGETS ServiceA DESTINATION ~/tempDir/bin/A)
An error message occurs saying that common.h cannot be included.
My guess is that the ${COMMON_LIB_NAME} variable is defined in CMakeLists.txt in another directory, so it is expected that it cannot be linked.
But even if I put CommonTemp , the value of the variable, it says that common.h cannot be found.
How can I link library links even if I build CMake individually in each directory?
In common/CmakeLists.txt.
You need to include the headers in target_include_directores.
target_include_directories(
${COMMON_LIB_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
No need to mention it in add_library
In A/CMakeLists.txt. Include path is not correct.
target_include_directories(
ServiceA PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/<path to common>/include
)
For linking the library you have to mention the correct library path otherwise it will fail
target_link_libraries(
ServiceA PUBLIC
${COMMON_LIB_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/<path to tempDir>/lib
)

How to add include_directory in simple CMake Project

I have CMake project whose directory structure is as follows:
├── build
├── CMakeLists.txt
├── src
│   ├── CMakeLists.txt
│   ├── headers
│   │   └── utility.h
│   └── main.cpp
└── tests
├── CMakeLists.txt
├── testfeature_a
│   ├── CMakeLists.txt
│   └── test_me.cpp
└── test_main.cpp
In test_me.cpp I wanted to include utility.h as I wanted to test functions defined there. So I did #include "headers/utility.h" and in testfeature_a CMakeLists.txt I did this:
file(GLOB SRCS *.cpp)
ADD_EXECUTABLE(testfeature_a ${SRCS})
include_directories(src/headers)
TARGET_LINK_LIBRARIES(
testfeature_a
libgtest
libgmock
)
add_test(NAME testfeature_a
COMMAND testfeature_a)
But the make fails with the error message fatal error: headers/utility.h: No such file or directory.
How can I include the headers directory in test_me.cpp
Your path in include_directories() may be incorrect. Here are two things that you could check
The file seems to be the CMakeLists.txt in tests-folder so you need to go up one folder before you can go to src-folder, i.e. include_directories(../src/headers).
You repeat the headers-folder in the #include "headers/utility.h" when you have already specified it in include_directories(src/headers). Either use #include "utility.h" in cpp-file or include_directories(src) in CMakeLists.txt.
Other option is that you don't need to specify the headers-folder in the CMakeLists.txt at all. You can simply use #include "path/to/your/file.h without any other configuration.
For debugging your path in the CMakeLists.txt you can call message-function, e.g. message(${your_path}), so it's printed when executed and you can check if it's correct.
In addition you can use CMake built-in variables such as CMAKE_CURRENT_SOURCE_DIR and CMAKE_SOURCE_DIR, e.g. include_directories(${CMAKE_SOURCE_DIR}/src/headers)

cmake can't find the depending library

I have a demo project which rely on a logger library, The file structure of the relevant files are listed as below:
.
├── FancyLogger
│   ├── CMakeLists.txt
│   ├── FancyLogger.cpp
│   ├── FancyLogger.h
│   ├── bin
│   │   └── libFancyLogger.a
└── HelloClion
├── CMakeLists.txt
├── helloclion.cpp
I have build a static library named as libFancyLogger.a in the ./FancyLogger/bin directory.
My CMakeFiles of the project HelloClion is listed as below:
cmake_minimum_required(VERSION 3.3)
project(HelloClion)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
get_filename_component(CODE_ROOT ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
set(SOURCE_FILES helloclion.cpp)
add_executable(HelloClion ${SOURCE_FILES})
include_directories(${CODE_ROOT}/FancyLogger)
link_directories(${CODE_ROOT}/FancyLogger/bin)
target_link_libraries(HelloClion FancyLogger)
But the linker complains that library not found for -lFancyLogger, I don't know how to fix this, please help.
I seems to find out why. ;)
In the cmake documentation:https://cmake.org/cmake/help/v3.0/command/link_directories.html
link_directories(directory1 directory2 ...)
Specify the paths in which
the linker should search for libraries. The command will apply only to
targets created after it is called.
The doc says, the command only applys to targets created after it is called. So I just need to move link_directories(${CODE_ROOT}/FancyLogger/bin) to some position in front of the add_executable(HelloClion ${SOURCE_FILES}) command.
Problems solved!