1

I'm new in Cmake. And I try to use Cmake to construct my project.

In my project, I need to load some resources in runtime. for instance:

string inFileName = "../Resources/resource.txt";
// string inFileName = "../../Resources/resource.txt";
ifstream ifs;
ifs.open(inFileName.c_str());
if (ifs) {
....
}

But when I use the command line cmake ../ and cmake --build . --config Release in project/build. my file path should be relative to ${PROJEDCT_BINARY}, i.e. inFileName = "../resources/resource.txt".

But when I use cmake ../ and open the sln file with VS2019 then right-click to build and run, my file path should be relative to the executable, i.e. inFileName = "../../resources/resource.txt".

I don't know why this happened, and I search through Internet, It seems no one else encounters this stupid question...

Below is my file structure.

|--3rdParty
|----CmakeLists.txt
|--include
|----header.h
|--source
|----source.cpp
|----CmakeLists.txt
|--resources
|----resource.txt
|--CmakeLists

and my root CmakeLists.txt

cmake_minimum_required(VERSION 3.12)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(OBMI VERSION 0.1.0.0 LANGUAGES C CXX CUDA)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR})

add_subdirectory(3rdParty)

add_subdirectory(source)

source/CmakeLists.txt

add_executable(mSI)

target_sources(mSI PRIVATE
    ${PROJECT_SOURCE_DIR}/include/header.h
    # source
    source.cpp
)

target_include_directories(multiSpectrumImaging 
    PRIVATE 
    ${PROJECT_SOURCE_DIR})

target_link_libraries(mSI
    PRIVATE
    ...
)
LSP
  • 13
  • 3
  • Your question is a bit unclear on where/how the resource.txt access happens exactly. Are you using the resource file *during compilation* or *during runtime*? If during runtime of your application - how are you starting it? The only thing that makes a difference when loading files at runtime from your program with a relative path is the current working directory of your application - depending on how you start it (from command line or from within the IDE), this working directory could be set differently – codeling Apr 08 '22 at 06:51
  • 1
    Unrelated: CMake is mostly a case-sensitive tool so you should name your files `CMakeLists.txt` not `CmakeLists.txt` you get away with it on Windows with NTFS but moving to another FS (case sensitive) will break everything. – ixSci Apr 08 '22 at 06:55
  • thanks for reminding me. I will notice the file name next time. And I add the question description. – LSP Apr 08 '22 at 07:04
  • If the reply is correct, you can mark it as the answer. Just a reminder :) – Minxin Yu - MSFT Apr 08 '22 at 08:41

2 Answers2

0

By generating an MSVS solution file you (CMake) create a working environment for MSVS where the solution (and projects) is generated. So everything relative there would be relative to those files generated and as far as MSVS is concerned, that directory is the center of the world. That's why you should strive to use absolute and not relative paths.

To achieve that CMake has a bunch of variables and PROJECT_SOURCE_DIR, which you use, is one of them. But there is one which seems to suite your case better case, though: CMAKE_SOURCE_DIR.

So whenever you need to use your resources, use the following path in your CMake script: "${CMAKE_SOURCE_DIR}/resources/resources.txt"


If you need your resources to load in runtime then it goes beyond CMake and its capabilities. You should put these resources relative to your resulting binary because what place they have in the project doesn't matter anymore. CMake helps with it by providing install and file(COPY ...). Where the former is mostly used during the packaging of your application and the latter might be used during development to ease the burden.

For example, you can have the following in your project (source/CmakeLists.txt) CMake file:

file(COPY "${CMAKE_SOURCE_DIR}/resources" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")

Which should place the resources folder where your binary gets created.

ixSci
  • 13,100
  • 5
  • 45
  • 79
  • thanks, but I want to use resources in my cpp file, should I use a set() and configure_file() to define the absolute path as a macro. so I can use it in cpp? – LSP Apr 08 '22 at 06:49
  • @LSP show how you want to use this file – ixSci Apr 08 '22 at 06:51
0

When using relative paths to load files, the resolution of the final filename depends on the current working directory. The relative path is appended to that working directory. That current working directory is not necessarily the same as the path of your application; it will be the path of the surrounding environment from which the application is started (or can be set specifically for a debug environment in most IDE's).

You don't specify exactly how you run your program when you run it not from the IDE - just by double-clicking the executable maybe? You also don't tell us where the executable is built in relation to your sources?

Specifically for running from Visual Studio, you can set the working directory in the "Debugging" section of the Project Properties.

For a more flexible solution, what I typically do is to determine the path of your executable, and then appending the relative path to load resources to that. Basically, the full executable path is stored in argv[0] (if you have a int main(int argc, char** argv) {...}, i.e., the first element of the second argument to your main function). For more information on this, see for example the answers to this other question.

codeling
  • 11,056
  • 4
  • 42
  • 71
  • you are right... I always thought relative paths were relative to executable. Never thought it was relative to the working directory. – LSP Apr 08 '22 at 07:30
  • glad I could help! please upvote and/or accept helpful answers accordingly! if you need more info, let me know! – codeling Apr 08 '22 at 09:38