CMake + Qt + GTest files linking - c++

I have a simple CMake + Qt + GTest project:
.
├── CMakeLists.txt
├── src
│   ├── CMakeLists.txt
│   ├── main.cpp
│   └── utils
│   ├── calculator.cpp
│   └── calculator.h
└── tests
├── calculator_test.cpp
└── CMakeLists.txt
Root CMakeFiles.txt
cmake_minimum_required(VERSION 3.5)
project(random_project)
# Place binaries and libraries according to GNU standards.
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# Add source folder.
add_subdirectory(src)
# Add GTest.
include(cmake/googletest.cmake)
fetch_googletest(
${PROJECT_SOURCE_DIR}/cmake
${PROJECT_BINARY_DIR}/googletest
)
enable_testing()
# Add tests folder.
add_subdirectory(tests)
And I want to reach calculator.h in calculator_test.cpp which uses GTest:
#include <gtest/gtest.h>
#include "utils/calculator.h" // <- Want to reach this in that path format.
TEST(example, add)
{
EXPECT_EQ(8, Calculator::sum(3, 5));
}
I have tried to link but then test is not found and the path is releative:
tests/CMakeFiles.txt
# Find the Qt libraries.
find_package(Qt5Widgets REQUIRED)
# Qt5 libraries.
set(QT5_LIBRARIES
Qt5::Widgets)
# Source files.
set(SOURCE_FILES
calculator_test.cpp
../src/utils/calculator.cpp
../src/utils/calculator.h
../src/main.cpp) # If I link like this, test is not found.
# Tell CMake to create the executable.
add_executable(unit_tests ${SOURCE_FILES})
# Use the Widgets module from Qt5.
target_link_libraries(unit_tests ${QT5_LIBRARIES} gtest_main)
# Add tests.
add_test(
NAME unit_tests
COMMAND ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/unit_tests
)
How to link calculator.h in calculator_test.cpp test with CMakeLists.txt?

My Qt project with CMake project file cannot resolve the path to
"someHeader.h". What can I do to fix it?
You can specify the include path:
include_directories("${PROJECT_SOURCE_DIR}/relativePathToHeader")
and likely the path needed:
include_directories("${PROJECT_SOURCE_DIR}/src/utils") or maybe
include_directories("${PROJECT_SOURCE_DIR}/utils") depending on where the source directory actually is.
You need to re-run CMake, of course.

Related

CMake with multiple sub projects building into one directory

I'm not very familiar with CMake and still find it quite confusing. I have a project that has a server and client that I want to be able to run independent of each other but that builds together into the same directory (specifically the top level project build directory kind of like how games have the server launcher and game launcher in the same directory) Currently it just creates a builds directory in each sub project, so one in client, one in server etc.
This is my current project structure
.
├── CMakeLists.txt
├── builds
│   ├── debug
│   └── release
├── client
│   ├── CMakeLists.txt
│   ├── assets
│   └── source
│   └── Main.cpp
├── documentation
├── libraries
│   ├── glfw-3.3.7
│   └── glm
├── server
│   ├── CMakeLists.txt
│   └── source
│   └── Main.cpp
└── shared
├── PlatformDetection.h
├── Utility.h
├── events
└── platform
├── linux
├── macos
└── windows
This is my root CMake file
cmake_minimum_required(VERSION 3.20)
project(Game VERSION 1.0.0)
add_subdirectory(libraries/glfw-3.3.7)
add_subdirectory(client)
add_subdirectory(server)
Client CMake file
cmake_minimum_required(VERSION 3.20)
project(Launcher LANGUAGES CXX VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 23)
set(SOURCE_FILES source/Main.cpp ../shared/events/Event.h ../shared/Utility.h
source/Client.cpp source/Client.h ../shared/PlatformDetection.h ../shared/events/EventManagementSystem.cpp
../shared/events/EventManagementSystem.h)
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
include_directories(${CMAKE_SOURCE_DIR}/libraries/glm)
include_directories(${CMAKE_SOURCE_DIR}/libraries/glfw-3.3.7/include/GLFW)
include_directories(${CMAKE_SOURCE_DIR}/shared)
add_executable(Launcher ${SOURCE_FILES})
target_link_libraries(Launcher LINK_PUBLIC glfw)
Server CMake file
cmake_minimum_required(VERSION 3.20)
project(ServerLauncher LANGUAGES CXX VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 23)
set(SOURCE_FILES source/Main.cpp ../shared/events/Event.h ../shared/Utility.h
../shared/PlatformDetection.h ../shared/events/EventManagementSystem.cpp
../shared/events/EventManagementSystem.h)
include_directories(${CMAKE_SOURCE_DIR}/libraries/glm)
include_directories(${CMAKE_SOURCE_DIR}/shared)
add_executable(ServerLauncher ${SOURCE_FILES})
How can I make the client and server build into the same directory? And can these cmake file structures be improved at all? They seem quite messy and all over the place to me though that may just be due to my unfamiliarity with CMake.
You cannot have multiple subdirectories use the same build directory, but that doesn't seem what you're trying to achieve.
Assuming you don't set the variable CMAKE_RUNTIME_OUTPUT_DIRECTORY anywhere in your project, and you don't specify the RUNTIME_OUTPUT_DIRECTORY target property for any of your targets by some other means, you could simply set the variable in the toplevel CMakeLists.txt before using add_subdirectory:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin)
add_subdirectory(...)
...
Note that for distributing the program you should be using install() logic:
Client CMakeLists.txt
...
install(TARGETS Launcher RUNTIME)
Server CMakeLists.txt
...
install(TARGETS ServerLauncher RUNTIME)
Note that you may need to add logic for installing dependencies.
Using those install commands allows you to use
cmake --install <build dir> --prefix <install dir>
to install the programs locally in the default directory for binaries on the system. Furthermore it's the basis for packaging your project using cpack.

