How to set include directories - cmake

I have a directory with various pre-built libraries (mostly headers and libs/dlls, all built without CMake or copied without installing using CMake). For my next project i want to use these libraries with CMake.
I am writing a script that iterates over all the libraries and generates the needed <name>Config.cmake and <name>ConfigVersion.cmake files referencing the existing directory structure.
A minimal config file may look like:
SET(ROOT_DIR_MYLIB "${CMAKE_CURRENT_LIST_DIR}/../../../../MyLib")
add_library(MyLib STATIC IMPORTED)
set_target_properties(MyLib PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${ROOT_DIR_MYLIB}/include"
IMPORTED_LOCATION "${ROOT_DIR_MYLIB}/Lib/MyLib.lib"
IMPORTED_LOCATION_DEBUG "${ROOT_DIR_MYLIB}/Lib/MyLibd.lib"
)
I have copied the line where the property INTERFACE_INCLUDE_DIRECTORIES is set from another project where this worked, but for some reason it does not for MyLib. When i attempt to include its header files i get compile errors that the include files can not be found.
What am i missing here?

Related

CMake INTERFACE_INCLUDE_DIRECTORIES for IMPORTED target with CONFIG

I have an IMPORTED target which comes from a config package generated by conan. Since conan creates packages for the build type specified in the build_type of the profile, I have added CMAKE_MAP_IMPORTED_CONFIG_DEBUG to Release, so that even if I compile a Debug build of my project, I can still use Config files generated with conan using a Release profile.
This works fine for all the targets in my project. include directories are set correctly, libraries link correctly. except for one case:
I have an INTERFACE target which I use to use only the include directories of an IMPORTED target if one option is set, or use the whole target.
add_library(deTracing INTERFACE)
# Get include directories of Tracy::TracyClient target
get_target_property(TRACY_INCLUDE_DIRECTORIES Tracy::TracyClient INTERFACE_INCLUDE_DIRECTORIES)
# Include the directories unconditionally
target_include_directories(deTracing INTERFACE ${TRACY_INCLUDE_DIRECTORIES})
# Some debug stuff
message(status ${TRACY_INCLUDE_DIRECTORIES})
add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "${TRACY_INCLUDE_DIRECTORIES}")
# If ENABLE_PROFILING is set, link to the library
if(ENABLE_PROFILING)
target_link_libraries(deTracing INTERFACE Tracy::TracyClient)
target_compile_definitions(deTracing INTERFACE ENABLE_PROFILING)
endif()
The issue is that TRACY_INCLUDE_DIRECTORIES is a generator expression with this content
$<$<CONFIG:Release>:/home/seddi/.conan/data/tracy/0.9/_/_/package/913e5b8c3a7b64b23fdaa63b58e3915a742a1112/include>, which is what I can expect, it just contains the include directory for the release config.
But when this expression is evaluated in a Debug build, it just collapses to an empty string, even though I have set the CMAKE_MAP_IMPORTED_CONFIG_DEBUG to Release, so it doesn't set any include directories.
I am out of ideas of how I set the correct INCLUDE_DIRECTORIES to deTracing target.
Edit:
According to CMake, the MAP_IMPORTED_CONFIG_ property is followed when evaluating properties of IMPORTED targets. I have modified deTracing to be an IMPORTED target, yet still doesn't work.
add_library(deTracing INTERFACE IMPORTED)
get_target_property(TRACY_INCLUDE_DIRECTORIES Tracy::TracyClient INTERFACE_INCLUDE_DIRECTORIES)
set_property(
TARGET deTracing
PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${TRACY_INCLUDE_DIRECTORIES}
APPEND) # ${TRACY_INCLUDE_DIRECTORIES})
get_target_property(deTracing_INCLUDE_DIRECTORIES deTracing INTERFACE_INCLUDE_DIRECTORIES)
message("deTracing INCLUDE_DIRECTORIES: ${deTracing_INCLUDE_DIRECTORIES}")
add_library(TestTarget INTERFACE)
target_link_libraries(TestTarget INTERFACE deTracing)
get_target_property(TestTarget_INCLUDE_DIRECTORIES TestTarget INTERFACE_INCLUDE_DIRECTORIES)
message("TestTarget INCLUDE DIRECTORIES: ${TestTarget_INCLUDE_DIRECTORIES}")
This snippet produces the following output
[cmake] deTracing INCLUDE_DIRECTORIES: $<$<CONFIG:Release>:/home/seddi/.conan/data/tracy/0.9/_/_/package/913e5b8c3a7b64b23fdaa63b58e3915a742a1112/include>
[cmake] TestTarget INCLUDE DIRECTORIES: TestTarget_INCLUDE_DIRECTORIES-NOTFOUND
which shows that deTracing is able to set the correct INCLUDE_DIRECTORIES for the Release config, but then is unable to set them on TestTarget, even though deTracing is an IMPORTED target.

