I have a static library in my project, lets call it libcommon, and I am including a header file from this library #include <libcommon/common.h>, not the angular brakets, not upper quotes. How can I configure CMakeLists.txt so that it find the include?
Assume the directory structure is like this:
-- root/
\-- src/
| |-- libcommon/common.h
| \-- main/main.c
\-- CMakeLists.txt
I tried:
include_directories (... src)
and:
include_directories (... ${main_SOURCE_DIR}/src)
but the libcommon/common.h was not found.
I figured it out while writing the question:
Instead of using just include_directories, I had to use target_include_directories:
target_include_directories(main PRIVATE src)
or:
target_include_directories(main PRIVATE ${main_SOURCE_DIR}/src)
Related
I'm in a similar situation to Adding object-file dependencies where it is mentioned:
... I need some object files that are part of the same library to be compiled before others.
Don't try to declare dependencies between object files. If there are files that have a dependency, break them out into a separate library with add_library and then declare the dependency with add_dependencies and target_link_libraries. There is no extra cost for doing this. Particularly, consider looking at Object Libraries.
I tried to implement this in my original project, where I'm working with a massive CMakeLists.txt file, where include & linker paths may be conditionally inserted or removed, and I failed. In essence, that CMakeLists.txt file would looks like this simplified:
project(MY_PROGRAM C CXX ASM)
set(MY_PROGRAM_sources
main.c
file_one.c
file_two.c
)
add_executable(MY_PROGRAM ${MY_PROGRAM_sources})
target_include_directories(MY_PROGRAM PRIVATE
${CUSTOM_PATH}/src/custom/include
...
)
add_compile_options(-Wall
-Wno-format
...
)
target_link_libraries(MY_PROGRAM
somelib1
somelib2
)
This builds fine, using Unix Makefiles.
Now, I've tried to extract file_one and file_two objects like this:
project(MY_PROGRAM C CXX ASM)
set(MY_PROGRAM_sources
main.c
#file_one.c
#file_two.c
$<TARGET_OBJECTS:SEPFILE_OBJS>
)
add_library(SEPFILE_OBJS OBJECT
file_one.c
file_two.c
)
add_executable(MY_PROGRAM ${MY_PROGRAM_sources})
target_include_directories(MY_PROGRAM PRIVATE
${CUSTOM_PATH}/src/custom/include
...
)
add_compile_options(-Wall
-Wno-format
...
)
target_link_libraries(MY_PROGRAM
somelib1
somelib2
)
cmake passes fine here, but when I hit make, there is breakage as soon as file_one.c starts compiling:
...
[ 9%] Building C object CMakeFiles/SEPFILE_OBJS.dir/file_one.c.obj
In file included from C:/tmp/file_one.c:14:
C:/tmp/file_one.h:19:10: fatal error: ExoticHeader.h: No such file or directory
19 | #include <ExoticHeader.h>
Clearly, the SEPFILE_OBJS library did not inherit the include libraries nor other compilation/linker settings from the MY_PROGRAM executable.
I could probably repeat all target_* lines for SEPFILE_OBJS - but that looks quite unmanageable, plus my original CMakeLists.txt is huge, and I'd like to avoid that kind of work.
So is there a way to say to CMake "keep the same compilation and linker settings as in executable for MY_PROGRAM, also for the object library SEPFILE_OBJS"?
I would do it the way around. I would first define a library section, including file_one.c and file_two.c, and then a main executable section, which would link against this library target.
I would also follow something along the lines below for a directory structure (ideally, I would put the source files within a src directory):
/ MY_PROGRAM
|- include
| \- MY_PROGRAM
| |- file_one.h
| \- fine_two.h
|- file_one.c
|- file_two.c
|- main.c
\- CMakeLists.txt
Put your header files in an include/${PROJECT_NAME} folder, and set an include_dir var pointing to it.
set(include_dir ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME})
Define the list of library and application sources:
set(lib_sources
"${CMAKE_CURRENT_SOURCE_DIR}/file_one.c"
"${CMAKE_CURRENT_SOURCE_DIR}/file_two.c"
)
set(app_sources
"${CMAKE_CURRENT_SOURCE_DIR}/main.cpp"
)
Library section. Define a lib_MY_PROGRAM target, and set the include directories, compile options, and link libraries for it. Notice it's better to use the target_... specific commands than the more general ones, such as add_compile_options:
add_library(lib_${PROJECT_NAME} ${lib_sources})
target_include_directories(lib_${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${include_dir}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_include_directories(lib_${PROJECT_NAME} SYSTEM PUBLIC
${CUSTOM_PATH}/src/custom/include
)
target_compile_options(lib_${PROJECT_NAME} PRIVATE
-Wall
-Wno-format
)
target_link_libraries(lib_${PROJECT_NAME} PRIVATE
somelib1
somelib2
)
Main binary section:
add_executable(${PROJECT_NAME} ${app_sources})
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${include_dir}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
target_compile_options(lib_${PROJECT_NAME} PRIVATE
-Wall
-Wno-format
)
target_link_libraries(${PROJECT_NAME} PRIVATE lib_${PROJECT_NAME})
I have C++ source code in following hierarchy
main.cxx
CMakeLists.txt
someDirectory/myClass.cxx
someDirectory/myClass.h
My CMakeLists.txt is as follows
cmake_minimum_required(VERSION 2.8)
project(cmakePjt)
include_directories(someDirectory)
add_executable(cmakePjt main.cxx)
My main.cxx includes myClass as follows
#include "myClass.h"
And the above works! But I want to include myClass in my main.cxx as follows and how should I change my CMakeLists.txt for that?
#include "myLibName/myClass.h"
There is nothing CMakeLists can do. You have to actually create an existing actual directory with the name myLibName, move the .h file to that directory, and add the containing directory of that directory to include the search path.
Your project may look for example like this:
main.cxx
CMakeLists.txt
myLibName/src/myClass.cxx
myLibName/include/myLibName/myClass.h
myLibName/CMakeLists.txt
Where:
# myLibName/CMakeLists.txt
add_library(myLibName src/myClass.cxx)
target_include_directories(myLibName PUBLIC ./include)
# CMakeLists.txt
add_subdirectory(myLibName)
add_executable(cmakePjt mina.cxx)
target_link_libraries(cmakePjt PRIVATE myLibName)
I have a project that we will call proj.
It has a subproject call config which does not link to anything because we want to manage it separately from the primary image.
But config has some configuration files, lets call them sys_config.h and user_config.h, that define the structure that others need to access and to be clean about it, I want those stored with the config subproject.
Finally, there is a library, we will call lib that is included in proj. It needs to be able to reference those config include files.
So, the file structure is approximately like this:
proj
main
src
include
(this references and includes lib below)
config
src
sys_config.c
user_config.c
include
config
sys_config.h
user_config.h
mylib
src
mylib.c
#include <config/sys_config.h>
or
#include <sys_config.h>
include
mylib.h
Now, what do I put in lib's CMakeLists.txt to get it to be able to see sys_config.h?
For example, this does not work:
target_include_directories(mylib
PUBLIC include
PRIVATE "{$CMAKE_SOURCE_DIR}/config/include"
)
nor does this work:
target_include_directories(mylib
PUBLIC include
PRIVATE "{$CMAKE_SOURCE_DIR}/config/include/config"
)
nor does this:
target_include_directories(mylib
PUBLIC include
PRIVATE "config/include"
)
My hope was maybe if I go back to the top and include the full path to config/include it would find it but it doesn't.
I feel that I must have a complete misunderstanding of how target_include_directories() is supposed to work and what it is supposed to do for me.
Roger
With modern CMake, notion of a subdir / subproject is to be an independent library / executable. Each subproject (lib / exe) should define set of PUBLIC / PRIVATE headers. See - https://cmake.org/cmake/help/latest/command/target_include_directories.html. Rest dependent projects should just link with subproject libs. Inclusion of libs is internally managed by CMake.
Sample cmake files based on your directory layout (I have not tested them so treat them as reference purpose only).
Top level cmake file # proj/CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
project(main)
subdirs(config)
subdirs(mylib)
add_executable(hello main/src/main.c)
target_link_libraries(hello config mylib)
install(TARGETS hello DESTINATION bin)
config cmake file # proj/config/CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
add_library(config src/sys_config.c src/user_config.c)
target_include_directories(config PUBLIC include)
# uncomment if you have any internal headers within config/src
# target_include_directories(config PRIVATE src)
As best practice keep all your module config exposed headers at config/include/config/. This will make them to be imported as #include "config/sys_config.h" in mylib source files.
mylib cmake file # proj/mylib/CMakeLists.txt
cmake_minimum_required(VERSION 3.9)
add_library(mylib src/mylib.c)
target_include_directories(mylib PUBLIC include)
# uncomment if you have any internal headers in proj/mylib/src
# target_include_directories(mylib PRIVATE src)
target_link_libraries(mylib config)
When executing cmake to generate ctest inputs, how can I directly specify the destination directory for the cmake-generated CTestTestfile.cmake? Specifically, my test suite is an independent cmake project. I currently add it to the main cmake project with include(), but the more appropriate method is to use add_subdirectory(). However, add_subdirectory() installs CTestTestfile.cmake in the subproject's directory in the build directory, but I need it in build/ for ctest to find it.
I set up the test macros in a file CTestList.cmake which lives in the test_project. This file is included in the build in test_project/CMakeLists.txt:
include(CTest)
include(${CMAKE_CURRENT_LIST_DIR}/CTestList.cmake)
With include():
project/
|-- CMakeLists.txt
|-- src/
|-- test_project/
`-- build/
|-- CTestTestfile.cmake
`-- test_project/
With add_subdirectory():
project/
|-- CMakeLists.txt
|-- src/
|-- test_project/
`-- build/
`-- test_project/
`-- CTestTestfile.cmake
The include and the add_subdirectory commands of CMake are very different.
While the include command works like #include of C and C++ – loads the content of included file into the file where it appears –, the add_subdirectory adds a subdirectory to the build. This means that when you use the add_subdirectory the variables inside the subdirectory's CMakeLists.txt will be the part of a different scope and the value of CMAKE_CURRENT_BINARY_DIR variable will be different too. Just add the following line to the test_project/CMakeLists.txt and try either to include it or add it by add_subdirectory:
message(STATUS "The files will be generated into: " ${CMAKE_CURRENT_BINARY_DIR})
The enable_testing enables testing for current directory and below. So, when you used the add_subdirecory instead of include the current directory meant build/test_project/ – as explained above.
To make sure the CTestTestfile.cmake will be created in build directory too, simply add an extra enable_testing command to the top-level CMakeLists.txt.
I have a project with about 600 directories, containing the source for about a dozen libraries and several dozen programs. Some of the programs depend upon a C++ header file that is generated from a text file.
How do I cleanly tell CMake how to include that path to the generated header file into the include path for those source files which require it?
Or alternatively, how can I force the generated file to be installed into a known location before CMake attempts to compile those programs? (This idea is based on the current Makefile system, which generates the header and installs it into the /include directory where all source files can find it.)
Or is there some other alternative?
-- EDIT: added "toy" example --
This example does not work. I need a way to tell prog1 and prog2 where to find home.h.
My tree:
.
|-- prog1/
| |-- CMakeLists.txt
| `-- prog1.cpp
|-- prog2/
| |-- CMakeLists.txt
| `-- prog2.cpp
`-- share/
`-- dict/
|-- CMakeLists.txt
`-- gen.sh*
In share/dict:
cmake_minimum_required(VERSION 2.8.4)
project(dict)
set(SRC foo.c)
set(HEADERS foo.h home.h)
add_custom_target(home
ALL
DEPENDS ${CMAKE_INSTALL_PREFIX}/include/home.h
)
add_custom_command(
OUTPUT ${CMAKE_INSTALL_PREFIX}/include/home.h
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/gen.sh gen.sh
COMMAND gen.sh ${CMAKE_INSTALL_PREFIX}
)
add_library(dict ${SRC})
install(TARGETS dict DESTINATION lib)
install(FILES ${HEADERS} DESTINATION include)
In prog1 (and similarly in prog2):
cmake_minimum_required(VERSION 2.8.4)
project(prog1)
add_executable(prog1 prog1.cpp)
target_link_libraries(prog1 dict)
install(TARGETS prog1 DESTINATION bin)
After
add_library(dict ${SRC})
add
target_include_directories(dict
# The location of the headers before installation
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
# The location of the headers after installation
$<INSTALL_INTERFACE:include>
)
and read the link I already provided in the comment.
Outputting generated files into out-of-source build directory is an intended way to do it.
Use CMAKE_BINARY_DIR and CMAKE_CURRENT_BINARY_DIR as output prefix and as target_include_directories() argument.