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
...
)
CodePudding user response:
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.
CodePudding user response:
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.