Here my minimal example (https://github.com/theCollectiv/cmake_minimal). I first got this project structure with seperate Headerplacement (-> src and include)
.
├── 1Cmake.sh
├── 2runExe.sh
├── 3cleanTarget.sh
├── 4runTest.sh
├── 7VersionOfCurrentTools.sh
├── build
│ ├── CMakeCache.txt
│ ├──...
│ ...
├── CMakeDefaults.txt
├── CMakeLists.txt
├── compile_commands.json -> ...
├── data
├── docs
│ ├── ...
├── include
│ └── addition
│ └── addition.hpp
├── src
│ ├── addition
│ │ └── addition.cpp
│ ├── main.cpp
├── tests
│ └── test01_proofOfWork
│ ├── CMakeLists.txt
│ └── tests.cpp
main.cpp
#include "addition.hpp"
#include <iostream>
int main() {
int a = 5;
int b = 3;
std::cout << "a is " << a << "\nb is " << b << "\nThe Sum of both "
<< add(a, b) << std::endl; }
addition.cpp
#include "addition.hpp"
int add(int a, int b) { return a + b; }
header of addition.cpp: addition.hpp
#pragma once
int add(int a, int b);
The CMakeList.txt in the root-folder looks like this:
cmake_minimum_required(VERSION 3.21.2)
set (This
Project_main)
project(${This}
LANGUAGES CXX
VERSION 1.000)
enable_testing()
find_package(GTest REQUIRED)
add_subdirectory(./tests/test01_proofOfWork)
# Custom Variables
set(QUELLE src/main.cpp)
set(ZIEL finalExecutable)
# integrate lib (with .cpp and its header)
set(LIB_1 addition)
add_library(
${LIB_1}
STATIC src/addition/addition.cpp
)
# add .hpp hinzufuegen and connect to lib
target_include_directories(
${LIB_1}
PUBLIC include/addition
)
# add executable
add_executable(${ZIEL} ${QUELLE})
# linking the lib
target_link_libraries(
${ZIEL}
PRIVATE ${LIB_1}
# PUBLIC ${LIB_1}
)
Now I want to add unit tests by using googletest. I'm using ubuntu and googletest is installed in my systempath (with shared libs) and working.
I'm now a little bit stuck, getting googletest well integrated in the project.
The CMakeList.txt in the tests-dir:
# Name of the Tests
set (This
runTest)
# Location of the test
set (Sources
tests.cpp)
# executable of the test
add_executable(${This} ${Sources})
# linking libs for the test
target_link_libraries(${This} PUBLIC
GTest::gmock
GTest::gtest
GTest::gmock_main
GTest::gtest_main)
# registrating the test
gtest_discover_tests(${This})
The test.cpp
// tests.cpp
// #include "./../../include/addition/addition.hpp"
#include <gtest/gtest.h>
#include <gtest/internal/gtest-internal.h>
// bool foo(){
// return true;
// }
//
//
// TEST(Simpletest, trueEqualsTrue) {
// EXPECT_TRUE(foo());
// EXPECT_FALSE(foo());
// EXPECT_EQ(true, foo());
// ASSERT_FALSE(foo());
// EXPECT_EQ(false, foo());
// }
//
TEST(SquareRootTest, PositiveNos) {
ASSERT_EQ(18.0, add(1,17));
EXPECT_EQ(6, add(1,6));
ASSERT_EQ(25.4, add(55, -1));
ASSERT_EQ(0, add(-4, 4));
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
The de-commented test code works and compiles fine, so gtest works fine (means: if I m testing code, thats in the same file the code is tested).
But... (I'm new to this stuff, so maybe its an easy (or noob) question):
The reason, why I added the googletest is to test the code in the src- or -include dir. Therefore I got the add all the headers and files in the these dirs for test cases all the time.
Is there a good way to make all of them available for the possible tests that I might run without configuring it all the time?
My problem is,
that the de-commented code works/compiles fine (of code in the same location like the test is). That means:
googletest is installed correctly
the tests-CMakeLists.txt is working correctly (and the root-CmakeLists.txt too)
If I want to compile the test-code, that is not de-commented (that means the 'code to test' is not in the same file like the test itself), it is complaining for missing headers. If I add them, the compilation of the tests quits with errors (like "cmake line XXX" ...doesnt tell me anything or "undefined reference too"). The problem I got
it doesnt compile the tests (obvious)
even if it would compile, I got to rebuild all the things (adding headers in the test-source-code) in the test-directory like I did in the root-directory (similar/same file linking in both of them). If I got a more complex project structure (using a function in a file which uses functions from another file), this is 'doing the same exact same stuff in for the normal project (src and include) and in the tests-dir'. Or am I wrong at this point?
Solution:
# linking libs for the test
target_link_libraries(${This} PUBLIC
GTest::gmock
GTest::gtest
GTest::gmock_main
GTest::gtest_main
# Solution: Got to link the lib(s) (which I want to test in the root-dir) against the test-executable
addition
)
You are not linking yout test project against your library. So it doesn't use your library. Link it.
target_link_libraries(${This} addition)
Related
my goal is to create libraries like client and generator and use them in src/main.cpp, but sometimes these libraries depend each other.
In this case: client/User.hpp uses generator/IdGenerator.hpp
Project
│
├── CMakeLists.txt
├── libs
│ ├── CMakeLists.txt
│ ├── client
│ │ ├── CMakeLists.txt
│ │ ├── User.cpp
│ │ └── User.hpp
│ └── generator
│ ├── CMakeLists.txt
│ ├── IdGenerator.cpp
│ ├── IdGenerator.hpp
│ └── Types.hpp
└── src
└── main.cpp
Project/CMakeLists.txt:
cmake_minimum_required (VERSION 3.8)
project(game-project VERSION 0.1.0)
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_FLAGS "-Wall -Wextra -O0 -std=c++20")
add_executable (game src/main.cpp)
add_subdirectory(libs)
target_link_libraries(game libclient libgenerator)
libs/CMakeLists.txt:
add_subdirectory(generator)
add_subdirectory(client)
libs/client/CMakeLists.txt:
add_library(libclient STATIC
User.cpp
User.hpp
)
include_directories(generator/)
target_link_libraries(libclient libgenerator)
libs/generator/CMakeLists.txt:
add_library(libgenerator STATIC
IdGenerator.cpp
IdGenerator.hpp
Types.hpp
)
C++ files:
main.cpp:
#include <client/User.hpp>
int main(int argc, const char* argv[])
{
User user;
return 0;
}
client/User.hpp:
#pragma once
#include <generator/IdGenerator.hpp>
class User
{
Identifier id = IdGenerator::generateId();
};
When I run make after cmake, I get this error:
In file included from Project/libs/client/User.cpp:1:
Project/libs/client/User.hpp:3:10: fatal error: generator/IdGenerator.hpp: No such file or directory
3 | #include <generator/IdGenerator.hpp>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Sorry for the verbose summary, I was able to shorten the example this much. What do you think the problem is?
This question might seem like a duplicate of CMake libraries that depend on each other but as you can see I'm already applying the
include_directories(generator/).
I misunderstood what the problem was initially, but now I think this might help.
Try adding to the CMakeLists.txt of your client instead of
include_directories(generator/)
this command
target_include_directories(libclient PUBLIC <Path to your generator file>)
Maybe you need to experiment a little to get the path correct as you might need to either specify it from the root directory or the current one (where this CMakeLists.txt resides), but it might solve your problem.
I'm working on an hobby project in C++, using flex and bison. I'm using CMake as my build system, and I had struggle in making all work together.
I'm quite new to CMake so the documentation seems quite minimal to me. It is showed how to link everything in one executable.
But I'm trying to keep all the parts of my code separated, so I would like to have my flex/bison file in a subfolder. My structure is this:
.
├── build
| └-- ...
├── CMakeLists.txt
├── flexbison
│ ├── CMakeLists.txt
│ ├── lexer.ll
│ └── parser.yy
├── lib
│ ├── CMakeLists.txt
│ └── ...
├── main.cpp
└── run.sh
So I want to have my yyparse function separate from my main.cpp, as well as my other C++ files. I managed to get it done in this way:
project_root/CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(progetto-di-prova VERSION 0.1)
add_subdirectory(flexbison)
add_executable(executable main.cpp)
target_include_directories(executable PUBLIC
"${PROJECT_BINARY_DIR}"
"${PROJECT_BINARY_DIR}/flexbison"
)
set_target_properties(executable PROPERTIES CXX_STANDARD 11)
target_link_libraries(executable parserlib)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
flexbison/CMakeLists.txt:
find_package(FLEX)
find_package(BISON)
flex_target(lexer lexer.ll "${CMAKE_CURRENT_BINARY_DIR}/lexer.cpp")
bison_target(parser parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.cpp
DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/parser.h)
add_flex_bison_dependency(lexer parser)
add_library(parserlib STATIC
${FLEX_lexer_OUTPUTS}
${BISON_parser_OUTPUTS}
)
the main.cpp file:
#include <parser.h> // <-this was the line causing troule
#include <iostream>
extern int yylex(void);
int main(int argc, char *argv[])
{
yyparse();
return 0;
}
Now, the point is: is this the correct way of doing so? Is it better to put the main function in the bison code?
My main problem, as highlighted in the code, was to include the parser.h header file in the main.cpp. Is this the CMake-way to do it?
Thanks in advance!
If I were you I would have:
flexbison/CMakeLists.txt:
...
add_library(parserlib STATIC
${FLEX_lexer_OUTPUTS}
${BISON_parser_OUTPUTS}
)
target_include_directories(parserlib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>
$<INSTALL_INTERFACE:include/parserlib> # <prefix>/include/parserlib
)
note: $<INSTALL_INTERFACE:include/parserlib> need to be adapted if you want and how you install parserlib...
project_root/CMakeLists.txt:
...
target_include_directories(executable PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
...
Since executable is "target_link" against parserlib which provides public include directories, you don't need to list these directories anymore in executable's include dirs.
ref: https://cmake.org/cmake/help/latest/command/target_include_directories.html
I have a given project structure
.
├── CMakeLists.txt
├── lib
│ ├── lodepng
│ │ ├── CMakeLists.txt
│ │ └── src
│ │ ├── lodepng.cpp
│ │ └── lodepng.h
│ └── pixel_reader
│ ├── CMakeLists.txt
│ └── src
│ ├── hello.cpp
│ └── hello.h
├── main.cpp
With the following CMakeLists
./CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
project(pov_system VERSION 1.0)
add_subdirectory(lib/lodepng)
add_subdirectory(lib/pixel_reader)
add_executable(pov_system main.cpp)
target_link_libraries(pixel_reader PRIVATE lodepng)
target_link_libraries(pov_system PRIVATE pixel_reader)
./lodepng/CMakeLists.txt
add_library(
lodepng
src/lodepng.cpp
src/lodepng.h
)
target_include_directories(lodepng PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
./pixel_reader/CMakeLists.txt
add_library(
pixel_reader SHARED
src/hello.cpp
src/hello.h
)
target_include_directories(pixel_reader PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
As one can see, I try to link the 'lodepng' library to the 'pixel_reader' library and include the 'lodepng.h' to the 'hello.h' file.
But at the moment I get the following error while trying to build the project.
[build] <path-to-project>/pov_system/lib/pixel_reader/src/hello.h:2:10: fatal error: lodepng.h: No such file or directory
[build] 2 | #include "lodepng.h"
[build] | ^~~~~~~~~~~
[build] compilation terminated.
Question
Why is my code not finding the 'lodepng.h' file or (and even more important) is it a good practice to link from one library to another?
Maybe two really simple questions, but just started to dive into the world of CMake, Compiling, etc... and I really appreciate your help.
Why is my code not finding the 'lodepng.h' file or (and even more important)
Because you probably didn't give it correct path. One way to fix that would be to give the exact path in hello.h
#include "../../lodepng/src/lodepng.h
Second way is to use target_include_directories:
target_include_directories(pixel_reader PUBLIC "../../lodepng/src/")
is it a good practice to link from one library to another?
It depends on your project. If library A requires library B, then yes, it is okay in my opinion.
More importantly, you are creating the target in the wrong place i.e., in the root CMakeLists file. It must be done in the directory in which target is created.
./pixel_reader/CMakeLists.txt
# create target
add_library(
pixel_reader SHARED
src/hello.cpp
src/hello.h
)
target_link_libraries(pixel_reader PRIVATE lodepng) #link library where target is created
target_include_directories(pixel_reader PUBLIC "../../lodepng/src/")
target_include_directories(pixel_reader PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
Your pixel_reader library target possibly needs lodepng.h header to compile, because it depends on it.
something like
target_include_directories(pixel_reader PUBLIC "PATH_TO_LODE_PNG_HEADER_DIRECTORY")
could solve this problem.
I have for some time had some problems incorporating modern cmake into a project I've been working fr some while and seem to be stuck on how i should define the the individual CMakeLists, and the top-level CMakeList.
My project structure is pretty simple.
├── build
└── src
├── include
│ ├── database
│ │ ├── database.cpp
│ │ └── database.h
│ ├── match
│ │ ├── match.h
│ │ └── mathc.cpp
│ ├── record
│ │ ├── lib
│ │ ├── record.cpp
│ │ └── record.h
│ └── spectogram
│ ├── spectogram.cpp
│ └── spectrogram.h
└── main.cpp
main.cpp are linked to all the includes, and some of the includes should know the presence of other includes, meaning, I should be able to include match.h in
database.h. Some third-party libs are also going to be used, in this case I am using portaudio, download and installed using externalproject_add, which should only be visible for the include which holds the library, in this case record, should only see this.
But how I should define the individual CMakeList, is currently unknown.
I've scouted the net for a proper way of setting this up, but cannot seem to find one that I understand.
How do i define the CMakeLists for this project, and how do i make sure that the includes, are visible for the Main.cpp and the includes files that need them, and how do I make third-party-libraries visible only for the includes that it is being used for.
CMakeLists example structure tried:
CMakeLists.txt
cmake_minimum_required(VERSION 3.2)
project(soundcloud)
#add_subdirectory(src/database)
#add_subdirectory(src/match)
#add_subdirectory(src/record)
add_subdirectory(src/include/spectogram)
add_executable(cmakeDemo src/main.cpp)
SET_TARGET_PROPERTIES(cmakeDemo PROPERTIES LINKER_LANGUAGE Cxx)
target_link_libraries(cmakeDemo spectogram)
#target_link_libraries(cmakeDemo database match record spectogram)
src/include/database/CMakeLists.txt
add_library(spectogram STATIC .)
target_include_directories(spectogram PUBLIC .)
getting error message:
CMake Error: Error required internal CMake variable not set, cmake may not be built correctly.
Missing variable is:
CMAKE_Cxx_LINK_EXECUTABLE
CMake Error: Cannot determine link language for target "spectogram".
CMake Error: CMake can not determine linker language for target: spectogram
You can use the PRIVATE property of target_include_directories. When PRIVATE, it means that the include directories will be available to the sources of the target. When PUBLIC, it will also be available to whomever links to the target.
If I were writing this in a single CMakeLists.txt, I'd do this:
cmake_minimum_required(VERSION 3.0)
add_library(database STATIC src/include/database.cpp)
target_include_directories(database PUBLIC src/include/database)
################
add_library(match STATIC src/include/mathc.cpp)
target_include_directories(match PUBLIC src/include/match)
################
include(ExternalProject)
ExternalProject_Add(portAudio ${SomeCommands})
add_library(record STATIC src/include/record.cpp)
target_include_directories(record PUBLIC src/include/record) # When cmakeDemo links to this, it'll get these includes
target_include_directories(record PRIVATE src/include/record/lib) # When cmakeDemo links to this, it won't get these includes
target_link_libraries(record portAudio)
#################
add_library(spectogram STATIC src/include/spectogram.cpp)
target_include_directories(spectogram PUBLIC src/include/spectogram)
##################
add_executable(cmakeDemo src/main.cpp)
target_link_libraries(cmakeDemo database match record spectogram)
If I were to do this with distributed CMakeLists.txt, I'd split the files where the ###### lines are, fix the paths, and use add_subdirectory() to include the sub-directories from higher-level cmake files.
First, you don't link to includes, you just "include" them during compilation.
Some people put one CMakeList.txt into every directory that contains a fairly independent compilation unit.
Some people just use one big one at the the top.
Having just one CMakeList.txt file makes it easier to start, but if the project gets huge, things get messy.
For every compilation unit, you can specify the include directories with target_include_directories
I'm trying to compile an example program that uses a shared library (also developed by me) in C++, which name is libtestlib.so.
The error
I have compiled the shared library without problems, but when I try to compile an executable that uses this library, I have the following error: iface/libtestlib.so: undefined reference to 'ALIB::function()'
What I have done
I have done the following:
C++ library (files in $project_dir/lib1):
// HEADER
#ifndef ALIB_H
#define ALIB_H
namespace ALIB{
int function();
}
#endif
-------------------------------------------
// SOURCE
#include "alib.h"
using namespace ALIB;
int ALIB::function(){
return 101;
}
The C interface for the C++ library (files in $project_dir/iface)
// HEADER
#ifndef IFACE_H
#define IFACE_H
#include "alib.h"
extern "C"{
int IFACE_function();
}
#endif
--------------------------------
// SOURCE
#include "iface.h"
int IFACE_function(){
return ALIB::function();
}
--------------------------------------------------------
// CMakeLists used to build the library:
cmake_minimum_required(VERSION 2.8)
PROJECT( testlib )
include_directories( ../lib1 )
add_library( testlib SHARED iface.cpp )
The executable that uses the library (files in $project_dir/main):
// SOURCE
#include "iface.h"
#include <iostream>
using namespace std;
int main(){
cout << IFACE_function() << endl;
}
-------------------------------------
// CMakeLists used to build the executable (file in `$project_dir`):
cmake_minimum_required(VERSION 2.8)
PROJECT( testlib )
find_library( LIB NAMES testlib PATHS ./iface )
include_directories( ./lib1 ./iface )
add_executable( testlib ./main/main.cpp )
target_link_libraries( testlib ${LIB} )
Generated files
$project_dir:
all generated by cmake. (CmakeLists.txt, CMakeCache, cmake_install.cmake, MakeFile)
$project_dir/lib1:
alib.cpp and alib.h
$project_dir/iface:
iface.cpp, iface.h, libtestlib.so and all generated by cmake.
$project_dir/main:
main.cpp.
As tree:
$project_dir
├── CMakeCache.txt
├── CMakeFiles
│ ├── ...
├── cmake_install.cmake
├── CMakeLists.txt
├── CMakeLists.txt~
├── iface
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ │ ├── ...
│ ├── cmake_install.cmake
│ ├── CMakeLists.txt
│ ├── CMakeLists.txt~
│ ├── iface.cpp
│ ├── iface.h
│ ├── libtestlib.so
│ └── Makefile
├── lib1
│ ├── alib.cpp
│ └── alib.h
├── main
│ └── main.cpp
└── Makefile
Thanks to Yuan's comment I have found the problem. I needed to add the alib.cpp file to the CMakeLists.txt, this way:
// CMakeLists used to build the library:
cmake_minimum_required(VERSION 2.8)
PROJECT( testlib )
include_directories( ../lib1 )
add_library( testlib SHARED iface.cpp ../lib1/alib.cpp )