Importing header files and linking .a file in CMake

Trying to put Skia in my CMake project. How do I tell CMake to link my executable against libskia.a and use the header files inside ext/skia so that I can include them like so?
#include <skia/subdirectory/headerfile.h>
My project structure is currently the following:
.
├── CMakeLists.txt
├── CMakeLists.txt.user
├── ext
│   ├── libskia.a
│   └── skia
│   └── <subdirectories>
│      └── <header files>.h
└── src
└── main.cpp
and my CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(project LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
add_executable(project src/main.cpp)
In your primary CMakeLists.txt file you would simply add the following:
target_link_libraries(project skia)
If CMake cannot find the library, you can either do:
target_link_libraries(project /full/path/to/libskia.a)
or:
link_directories(/path/to/libraries)
target_link_libraries(project skia)

Ctest does not find catch2 tests with subdirectory

I don't seem to get my CTest project to recognize my Catch2 tests. The test project itself builds fine and I manage to run the tests using the executable created by it. However when running
ctest -V
The output I keep getting is:
UpdateCTestConfiguration from :/home/user/code/project/libs/DartConfiguration.tcl
UpdateCTestConfiguration from :/home/user/code/project/libs/DartConfiguration.tcl
Test project /home/user/code/project/libs/
Constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
No tests were found!!!
My set-up is as follows:
The folder structure:
libs
├── maths
│   ├── matrix.cpp / hpp
│   ├── function.cpp / hpp
│   └── CMakeLists.txt
├── ctest
│   ├── matrix_test.cpp
│   ├── function_test.cpp
│   └── CMakeLists.txt
├── build
   └── CMakeLists.txt
I build from the build folder
cmake ..
cmake --build .
ctest -V
CMakeLists.txt in ctest
set(SOURCE_FILES
main.cpp
maths/matrix_test.cpp
maths/function_test.cpp
)
# find the Catch2 library
find_package(Catch2 REQUIRED)
# create a test executable
add_executable(ctest ${SOURCE_FILES})
target_link_libraries(ctest maths Catch2::Catch2)
include(CTest)
include(ParseAndAddCatchTests)
ParseAndAddCatchTests(ctest)
The main CMakeLists.txt
# set CMake version
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(mathlib LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_SHARED_LIBRARY_PREFIX "lib")
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
set(LIB_BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../libs")
find_package(Catch2 REQUIRED)
enable_testing()
add_subdirectory("${LIB_BASE_DIR}/maths" maths)
add_subdirectory("${LIB_BASE_DIR}/ctest" ctest)
include(CTest)
include(Catch)
catch_discover_tests(ctest)
add_test(
NAME catch_test
COMMAND $<TARGET-FILE>:ctest --success
)
I have looked at the recipes here, the cmake cookbook, modern-cmake, the catch2 github page, but I seem to miss something obvious as for some reason the tests do not get picked up. I have not been able to find an example with add_subdirectory so may be that leads to a different set-up.
If I run
./bin/ctest
all tests run fine. So the executable itself is fine.

Creating and using a static library with CMake

I am trying to first create a static library and then link it to an executable using CMake. My project file structure looks like this:
├── CMakeLists.txt
├── build
├── lib
│   ├── CMakeLists.txt
│   ├── build
│   ├── include
│   │   └── Point.hpp
│   └── src
│   └── Point.cpp
└── mainApp.cpp
I first build the library like so.
cmake_minimum_required(VERSION 2.8.9)
project(CAST3)
set(CMAKE_BUILD_TYPE Release)
include_directories(include)
file(GLOB SOURCES "src/*.cpp")
add_library(CAST3 STATIC ${SOURCES})
However, when i try to link the library to my executable I get an error.
This is my executable
#include"Point.hpp"
int main(int argc, char *argv[]){
Point p = Point(1,2,3);
return 0;
}
This is my CMake file to link the library to the executable.
cmake_minimum_required(VERSION 2.8.9)
project (CAST3)
set ( PROJECT_LINK_LIBS libCAST3.a )
link_directories( ${CMAKE_CURRENT_SOURCE_DIR}/lib/build)
add_executable(libtest mainApp.cpp)
target_link_libraries(libtest ${PROJECT_LINK_LIBS} )
When I run that I get the this error
/mainApp.cpp:1:9: fatal error: 'Point.hpp' file not found
#include"Point.hpp"
^~~~~~~~~~~
1 error generated.
make[2]: *** [CMakeFiles/libtest.dir/mainApp.cpp.o] Error 1
make[1]: *** [CMakeFiles/libtest.dir/all] Error 2
make: *** [all] Error 2
What am I missing?
What am I missing?
You are missing target_include_directories(CAST3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) inside lib/CMakeLists.txt.
You are missing add_subdirectory(lib) from root CMakeLists.txt.
The set ( PROJECT_LINK_LIBS libCAST3.a ) and target_link_libraries(libtest ${PROJECT_LINK_LIBS} ) and link_directories( ${CMAKE_CURRENT_SOURCE_DIR}/lib/build) could be removed. Then you are missing just target_link_libraries(libtest PUBLIC CAST3). Cmake will automatically find the proper .a file and propagate include paths with target_link_libraries.
So your lib/CMakeLists.txt could look like this:
cmake_minimum_required(VERSION 3.0) # I would advise to update
project(CAST3)
include_directories(include)
file(GLOB sources src/*.cpp) # upper case variable names reserved for exported variables by convention
add_library(CAST3 ${sources}) # STATIC by default
target_include_directories(CAST3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
And root CMakeLists.txt could look like this:
cmake_minimum_required(VERSION 3.0) # I would advise to update
project(CAST3)
add_subdirectory(lib)
add_executable(libtest mainApp.cpp)
target_link_libraries(libtest CAST3)

verifying my understanding of a CMakeLists.txt file

I successfully played trial-and-error with a CMakeLists.txt file, and now everything builds. However, I want to make sure my understanding is correct about how it's working.
I have a project with the following structure:
./
├── bin
├── CMakeLists.txt
├── include
│   └── sql-writer
│   ├── credentials.h
│   ├── database.h
│   ├── datetime.h
│   ├── market_bar.h
│   └── writer.h
├── README.md
├── src
│   ├── CMakeLists.txt
│   ├── database.cpp
│   ├── main.cpp
│   └── writer.cpp
└── test
├── CMakeLists.txt
├── test-main.cpp
├── test_sym_table_pairs
└── writer_tests.cpp
This builds an executable, a static library, and a test executable. The problem was src/CMakeLists.txt:
set(HEADER_DIR ${sql-writer_SOURCE_DIR}/include/sql-writer)
add_executable(sql-writer-demo main.cpp ${HEADER_DIR})
target_include_directories(sql-writer-demo PUBLIC ${HEADER_DIR}) #!
target_link_libraries(sql-writer-demo sql-writer-lib mysqlcppconn ${Boost_LIBRARIES})
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp)
file(GLOB HEADERS ${HEADER_DIR}/*.h)
add_library(sql-writer-lib ${HEADERS} ${SOURCES})
target_link_libraries(sql-writer-lib mysqlcppconn ${Boost_LIBRARIES})
target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR})
the first line's set command just defines HEADER_DIR. This is easy.
target_include_directories(sql-writer-demo PUBLIC ${HEADER_DIR}) must be included after the first add_execuable because otherwise header files will need to be included with relative paths. Is that right? Why does it come after? I've heard cmake treats include directories as "separate" from "sources" (cmake sources not .cpp files). What does that mean?
target_link_libraries(sql-writer-demo sql-writer-lib mysqlcppconn ${Boost_LIBRARIES}) needs to come after add_executable(sql-writer-demo main.cpp ${HEADER_DIR}) as well, and it tells how to link to other libraries.
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp) is not recomended before only because the directory/file structure could change, and then this wouldn't work anymore
target_link_libraries(sql-writer-lib mysqlcppconn ${Boost_LIBRARIES}) needs to come after add_library(sql-writer-lib ${HEADERS} ${SOURCES}) because the compulation of my library sql-writer-lib needs to use other libs, and this is where we tell cmake to look out for those.
You typically don't include headers into add_executable and add_library, but only implementation files:
add_executable(sql-writer-demo main.cpp)
add_library(sql-writer-lib ${SOURCES})
add_executable and add_library create a target, target_include_directories specifies include directories for this target. The documentation is pretty clear:
The named <target> must have been created by a command such as add_executable() or add_library() and must not be an IMPORTED target.
If you use target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR}) with PUBLIC specifier, you don't need to use target_include_directories to specify include directories for targets that link against that library, because the dependency will be propagated automatically. The same applies to target_link_libraries.
So, src/CMakeLists.txt
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp)
add_library(sql-writer-lib ${SOURCES})
target_link_libraries(sql-writer-lib PUBLIC mysqlcppconn ${Boost_LIBRARIES})
target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR})
add_executable(sql-writer-demo main.cpp)
target_link_libraries(sql-writer-demo sql-writer-lib)
should work. Whether you want to use PUBLIC on mysqlcppconn ${Boost_LIBRARIES} depends on the structure of your project. I specified it as an example only.