Include particular header files in a cmake project with absolute paths - c++

to start with, I have the following repo structure.
root
|
|--- blocks
| |
| |---example
| |
| |---example.cpp
| |---CMakeLists.txt
|
|--- interfaces
|
|--- types
|
|-- types1.h
|-- types2.h
|-- CMakeLists.txt
What I would like to do is to only include types1.h in the cmake target of example.cpp. And I would like to include types1.h such that I can include it in example.cpp using its path relative to root (i.e. #include "interfaces/types/types1.h") and I don't want to use include_directories(${CMAKE_SOURCE_DIR}) since that would expose the whole repo to the target.
target_include_directories did not work since it only includes directories but not individual files and I don't want to include a whole directory and expose irrelevant headers in types folder to example.cpp or move types1.h to a dedicated subfolder.
Do you have any suggestions on how to achieve this?
My current solution is as below which gives fatal error: interfaces/types/types1.h: No such file or directory when I compile exampleblock target. (I eased the requirements for start and allowed interface_types target to include types2.h also even though example.cpp doesn't need it)
blocks/example/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
add_library(exampleblock STATIC
example.cpp
)
target_link_libraries(exampleblock INTERFACE
${CMAKE_SOURCE_DIR}/interfaces/types:interface_types
)
interfaces/types/CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
add_library(interface_types INTERFACE)
target_include_directories(interface_types INTERFACE .)

Related

Add header-only library to executable in CMake

I am trying to include the Windows GNU GSL headers-only library (downloaded from https://gnuwin32.sourceforge.net/packages/gsl.htm) to an example code in C++ but have lots of errors unfortunately.
Here is the structure of my repository:
folder/
gsl/
gsl_sf_bessel.h
gsl_mode.h
*.h # other header files
main.cpp
CMakeLists.txt
main.cpp is as such:
#include <stdio.h>
#include <gsl_sf_bessel.h>
int main (void)
{
double x = 5.0;
double y = gsl_sf_bessel_J0 (x);
printf ("J0(%g) = %.18e\n", x, y);
return 0;
}
and CMakeLists.txt:
cmake_minimum_required(VERSION 3.0.0)
project(demoproject VERSION 0.1.0)
add_executable(
demoexecutable
main.cpp
)
target_include_directories(
demoexecutable
PUBLIC
gsl/
)
The error I get when compiling is main.cpp is:
fatal error: gsl/gsl_mode.h: No such file or directory
[build] 26 | #include <gsl/gsl_mode.h>
It looks like it managed to find gsl_sf_bessel.h from gsl/ but gsl_sf_bessel.h needs in its turn gsl_mode.h which the compiler cannot find. Any ideas on how to solve this issue?
I tried different combinations in CMakeLists.txt of functions such as add_library, include_directories, target_link_libraries but nothing worked unfortunately.
Try adding ${CMAKE_CURRENT_SOURCE_DIR} as an include directory. That is the directory that contains gsl/gsl_mode.h. The gsl directory does not contain itself, so adding it as an include directory will not make that error go away.
I've adopted the following practice in my CMake projects:
1) Project's folder structure.
Have an include/${PROJECT_NAME} subfolder (i.e., include subfolder and, within that, another subfolder named after the project's name). For example, in your case:
demoproject_or_whatever
|- include
| \- demoproject
| \- gsl
| |- gsl_sf_bessel.h
| \- gsl_mode.h
|- src
\- test
2) src/CMakeLists.txt.
Set an include_dir var at the top of the file, then use it when setting the executable's target_include_directories.
set(include_dir ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME})
add_executable(${PROJECT_NAME} ${app_sources})
target_include_directories(${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${include_dir}>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
3. Including header files from source files.
Use paths relative to include/${PROJECT_NAME}.
#include <gsl/gsl_sf_bessel.h>

Dependent sibling subdirectories in CMake

My current project has the following structure:
root
|- parser
| |- include // a directory for headers
| |- src // a directory for sources
| |- parser.yy
| |- scanner.ll
| |- CmakeLists.txt
|
|- preprocessor
| |- include // a directory for headers
| |- src // a directory for sources
| |- CmakeLists.txt
|
|- main.cpp
|- CMakeLists.txt
Now I want to start generating assembly codes. I have to use staticstack and codegen (are classes which are going to be defined) in the parser.yy and in srcfolder of the parser foler.
I cannot figure out how to do that.
What's the best practice in CMake to do this ?
Should I make subdirectories named semstack and codegen in parser folder ? This doesn't seem correct to me since as a CMake project gets larger the hierarchy will get deeper and if more dependencies are there then it would be a mess.
Should I make these subdirectories in the root ? If then what is the syntax in CMake to use sibling subdirectory ?
If then what is the syntax in CMake to use sibling subdirectory ?
There is no special syntax for this since normal (i.e. not IMPORTED) targets are global. If you define a library in one subdirectory, it may be used in any other via target_link_libraries.
For instance:
# parser/CMakeLists.txt
add_library(parser ...)
add_library(proj::parser ALIAS parser)
target_include_directories(
parser PRIVATE "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")
target_link_libraries(
parser PRIVATE proj::semstack proj::codegen)
The code for other subdirectories is similar.
# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.22)
project(proj)
add_subdirectory(semstack)
add_subdirectory(codegen)
add_subdirectory(parser)
add_subdirectory(preprocessor)
add_executable(main main.cpp)
target_link_libraries(
main PRIVATE proj::parser proj::preprocessor)
I create and link to ALIAS targets to avoid a typo in a target name being forwarded to the linker verbatim (names with :: in CMake are always considered targets and this is validated at generation time).

Including my libraries without a full path

The project has the following structure:
.
|- CMakeList.txt
`- src
|- lib
| |- CMakeList.txt
| `- libA
| |- CMakeList.txt
| |- libA.c
| `- libA.h
`- main
|- CMakeList.txt
`- main.c
and I want to include the libA.h file in main.c using #include "libA.h", but an error occurs when trying to compile fatal error: hello.h: No such file or directory. Can I make cmake add the appropriate include flags and I could write #include "libA.h".
I understand that I can manually add flags like -Ipath/to/src/lib/libA -Ipath/to/src/lib/libB ..., but I would like to automate this process.
Include_directories should solve that for you:
https://cmake.org/cmake/help/v3.0/command/include_directories.html
You can use the built-in PROJECT_SOURCE_DIR CMake variable to access the root source directory of your project. Use this with target_include_directories() to use #include "libA.h" in main.c:
In your src/main/CMakeLists.txt:
add_executable(MyMain main.c)
target_include_directories(MyMain PUBLIC ${PROJECT_SOURCE_DIR}/src/lib/libA)
You want to set your target_include_directories in your libA/CMakeLists.txt. After the target is built with add_library, you want to add the following instruction:
add_library(libA libA.c libA.h)
target_include_directories(libA PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
This instruction will specify that libA and any target that links to it also considers ${CMAKE_CURRENT_SOURCE_DIR} as a path to look for includes. This is known as a library's public header. Ideally, you would want those header files to be in their own subdirectory so you could include them easily to your other projects, without having the libA.c file be in the include directory. For example:
.
|- CMakeList.txt
`- src
|- lib
| |- CMakeList.txt
| `- libA
| |- CMakeList.txt
| |- include
| | `-libA.h
| |- src
| `- libA.c
`- main
|- CMakeList.txt
`- main.c
Solved.
If I create library
add_library(MyLib src/MyLib.cpp include/MyLib.h)
target_include_directories(MyLib PUBLIC include)
then I can write
add_executable(MyExe ${SOURCES} ${HEADERS})
target_link_libraries(MyExe MyLib)
The last line will automatically add the flag '-I/path/to/MyLib/include' when compiling MyExe.

CMake: Build and install locally stored submodule

There are numerous similar questions on Stack Overflow, but none come near to answering my question.
I have a C++ library built using CMake:
mylib
| - CMakeLists.txt
| - src/
| | - m.h
| | - m.cpp
| - include/
| | - mylib/
| | | - a.h
| | | - something/
| | | | - some.h
| - cmake/
| - mylibConfig.cmake.in
| - mylibConfigVersion.cmake.in
I then create another library or executable which includes the aforementioned library:
myapp
| - CMakeLists.txt
| - src/
| | - main.cpp
| - include/
| | - myapp/
| | | - b.h
| - libs
| | - mylib
And would like to use mylib within myapp like so. Please take notice how mylib headers are included in a directory like format:
#include <mylib/a.h>
#include <mylib/something/some.h>
mylib should be built when building myapp so that the following works without any other build steps:
$ cd myapp/build
$ cmake ..
$ make
Here is a list of some of the Stack Overflow posts I have reviewed. I have attempted each, and they simply do not work:
CMake: How to build external projects and include their targets
CMake ExternalProject_Add() and FindPackage()
Assuming in the project described, only header files in the mylib/include directory are to be considered public:
The top-level CMakeLists.txt for mylib needs to contain:
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
project(mylib VERSION 0.1 LANGUAGES CXX)
add_library(${MyLibName} ${MyLib_SOURCES})
target_include_directories(${MyLibName}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
This ensures that projects including mylib will only have access to files in the include/ directory. Files in include/ can be used like #include <myfile.h> and files in include/mylib (the general convention) can be used like #include <mylib/myfile.h>.
The top-level CMakeLists.txt for myapp should include:
cmake_minimum_required(VERSION 3.13 FATAL_ERROR)
project(myapp VERSION 0.1 LANGUAGES CXX)
add_subdirectory(libs/mylib)
add_executable(${MyAppName} ${MyApp_SOURCES})
target_link_libraries(${MyAppName} ${MyLibName}
The use of add_subdirectory ensures that mylib will be built before myapp and target_link_libraries adds mylib to the executable.
As mentioned by Tzalumen, make sure you take a look at the CMake tutorials and prefer the use of cmake --build . instead of make.
So, I actually do this in one of my projects.
First, the library needs to be built with ADD_LIBRARY(), but I'm assuming you do that. Something like
ADD_LIBRARY (${MyLibName} ${SOURCES}) in the library's CMakeLists.txt
That adds the library into cmake's list of libraries.
Second, you add the library to your project with
target_link_libraries (${PROJECT_NAME} ${MyLibName}) in the executable's CMakeLists.txt, the same one where you have your add_executable (${PROJECT_NAME} ${SOURCES})
That will set up the dependency chain to force MyLibName to explicitly build before PROJECT_NAME.

cmake errors: Cannot find source file

I'm trying to use cmake for the first time and I'm having a hard time getting this to work. There's a source file and a library file (Lab_4.cpp and Trip_4.cpp, respectively) and they're both in the source folder (Lab_4). Here's what's in my cmake file so far:
cmake_minimum_required (VERSION 2.6)
project (Lab_4)
#add executable
add_executable(Lab_4 ${PROJECT_SOURCE DIR}/Lab_4.cxx)
target_link_libraries (Lab_4 ${EXTRA_LISTS})
#add libraries
add_library (${PROJECT_SOURCE_DIR}/Trip.cxx)
ls shows both files are in that folder. I'm really new to cmake so I'm sure I'm making an obvious mistake but I have no idea what it is. Any help would be appreciated!
cmake_minimum_required(VERSION 2.6)
project(Lab_4)
add_library(Trip_4 Lab_4/Trip4.cpp)
add_executable(Lab_4 Lab_4/Lab_4.cpp)
target_link_libraries(Lab_4 Trip_4 ${EXTRA_LISTS})
Your exact intentions are not completely clear, but the above are the simplest possible instructions according to your current question description.
Are you absolutely sure your CMake is version 2.6? You should update the version to whatever CMake you are currently using (type cmake --version to find out).
To add your sources to CMake project, you can use the aux_source_directory command. If your sources are in Lab_4 folder, then you can do the following:
project(Lab_4)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/Lab_4 LAB4_SOURCES)
add_executable(Lab_4 ${LAB4_SOURCES})
The CMAKE_CURRENT_SOURCE_DIR is the path of the directory where the current CMakeFiles.txt is. The example above won't build Trip_4.cpp as a library but use it as another source file together with Lab_4.cpp.
If you wish to build the Trip_4.cpp as library fist I recommend to separate it from Lab_4.cpp to make later uses easier. An example directory structure could be:
MyProject/
|-- app/
| |-- src/
| | `-- Lab_4.cpp
| |-- inc/
| `-- CMakeLists.txt
|-- lib/
| |-- src/
| | `-- Trip_4.cpp
| |-- inc/
| `-- CMakeLists.txt
`-- CMakeLists.txt
In this case the MyProject/lib/CMakeLists.txt will contain something like the following:
project(Trip_4)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src TRIP4_SOURCES)
add_library(Trip_4 ${TRIP4_SOURCES})
The MyProject/app/CMakeLists.txt will be almost the same as I showed in my first example, except now it has to maintain its dependency on Trip_4 library:
project(Lab_4)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/../lib
${CMAKE_CURRENT_SOURCE_DIR}/inc
)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/src LAB4_SOURCES)
add_executable(Lab_4 ${LAB4_SOURCES})
add_dependencies(Lab_4 Trip_4)
target_link_libraries(Lab_4 Trip_4)
Finally, the MyProject/CMakeLists.txt has to tie together the library and the executable subprojects as follows:
project(MyProject)
add_subdirectory(lib)
add_subdirectory(app)