Get cmake to find a custom config file

A cmake project I want to build depends on SDL2, and it comes with the following instruction:
Create a helper called /usr/local/lib/cmake/SDL2/sdl2-config.cmake (because SDL2 doesn't have an SDL2::SDL2 alias) containing:
if(NOT TARGET SDL2::SDL2
AND EXISTS "/usr/lib/x86_64-linux-gnu/cmake/SDL2/sdl2-config.cmake")
include(/usr/lib/x86_64-linux-gnu/cmake/SDL2/sdl2-config.cmake)
add_library(SDL2 SHARED IMPORTED)
set_target_properties(SDL2
PROPERTIES
IMPORTED_LOCATION "${libdir}/libSDL2.so"
INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}"
)
add_library(SDL2::SDL2 ALIAS SDL2)
endif()
The problem is that this file isn't found by my cmake (I put a message(...) at the beginning to verify this). If I change the dependency in my CMakeLists.txt from SDL2::SDL2 to just SDL2, it works fine and reads from /usr/lib/x86_64-linux-gnu/cmake/SDL2/sdl2-config.cmake. But this shouldn't be necessary.
How can I get cmake to find this custom file, or how do I find out where to put it?

Zephyr / PlatformIO / CMake / external code

I'm pretty new to Zephyr and am having trouble adding and compiling code in a sibling folder. This may be further complicated by using PlatformIO, which has a slightly different build structure than the stock Zephyr structure.
The IDE is Visual Studio Code under Windows
The structure of the code is:
Parent Folder
|-ext_library (contains CMakeList.txt)
|--source
|--include
|-zephyr_project (structure generated by PlatformIO)
|--zephyr (contains the master CMakeList.txt and prj.conf)
|--source
|--include
|--lib
What I want to do is add either source files or a static library from ext_library to the zephyr_project with out manually copying source / include files or manually building the library and copying it over.
What I've tried so far:
Adding a path to ext_library in the FILE(GLOB ...) command in the zephyr_project/zephyr/CMakeList.txt. This command pulls the
source files from zephyr_project/source, but doesn't seem to like
either relative or static paths to ext_library.
Adding a CMakeList.txt in the ext_library that compiles a static library. This also requires using add_subdirectory to the
zephyr CMakeLists.txt file. This didn't seem to compile the library,
however, it appears to have found the ext_library/CMakeLists.txt.
The evidence of this is in zephyr_project/lib folder which has some CMake folders that are empty but named the same as
the ext_library/CMakeLists.txt. Other evidence is that the
message(...) commands in both CMakeLists.txt are being printed.
Using both static and relative paths to the ext_library folder.
Using cmake FILE(COPY ...), the files weren't copied. No apparent error.
What has worked:
Manually copying code from the ext_library/source and ext_library/include into the appropriate folders in zephyr_project.
Additional info:
zephyr_project/zephyr/CMakeLists.txt (original + attempt at adding the ext_library as a subdirectory)
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(firmware)
set(EXT_LIB "C:/Users/mcelr/Desktop/project/ext_library")
add_subdirectory(${EXT_LIB} ${PROJECT_SOURCE_DIR})
FILE(GLOB app_sources
"../src/*.c*"
)
ext_library/CMakeLists.txt (CMAKE_CURRENT_SOURCE_DIR does point to the correct directory at runtime, as confirmed via removed message(...) logging)
cmake_minimum_required(VERSION 3.13.1)
project(ext_lib)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
set(LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build)
add_library(ext_lib_zephyr STATIC
${CMAKE_CURRENT_SOURCE_DIR}/source/packet.c
${CMAKE_CURRENT_SOURCE_DIR}/source/checksum.c
)
Thank you so much for any advice or hints to solve this,
Austin
I found workaround for it:
cmake_minimum_required(VERSION 3.13.1)
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(Project_work_queue)
SET(LIB_PATH ../../libs/)
FILE(GLOB lib_sources ${LIB_PATH}*.*)
FILE(COPY ${lib_sources} DESTINATION ../../../src/libs_tmp)
FILE(GLOB app_sources ../src/*.c*)
include_directories(${LIB_PATH})
target_sources(app PRIVATE
${app_sources}
)
And add src/libs_tmp to .gitignore. I know it is ugly way but it works :-P

Use target_link_libraries to libraries not start with lib*

I am trying to link my program(hello) with a special library(/path/abc.so) that not starts with 'lib'.
Here is my CMakeLists.txt
add_executables(hello hello.c)
target_link_libraries(hello /path/abc.so)
It works fine, but is there any other way to avoid this full path(/path/abc.so) things?
I don't want to make symlink of abc.so or modify abc.so itself.
Probably your best option is not to link directly the library, but use imported targets:
You can have your library target as
add_library(ABC SHARED IMPORTED)
set_target_properties(ABC PROPERTIES
IMPORTED_LOCATION path/to/library/abc.so
INTERFACE_INCLUDE_DIRECTORIES path/to/include
)
Then you can link it as a target:
target_link_libraries(hello ABC)
The next step would be to have a library find module, or config module, so you don't define full path in your CMakeLists.txt, but search for the library, or just include a .cmake file with all of the paths.
Have a look HERE and HERE

How can I create a target for an _existing_ library?

In CMake, we can add_library(mylib file1.cpp file2.cpp) and have a mylib.a in the library path get built. We can also target_include_directories(mylib INTERFACE some/directory), which effects targets depending on mylib.
But what if I have a library to begin with, which I will not be compiling. How can I add a target relating to it? That what I add as a dependency, will cause the .a file to be linked against, and for which I can set target_include_directories() ?
Note: I'm asking about CMake 3.x.
CMake provide an alternate signature for libraries that are already compiled:
add_library(
mynamespace::mylib
STATIC # or it could be SHARED
IMPORTED
)
See the official CMake documentation for more details.
with that you'll be able to add properties to the target doing so
set_target_properties(
mynamespace::mylib
PROPERTIES
IMPORTED_LOCATION "path/to/libmylib.a"
)
Little precision here, if you're using a Windows DLL, you must pass the DLL file's path in IMPORTED_LOCATION and set another property IMPORTED_IMPLIB that points to the .lib file, (not very handy).
Note that there is also a equivalent properties per configuration (Debug, and Release), that will need another property to be set (IMPORTED_CONFIGURATION), e.g. IMPORTED_LOCATION_DEBUG.
See also here and here in the documentation.
To avoid missing include files you can also precise the include directory using INTERFACE_INCLUDE_DIRECTORY property
set_target_properties(
mynamespace::mylib
PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "path/to/mylib/include"
)
With this, upon link declaration using target_link_libraries(), CMake will read information of the imported target and will add include directories implicitly.
Official documentation reference.