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>
Related
I have multiple projects (subdirectories) inside my repository. All projects have only one executable file named main.cpp and they all use libraries from the common folder with #include statements. The folder structure looks like this:
root
|
├────common
| ├──── example.h
| ├──── example.cpp
| ├──── *.h # many header files
| └──── *.cpp # many source files
|
├────Project_A
| ├──── CMakeLists.txt
| └──── main.cpp
|
├────Project_B
| ├──── CMakeLists.txt
| └──── main.cpp
|
└──── CMakeLists.txt
This is my attempt at writing the root's CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
project ("root")
file(GLOB_RECURSE CommonLibs ${CMAKE_SOURCE_DIR}/common/*.cpp)
link_libraries(${CommonLibs})
add_subdirectory ("Project_A")
add_subdirectory ("Project_B")
Project_A's CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
add_executable (Project_A "main.cpp")
Project_B's CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
add_executable (Project_B "main.cpp")
However when running any of the projects I get this error:
LNK1107 invalid or corrupt file: cannot read at 0x7AC, file example.h
I don't believe the file is corrupted because before I tried to use link_libraries() in root's CMakeLists.txt I was getting other error:
Unresolved external symbol SomeNamespace::ExampleClass::ExampleClass(bool)
Possible duplicates
Other questions such as this one don't solve my problem because they usually work with a more complex folder structure. Also there are questions that attempt to target only single project like this one, but I have multiple projects.
Can you please provide a concise solution?
Add a CMakeLists.txt to your common/ directory:
root
|
├────common
| ├──── CMakeLists.txt <-------- Add this
| ├──── example.h
....
common/CMakeLists.txt
file(GLOB_RECURSE CommonLibsFiles ${CMAKE_CURRENT_SRC_DIR}/*.cpp)
add_library(CommonLibs ${CommonLibsFiles})
...
root's CMakeLists.txt
...
### NO NEED FOR THESE
file(GLOB_RECURSE CommonLibs ${CMAKE_SOURCE_DIR}/common/*.cpp)
link_libraries(${CommonLibs})
###
add_subdirectory(common) #CommonLibs will now be visible to children directories
...
Now link the libraries as required. For example for project A:
Project_A's CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
add_executable (Project_A "main.cpp")
target_link_libraries(Project_A PRIVATE CommonLibs) #link to common libs here,
All the targets/variables that are created or are visible to parent cmake file, are visible to children. The reverse is not true though. For children to expose their variables to parent, they need to explicitly specify PARENT_SCOPE
The following lines in your top-level CMake do not make much sense:
file(GLOB_RECURSE CommonLibs ${CMAKE_SOURCE_DIR}/common/*.cpp)
link_libraries(${CommonLibs})
The link_libraries() command accepts libraries or library targets, not variables (such as CommonLibs). You can use the CommonLibs variable to define a new library target, then link the library target to your executables using link_libraries():
file(GLOB_RECURSE CommonLibs ${CMAKE_SOURCE_DIR}/common/*.cpp)
# Add this line.
add_library(MyCommonLib SHARED ${CommonLibs})
link_libraries(MyCommonLib)
Please note that the use of link_libraries() in general is discouraged, even in CMake documentation itself. You should prefer linking your MyCommonLib to the specific executables that require it using target_link_libraries.
target_link_libraries(Project_A PRIVATE MyCommonLib)
For my research project I am setting up a project (coom) to benchmark a set of algorithms on a data structure. For unit testing I settled on Bandit, which leaves me with a project structure that looks as follows:
+ root
|-- CMakeLists.txt
|-+ external/
| \-- bandit/
|-+ src/
| |-- CMakeLists.txt
| |-- node.cpp
| \-- node.h
\-+ test/
|-- CMakeLists.txt
|-- test.cpp
\-- test_node.cpp
From my experience with other languages, this seems to me a standard project structure? The test/ folder contains unit tests for the logic in src/ and no dependencies are intermixed with the source and test code, but are instead in external/.
The testing files I want to look as follows (with irrelevant parts removed)
// test/test.cpp
#include <bandit/bandit.h>
(...)
#include "test_node.cpp"
int main(int argc, char* argv[]) {
(...)
}
// test/test_node.cpp
#include <coom/node.h>
(...)
But my problem is, that when I try to compile with cmake .. and the subsequent Makefile, they are unable to find the source code in src/ where I get the compiler error:
fatal error: coom/node.h: No such file or directory.
I would expect the test/CMakeLists.txt should look somewhat like the following:
# test/CMakeLists.txt
add_executable (test_unit test.cpp)
target_link_libraries(test_unit coom)
I cannot figure out how to setup the CMakeLists.txt and src/CMakeLists.txt to ensure I get the desired outcome above. Currently they look as follows:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project (coom VERSION 0.1)
# ============================================================================ #
# Dependencies
(...)
# ============================================================================ #
# COOM project
add_subdirectory (src)
add_subdirectory (test)
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
node.h
)
set(SOURCES
node.cpp
)
add_library(coom ${HEADERS} ${SOURCES})
I can see from other projects, that it is possible to link the src/ directory with some libname/ prefix, but I cannot discern from their CMakeLists.txt files what I am doing wrong. I have looked at writing a coom.pc.in file and providing an install-target, and tried to set_target_properties with either FOLDER coom or PREFIX coom, but neither worked. I can hack an include_directory(../src) into the test/CMakeLists.txt to be able to include the file via an #include <node.cpp>, but that screams I'm doing something inherently wrong.
I'm at this point very much pulling my hairs out, and the CMake documentation is of very little help to me.
Your coom target has no include directories defined. You can define the include directories to use for this target (with target_include_directories()), and propagate these include directories so they are visible to the consuming test_unit target (by using PUBLIC):
# src/CMakeLists.txt
# ============================================================================ #
# Link up files for the library
set(HEADERS
node.h
)
set(SOURCES
node.cpp
)
add_library(coom ${HEADERS} ${SOURCES})
target_include_directories(coom PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Furthermore, the file path to the node.h header is coom/src/node.h, not coom/node.h. But, because you now have coom/src as an public include directory, you can use the following to include the node.h header in your test file:
#include <node.h>
I am trying to learn CMake and for that purpose I am working with an example project of the structure shown below. I am trying to configure all the CMakeLists.txt files such that after make install I can copy the resulting build directory and copy-paste it around freely such that other people are able run the executable.
Problem: after running make install (maxOS 10.14.6 (Darwin 18.7.0)) everything works if I run the executable inside build BUT if I move the build directory from its original location - for example to Desktop - the executable is unable to find the shared libraries. It seems that the reason for this is that the paths to the shared libraries are defined as absolute paths instead of relative paths with respect to the build directory.
Question: How can I build the project such that the executable finds the shared libs?
Project structure:
myapp
|
CMakeLists.txt (top-level)
- build
- app
| CMakeLists.txt (app)
| - inc
| - app
| app.h
| - src
| app.cpp
| main.cpp
|
- external
|
- mylib
CMakeLists.txt (mylib)
- inc
- mylib
mylib.h
- src
mylib.cpp
CMakeLists:
CMakeLists.txt (top-level)
cmake_minimum_required(VERSION 3.0)
project(myapp)
add_subdirectory(external/mylib)
add_subdirectory(app)
CMakeLists.txt (app)
# myapp program
cmake_minimum_required(VERSION 3.0)
project(myapp_prog)
set(SOURCES ./src/)
set(HEADERS ./inc/app/)
set(SOURCE_FILES
${SOURCES}/app.cpp)
set(HEADER_FILES
${HEADERS}/app.h)
# All sources that need to be tested in unit test go into a static library
add_library(myapp_lib SHARED ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories(myapp_lib PUBLIC ${HEADERS})
# The main program
add_executable(prog ./src/main.cpp)
target_include_directories(prog PUBLIC ./inc/)
# Link the libraries
target_link_libraries(prog PRIVATE myapp_lib mylib)
install(TARGETS myapp_lib DESTINATION ${CMAKE_BINARY_DIR}/lib)
CMakeLists.txt (mylib)
# mylib
cmake_minimum_required(VERSION 3.0)
project(mylib)
set(SOURCES src/)
set(HEADERS inc/mylib/)
set(SOURCE_FILES
${SOURCES}/mylib.cpp)
set(HEADER_FILES
${HEADERS}/mylib.h)
add_library(mylib SHARED ${HEADER_FILES} ${SOURCE_FILES})
target_include_directories(mylib PUBLIC inc/)
install(TARGETS mylib DESTINATION ${CMAKE_BINARY_DIR}/lib)
C++ code:
mylib.h
void mylib_print_hello();
mylib.cpp
#include "library.h"
#include <iostream>
void mylib_print_hello() {
std::cout << "Hello from mylib!" << std::endl;
}
app.h
void myapp_hello();
app.cpp
#include <iostream>
#include "app.h"
void myapp_hello()
{
std::cout << "Hello from myapp!" << std::endl;
}
main.cpp
#include <iostream>
#include "app/app.h"
#include "mylib/mylib.h"
int main()
{
myapp_hello();
mylib_print_hello();
}
I think the issue is that you might be confusing the build step with the install step. By using ${CMAKE_BINARY_DIR}, you are passing an absolute path to your binary directory (build), which may interfere with the moving of the build afterwards. If you would like to ouput your libraries to a folder after the build, you may set the target of the library with:
set_target_property(<library-name> PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
This will affect only the build stage of your project. As far as installs go, you are better off using only relative paths in the install directives. These paths will be relative to your ${CMAKE_INSTALL_PREFIX} variable. For example, you would use:
install(TARGETS mylib DESTINATION lib)
To install the library under the ${CMAKE_INSTALL_PREFIX}/lib folder. Best practice states that you should NEVER manipulate this variable directly in your CMakeLists.txt files, as it could break a build somewhere down the line. Starting with CMake 3.15, it is possible to use cmake --install to install a project. This command allows setting an installation prefix, such as:
cmake --install . --prefix desired/install/path
With this, all your link path should stay valid.
Please add a macos tag to this question.
I think that you are looking for a relative RPATH. CMake builds the executable with an absolute RPATH, so if you move or rename the build directory the program stop working. In your example, you only need to modify the main program CMakeLists.txt, to change the value of the RPATHs that CMake inserts in your executable.
# The main program
add_executable(prog ./src/main.cpp)
target_include_directories(prog PUBLIC ./inc/)
set_target_properties(prog PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH "#executable_path/;#executable_path/../external/mylib")
You can verify the values of the LC_RPATHs with this command from your build directory:
$ otool -l app/prog
For dependencies between libraries, it may also be useful "#loader_path" instead of #executable_path. And for other Unix operating systems, use "$ORIGIN". More information here.
I have a C++ project containing several modules, some built as libraries, with such structure:
/MyProject
+---/build
/ModuleA
+---CMakeLists.txt <- module level CMakeLists
+---/src
| +--CMakeLists.txt <- src level CMakeLists
| +--FileA1.cpp
| +--FileA2.cpp
+---/include
| +--FileA1.h
| +--FileA2.h
| +--FileA3.h
/ModuleB
+---CMakeLists.txt
+---/src
| +--CMakeLists.txt
| +--FileB1.cpp
| +--FileB2.cpp
+---/include
| +--FileB1.h
| +--FileB2.h
| +--FileB3.h
main.cpp
CMakeLists.txt <- project level CMakeLists
CMakeLists.txt files look as follow:
project level:
cmake_minimum_required(VERSION 3.05)
project(MyProject)
subdirs(ModuleA ModuleB)
set(CMAKE_CXX_STANDARD 11)
add_executable(MyProject main.cpp)
target_link_libraries(MyProject ModuleA ModuleB)
module level:
subdirs(src)
src level:
FIND_PACKAGE(SomePackage REQUIRED)
INCLUDE_DIRECTORIES(
${SomePackage_INCLUDE_DIR}
${MyProject_SOURCE_DIR}/ModuleA/include
)
SET(SOURCE_FILES <all files from ModuleA/src goes here>)
ADD_LIBRARY(ModuleA STATIC ${SOURCE_FILES})
TARGET_LINK_LIBRARIES(ModuleA
${SomePackage_LIBRARIES}
)
The problem is: when I include header files from 'SomePackage' in my ModuleA header files (i.e. SomePackageFile.hpp in FileA1.h) I get an error while running a build with make:
fatal error: SomePackageFile.hpp: No such file or directory
When I include them in cpp files they are visible and project compiles correctly. I assume that is sth wrong with CMakeLists on src level or entire hierarchy of files is missing something.
I have a github project to be used as a skeleton for other projects:
https://github.com/gnyiri/cmake-sandbox
If you follow this layout, you will not need to add ${SomePackage_INCLUDE_DIR} to INCLUDE_DIRECTORIES which is not the best way to add directories to the include path otherwise.
In a nutshell, you should define a new library like this:
project(module_a)
set(sources
src/source_a_1.cc
)
add_library(library_a
${sources}
)
target_include_directories(library_a
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
Then, if you define another library (library_b), you only need to add library_a in target_link_libraries:
project(module_b)
# set list of sources, needs to be extended when new source arrives
set(sources
src/source_b_1.cc
)
# define a library (static by default -> liblibrary_b.a or library_a.lib will be generated)
add_library(library_b
${sources}
)
# include directories
target_include_directories(library_b
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
)
# link library_b
target_link_libraries(library_b
library_a
)
Note that in this source tree, all the header files are located in
<module>/include/<module>
This way you will include a header file from like this:
#include "<module>/<module_header.h>"
This is simply because /include will be on include path.
Switching from INCLUDE_DIRECTORIES() to TARGET_INCLUDE_DIRECTORIES() was the case, no change to the structure of the project was needed.
From Catch2's example, I tried to run this example with cmake where structure of my project is like this:
/factorial
+-- CMakeLists.txt
+-- /bin
+-- /include
| +-- catch.hpp
| +-- fact.hpp
+-- /src
| +-- CMakeLists.txt
| +-- fact.cpp
+-- /test
+-- CMakeLists.txt
+-- test_fact.cpp
fact.cpp:
unsigned int factorial( unsigned int number ) {
return number <= 1 ? number : factorial(number-1)*number;
}
fact.hpp:
#ifndef FACT_H
#define FACT_H
unsigned int factorial(unsigned int);
#endif
test_fact.cpp:
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "fact.hpp"
TEST_CASE( "factorials are computed", "[factorial]" ) {
REQUIRE( factorial(1) == 1 );
REQUIRE( factorial(2) == 2 );
REQUIRE( factorial(3) == 6 );
REQUIRE( factorial(10) == 3628800 );
}
I tried several ways already to build this project with cmake but it's failed. Sometimes I got an error:
cpp:X:XX: fatal error: 'fact.hpp' file not found
...
and sometimes I got:
Undefined symbols for architecture x86_64:
"_main", referenced from:
...
when I run make.
What should I have in factorial/CMakeLists.txt,factorial/src/CMakeLists.txt and factorial/test/CMakeLists.txt, if I want to have my execution files in factorial/bin?
Additional:
This is my CMakeLists.txts (I think they are completely wrong).
factorial/CMakeLists.txt:
project(factorial)
cmake_minimum_required(VERSION 2.8.12)
add_definitions("-std=c++11")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
add_subdirectory(src)
add_subdirectory(test)
factorial/src/CMakeLists.txt:
project(factorial)
cmake_minimum_required(VERSION 2.8.12)
add_executable(fact fact.cpp)
factorial/test/CMakeLists.txt:
project(factorial)
cmake_minimum_required(VERSION 2.8.12)
add_executable(test_fact test_fact.cpp)
target_include_directories(test_fact PRIVATE ${CMAKE_SOURCE_DIR}/include)
Many problems here:
add_executable(fact fact.cpp)
The call should be using add_library (You could also specify STATIC or SHARED), since you are only defining a factorial function, not an executable with a main function.
add_executable(fact fact.cpp)
The file should be test_fact.cpp and the target should have a different name to avoid conflict with the previous library you created. Also, your fact.cpp doesn't include fact.hpp. Last but not least, instead of doing target_include_directories, just write the following in your top-level CMakeLists.txt:
include_directories(include)
Now, all subdirectories should be able to access the header files. Beware that this removes control of the scoping of the header files (PRIVATE vs PUBLIC vs INTERFACE) and allows all subdirectories to access the header files. If you want to restrict this behavior, then use target_include_direcories for all targets (Your library and the test executable). For this example, since everything needs to access the header files, there is no problem with the statement above.
More problems:
project(factorial)
cmake_minimum_required(VERSION 2.8.12)
Either switch the order of these statements, or remove both of them. (You only need them in your top level CMake file)
If you look at the CMake documentation, the PROJECT_SOURCE_DIR variable is define as that:
Top level source directory for the current project.
This is the source directory of the most recent project() command.
Since you called project many times, that variable will constantly change. I would suggest you to remove your project directive, or to use CMAKE_SOURCE_DIR, which always point to the source directory of the whole project.
As a side note, I suggest to use set(CMAKE_CXX_STANDARD 11) instead of add_definition