How to include headers in CMake? - cmake

I am having trouble in linking header files to .c files. It will tell me "Cannot open include file: headerfile1.h : No such file directory"
My file structure looks like this
library
- folder1
-- include
--- headerfile1.h
--- headerfile2.h
--- CMakeLists.txt
-- CMakeLists.txt
- CMakeLists.txt
src
- file.c
- file.h
- CMakeLists.txt
CMakeLists.txt
I have read many posts about this and tried a lot. Originally, I tried to create a header-only library or using ${CMAKE_SOURCE_DIR} referencing from a few posts, but was unsuccessful. I would get the same error
Currently, I have this
Under the root CMakeLists.txt, I've added the subdirectories
add_subdirectory(src)
add_subdirectory(library/folder1/include)
Under the src CMakeLists.txt, I've included the directory
include_directories(library/folder1/include)
In file.h, I have
#include "include/headerfile2.h"
The CMakeLists.txt files I have under the library folder are empty. They were made so that add_subdirectory(library/folder1/include) could work

You need to add an interface library [1][2] in the library/folder1/include/CMakeLists.txt (or the parent one... I dunno what do you have in it and why you need another one in the include/).
This library gonna export include path via build interface (and probably install interface if you plan other projects gonna have this one as an external dependency to be found via find_package()).
So, your executable (or whatever) just needs target_link_library(my_exe PRIVATE my_header_lib) to get the proper #include path.
PS Please, forget about include_directories() and use only target_xxx() calls.

Related

Using Cmake to add compiler options to existing cmake

