I have a cmake project with an application and a library. The library has one header file generated with configure_file. The problem is that the application code cannot find the generated header file.
What is the proper way to include the generated header file path to the application -I options? target_link_libraries adds the path, but to the source but not to the binary directory?
Is it possible to add a property to the library when add_library is used so that this property can be used when target_link_libraries is used?
If you have generated your header file with
configure_file(config.h.in config.h #ONLY)
and have your library target already created with
add_library(libtarget ${SOURCE_FILES})
it's simply a call to
target_include_directories(libtarget PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
under the assumption that all commands are given in this order and are located in the same CMakeLists.txt file.
Related
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?
I have created a very simple cmake project for testing cmake features. The project directory contains two libraries. I would like to export MyLibA include path.
The main CMakeLists.txt:
cmake_minimum_required(VERSION 3.11)
project(TestProject)
add_subdirectory(MyLibA)
add_subdirectory(MyLibB)
MyLibA CMakeLists.txt:
add_library(MyLibA SHARED)
target_sources(MyLibA PRIVATE fileA.h fileA.cpp)
target_include_directories(MyLibA INTERFACE "${CMAKE_SOURCE_DIR}/MyLibA")
MyLibB CMakeLists.txt:
add_library(MyLibB SHARED)
target_sources(MyLibB PRIVATE fileB.h fileB.cpp)
target_link_libraries(MyLibB PRIVATE /home/user/MyProjects/CmakeTestProject/build/MyLibA/libMyLibA.so)
I have exported an include path using INTERFACE keyword but the following include in fileB.h:
#include "fileA.h"
is not found. What am I doing wrong ?
What am I doing wrong?
Several things:
Never put absolute paths in your CMakeLists.txt and always link to targets rather than library files.
# Linking to a target propagates usage requirements, like include paths.
target_link_libraries(MyLibB PRIVATE MyLibA)
CMAKE_SOURCE_DIR is not what you think. It refers always to the top-level build directory, which is a bad assumption if your project might be an add_subdirectory or FetchContent target. Your usage can be replaced by:
# Not optimal, see below.
target_include_directories(MyLibA INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}")
Missing $<BUILD_INTERFACE:...> on include path, if you intend to export your targets. When targets are exported, their properties are copied verbatim to the output. Not guarding the local include path with $<BUILD_INTERFACE:...> will break users of the exported target.
target_include_directories(
MyLibA
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
)
Instead of
target_link_libraries(MyLibB PRIVATE <path/to/MyLibA/file>)
use
target_link_libraries(MyLibB PRIVATE MyLibA)
This is how CMake is intended to be used: when link with the library target, CMake automatically transforms that into the path and actually propagates all interface properties of the target.
Let's assume I have a project with a series of libraries. I also need to generate a header file that will be used by all of these projects. So I created a CMake file, like this:
project(main)
add_subdirectory(sub_1)
add_subdirectory(sub_2)
# ...
add_subdirectory(sub_n)
add_custom_command(
OUTPUT CustomHeader.h
COMMENT "Generating custom header for all the libraries"
COMMAND ...)
add_library(${PROJECT_NAME} STATIC ${OBJECT_LIST})
The problem is, that I don't know how to tell CMake to run my custom command (that generates this CustomHeader.h) before it would try to build the libraries in the subfolders.
I tried add_custom_target(TARGET MyPrebuild PRE_BUILD ...) but I'm running on Linux, and this option only works on Windows platform according to the documentation.
add_dependencies only work between targets, and not a target and a single file.
I could, in theory, add the header to be among the source files of the individual libraries (in the sub_1, .., sub_n folders) but it feels wrong, as the header is not required to be part of those libraries.
So I just have no idea how I can make a library depend on an include file, that is not part of it.
Any tips how I can overcome this problem?
For make header file (re)built before a library in subdirectory is compiled, you may create target, which builds the file, and make the library dependent from the target:
# *CMakeLists.txt*
# ...
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h ...)
add_custom_target(generate_custom_header DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h)
# *sub/CMakeLists.txt*
# ...
add_library(libA ...)
add_dependencies(libA generate_custom_header)
Instead of using add_dependencies, you may create header-only library which "implements" you header and link with it:
# *CMakeLists.txt*
# ...
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h ...)
add_custom_target(generate_custom_header DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h)
add_library(libCustom INTERFACE) # Header only library
add_dependencies(libCustom generate_custom_header) # which depends on generated header
# You may even assign include directories for the header-only library
target_include_directories(libCustom INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
# *sub/CMakeLists.txt*
# ...
add_library(libA ...)
target_link_libraries(libA libCustom) # Common linking with a header-only library.
Note, that INTERFACE library is a "fake" - it is never created by itself. Instead, all "features" of INTERFACE library are just propagated to its users.
I would suggest to add another library target that will both keep track of the generated headers and will help to properly configure other libraries to know where to find them (i.e. target_include_directories).
cmake_minimum_required(VERSION 3.0)
project(testable)
set(CustomHeaderInPath ${CMAKE_CURRENT_SOURCE_DIR}/CustomHeader.example)
set(CustomHeaderPath ${CMAKE_CURRENT_BINARY_DIR}/CustomHeader.h)
add_custom_command(
OUTPUT ${CustomHeaderPath}
COMMAND cp ${CustomHeaderInPath} ${CustomHeaderPath}
COMMENT "Generated file"
DEPENDS ${CustomHeaderInPath})
add_library(CustomHeaderLibrary ${CustomHeaderPath})
target_include_directories(CustomHeaderLibrary PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
set_target_properties(CustomHeaderLibrary PROPERTIES LINKER_LANGUAGE C)
add_library(LibA a.c)
target_link_libraries(LibA CustomHeaderLibrary)
add_library(LibB b.c)
target_link_libraries(LibB CustomHeaderLibrary)
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} PUBLIC LibA LibB)
Note that I had to explicitly set the LINKER_LANGUAGE of the new target as cmake won't be able to deduce it properly if no c or cpp files are added to the library.
How to tell CMake that directory is generated so that it doesn't complain before building process that directory doesn't exist?
My library project is used by many clients and for every client I have client-specific configuration generated by scripts and placed into generated/[client-name]/generated.h header. So for every client there's is folder generated. But parent project source files (*.cpp) include just generated.h. I wanted to add generated/[client-name] interface include directory for my library by using:
set_target_properties(mylib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "generated/myclient" ...)
but CMake complains even before starting compilation - Imported target "xxx" includes non-existent path. So I guess CMake doesn't like that include directory is missing when it starts building process although target depends on other targets which should create correct directory & header file within it.
You can create the directory first with CMake:
file(MAKE_DIRECTORY "generated/myclient")
This will have no effect if the directory exists already.
Given I have defined an executable with its main source file in a CMakeList.txt file:
ADD_EXECUTABLE(MyExampleApp main.cpp)
Can I add further source files to this executable after this line but in the same or an included CMakeList.txt file?
Use target_sources, available since cmake 3.1
eg.
target_sources(MyExampleApp PRIVATE ${extra_file})
https://cmake.org/cmake/help/v3.1/command/target_sources.html
I think you may use:
add_executable(MyExampleApp main.cpp)
add_library(library STATIC ${ADDITIONAL_SOURCES})
set_target_properties(library PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(MyExampleApp library)
It should be noted that for more recent versions of CMake (> 3.1 I think) one can append files to the SOURCES property on targets.
http://www.cmake.org/cmake/help/v3.3/prop_tgt/SOURCES.html