2
votes

I have a project built with CMake that uses Catch2 for unit tests. Some of the unit tests exercise code that loads data from a file like this:

std::string resource_dir = "TEST_CWD/resources/";
std::ifstream infile{resource_dir + "datafile.txt"}

The question is how to properly get the value of TEST_CWD.

The directory structure is simple (and not set in stone):

my_project/
    test/
        resources/datafile.txt
        loader_test.cpp

Leaving TEST_CWD blank sometimes works, but breaks when running tests through an IDE. Setting an environment variable with the absolute path also works, but will break on others' machines. Similarly forcing all users to manually set environment variables is user unfriendly.

What is a good way to specify relative file paths in CMake projects?

1

1 Answers

10
votes

I don't know about relative paths, but you can use ${CMAKE_SOURCE_DIR} to get the path to the top-level directory of your project-- where the main CMakeLists.txt file is.

From the CMake docs for CMAKE_SOURCE_DIR:

The path to the top level of the source tree.

This is the full path to the top level of the current CMake source tree. For an in-source build, this would be the same as CMAKE_BINARY_DIR.

Then you can just base all your paths off of this. For example, in a CMake script, you could write ${CMAKE_SOURCE_DIR}/resources/datafile.txt.

Edit:

If you need access to this value in your C++ code itself, you could use the configure_file command. For example you could create a file called something like Config.h.in...

// Config.h.in

#ifndef CONFIG_H
#define CONFIG_H

#define SOURCE_DIR "${CMAKE_SOURCE_DIR}"

#endif

... and then in your CMakeLists.txt file,

configure_file(Config.h.in ${CMAKE_BINARY_DIR}/Config.h)

include_directories(${CMAKE_BINARY_DIR})

Then you could include Config.h like a normal header, and be on your way!

Single variable shortcut

Just use a preprocessor macro. In the CMakeLists.txt in test/:

target_compile_definitions(target_name PUBLIC TEST_RESOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}/resources/")

in C++:

std::string resource_dir = TEST_RESOURCE_DIR;