I have a submodule with a CMakeLists.txt, which I would like to "amend" in a way to make it work for my specific purpose (I need to add compiler flags and a different output directory) The output is a static library. My current approach is as follows:
I have a CMakeLists.txt in the root directory, which adds the submodule CMakeLists.txt via add_subdirectory() like so:
set(CMAKE_CXX_FLAGS "-my_needed_flags "
add_subdirectory(SubmoduleLibrary)
set_target_properties(SubmoduleLibrary PROPERTIES ARCHIVE_OUTPUT_DIRECTORY output_folder)
add_custom_target(BuildLib)
add_dependencies(BuildLib SubmoduleLibrary)
Now this seems to work in some ways (the output directory is correctly chosen). But I get linker errors which I don't get when I compile the library adding the flags etc to the original CMakeLists.txt.
What is the correct way to build a library from an existing CMakeLists.txt with added parameters?

Providing include directory outside source folder for static library users

I am developing a simple static C library for learning purposes using cmake.
Some projects like GLFW provide an include folder on the root, so library users can copy it and use it as an include directory.
In my library, I want to have an include folder on the root, so when I use the library on other projects, I can just copy this folder and set it as an include directory.
Here is a simplified folder structure of my library:
include
+--mylib.h
src
+--myheader.h
+--mysource.c
+--CMakeLists.txt
CmakeLists.txt
The src folder has my headers and implementation files, and a CMakeLists.txt for building a static library out of mysource.c.
The CMakeLists on the root folder just sets the project and adds src as a subdirectory.
I want the mylib.h file to have a #include <myheader.h>.
Here's a detour to talk about how I want to use it when it's done.
The idea is that when using the lib on another project, I can have something like this:
deps
+--include
+--mylib.h
src
+--main.c
And in the main.c file, include mylib.h and use what's defined on myheader.h
Here the detour ends, and I'm talking about my actual lib project again.
How can I achieve this using cmake? As far as I know, the mylib.h file needs to know it's including files from the src diretory, but I see no way of setting that, as for exemple in GLFW this directory does not have a CMakeLists.txt.
I am gonna quess that this is a design issue since it would make sense to you if you would have installed the library to a system before you tried to use it. That is, not using add_subdirectory() but find_library() at usage.
First, if you are using a external library, but not installing it, you would include all files in you deps-folder. All files then include source-files and so on and will be compiled besides you main.c. This is done with add_subdirectory(deps/MyLib) and later also included in you main-project.
Example:
add_subdirectory(deps/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
If you do not want to compile it all the time, then you must instruct cmake where it can find headers and library-files. Preferred way is to use find_library() which does some magic for you. Since you do not mention any installation i will assume that it does not exist and your only option is then to use add_subdirectory().
"I can just copy this folder and set it as an include directory."
CMake wants to handle these things for you so you should never copy headers around. You should either use add_subdirectory() to include a project/headers or make use of the find_library() which make sure you find where the headers are in the system.
I suggest that you push yourself to learn howto install a library into a system and how to utilize it later, but only by using find_library(). Then the library will be global for all projects and also not duplicated.
Adding some kind of psudo-code in hope it all makes more sense. Although it is around add_subdirectory() since the code for installing is quite large unfortunately.
CMakeLists.txt for main.c
cmake_minimum_required(VERSION 3.8)
project(MyLibTest)
add_executable(${PROJECT_NAME}
src/main.c
)
add_subdirectory(external/MyLib EXCLUDE_FROM_ALL)
target_link_libraries(${PROJECT_NAME} PRIVATE MyLib)
target_include_directories(${PROJECT_NAME} PRIVATE MyLib)
CMakeLists.txt for library
cmake_minimum_required(VERSION 3.8)
project(MyLib)
add_library(${PROJECT_NAME} STATIC
src/MyLib.c
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
The structure for the project would then be:
/
external/MyLib
external/MyLib/src
MyLib.c
external/MyLib/include
MyLib.h
src
main.c
CMakeLists.txt

The proper way to include variable with sources from .cmake file to CMakeList.txt

I have the following CMake problem.
The structure of my project is:
Project
--- libs
------ lib1
---------CmakeLists.txt
------ lib2
---------lib2.cmake
---------file1.c
---------file2.c
--- src
...
In my lib2.cmake I have:
set(LIB2_SOURCES
file1.c
file2.c
)
And I want to use ${LIB2_SOURCES} in my lib1 CMakeList.txt:
include(../lib2/lib2.cmake)
set(LIB1_SOURCES
....
)
add_library(media SHARED ${LIB1_SOURCES} ${LIB2_SOURCES})
But I'm getting this error:
Cannot find source file:
file1.c
If I change my lib2.cmake and fix the path like that:
set(LIB2_SOURCES
../lib2/file1.c
../lib2/file2.c
)
It works. But that's not a good way for me.
I can move lib2.cmake into the lib1 directory, but this is also not a good way for me.
So what is the proper way to deal with this include? Is there any way to include lib2.cmake without losing the path?
If you want to have paths which do not depend on the current directory, use absolute paths:
set(LIB2_SOURCES
${CMAKE_CURRENT_LIST_DIR}/file1.c
${CMAKE_CURRENT_LIST_DIR}/file2.c
)
CMAKE_CURRENT_LIST_DIR is the directory containing the CMake file currently being processed (which will be Project/libs/lib2 in your case when processing lib2.cmake).
However, instead of defining sources like this, you might also want to look into giving lib2 a proper CMakeLists.txt and defining an object library in it, and then adding that object library into the media library.

cmake: generated header in subdir A needed transitively by target in subdir B

So I'm transitioning from make to cmake and I'm stuck at a point which is trivial in make because of in-source-dir building.
The following scenario:
Directory A/ generates some header, A.h.
In order for other cpp/h, non-generated files to find the generated header, I've added the ${CMAKE_CURRENT_BINARY_DIR} as an include (<--assumption 1 here for being best approach)
However now in directory B/ (a sibling directory of A/) there is a particular source file which transitively through a file.h, which is also in A/, needs the generated A.h file.
The problem I face now is that file.h has the reference to A.h as #include "A.h" but at this point in the cmake execution the only include directories are:
B/
Now.. what is the best way to include A.h in directory B, should I hardcode something like: ${CMAKE_BINARY_DIR}/path/to/include/for/A/A.h that feels bad though
Another way is to generate the A.h file to the source dir, however I often see advise to not generate anything to the source directory.
You can use PROJECT_BINARY_DIR variable to set up location of generated file from different directories. Note that PROJECT_BINARY_DIR change every time you use project command. In this case you can use <PROJECT>_BINARY_DIR variable:
# CMakeLists.txt
project(Foo)
add_subdirectory(Boo)
# Boo/CMakeLists.txt
project(Boo)
message("Boo_BINARY_DIR: ${Boo_BINARY_DIR}") # == PROJECT_BINARY_DIR
message("Foo_BINARY_DIR: ${Foo_BINARY_DIR}") # != PROJECT_BINARY_DIR

Changing cmake directories

I'm writing a cmake file for a project which has the following structure
project/ (root)
libraries/ (contains (precompiled) libraries
src/
code/ (contains a set of fortran files)
My CMakeLists.txt file is currently in project/ and effectively is just
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (sc1 sc1.f90)
target_link_libraries(sc1 ${PROJ_LIBRARY})
This creates my binary in the same folder as the source code, when I actually want it in the level above (i.e. in the src folder - this structure will be changed so we have a bin folder eventually), but haven't worked out how to do it.
Some answers on SO say you have to have a CMakeLists.txt file in every folder - is this correct? Is it possible to set an environment variable or use a CMake variable (e.g. http://cmake.org/cmake/help/v2.8.8/cmake.html#command:set). It's also not very clear from some answers whether the solutions they have posted are C++ specific (as that is what language CMake most often seems to be used for).
Edit
I found out that I can change it to the behaviour I want by modifying it slightly:
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (src/sc1 ${projsrc}/sc1.f90)
target_link_libraries(src/sc1 ${PROJ_LIBRARY})
However, this doesn't explain why my behaviour is different to how it should be, according to arrowdodger below. I'm also still trying to work out how to display the values of environment variables; I've tried the following with no luck:
message(${RUNTIME_OUTPUT_DIRECTORY})
message($ENV{RUNTIME_OUTPUT_DIRECTORY})
message(${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
message($ENV{CMAKE_RUNTIME_OUTPUT_DIRECTORY})
By default, binaries will appear in respective subdirectory of your build dir. By respective i mean the directory that contains CMakeLists.txt with add_executable() call.
For example, if you have following CMakeLists.txt
add_executable(tgt1 src1.f90)
add_executable(tgt2 subdir/src2.f90)
in the root folder, you will get both binaries in ${CMAKE_BINARY_DIR}. So if you wish tgt2 to be in ${CMAKE_BINARY_DIR}/subdir, you need to add CMakeLists.txt there and call add_executable(tgt2 src2.f90) from there.
You can change this behavior:
CMAKE_LIBRARY_OUTPUT_DIRECTORY, CMAKE_RUNTIME_OUTPUT_DIRECTORY and others.
You can also set respective target properties.