为什么我使用 Cmake build 和 VS 2019 build 时相对路径不同?
why the relative path is different when I use Cmake build and VS 2019 build?
我是 Cmake 的新手。我尝试使用 Cmake 构建我的项目。
在我的项目中,我需要在运行时间内加载一些资源。例如:
string inFileName = "../Resources/resource.txt";
// string inFileName = "../../Resources/resource.txt";
ifstream ifs;
ifs.open(inFileName.c_str());
if (ifs) {
....
}
但是当我在project/build中使用命令行cmake ../
和cmake --build . --config Release
时。我的文件路径应该是相对于 ${PROJEDCT_BINARY}
,即 inFileName = "../resources/resource.txt"
.
但是当我使用 cmake ../
并用 VS2019 打开 sln 文件然后右键单击构建和 运行 时,我的文件路径应该是相对于可执行文件的,即 inFileName = "../../resources/resource.txt"
.
不知道为什么会这样,网上搜了一下,好像没人遇到过这种傻问题...
下面是我的文件结构。
|--3rdParty
|----CmakeLists.txt
|--include
|----header.h
|--source
|----source.cpp
|----CmakeLists.txt
|--resources
|----resource.txt
|--CmakeLists
和我的根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
...
)
通过生成 MSVS 解决方案文件,您 (CMake) 为生成解决方案(和项目)的 MSVS 创建工作环境。因此,与那里相关的所有内容都与生成的文件有关,就 MSVS 而言,该目录是世界的中心。这就是为什么你应该努力使用绝对路径而不是相对路径。
要实现这一点,CMake 有一堆变量,您使用的 PROJECT_SOURCE_DIR
就是其中之一。但是,有一个似乎更适合您的情况:CMAKE_SOURCE_DIR
.
因此,每当您需要使用资源时,请在 CMake 脚本中使用以下路径:"${CMAKE_SOURCE_DIR}/resources/resources.txt"
如果您需要在运行时加载资源,那么它超出了 CMake 及其功能。您应该将这些资源与生成的二进制文件相关联,因为它们在项目中的位置不再重要。 CMake 通过提供 install
and file(COPY ...)
来帮助它。前者主要用于应用程序的打包过程,而后者可能用于开发过程以减轻负担。
例如,您可以在项目 (source/CmakeLists.txt) CMake 文件中包含以下内容:
file(COPY "${CMAKE_SOURCE_DIR}/resources" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
应该将 resources
文件夹放在创建二进制文件的位置。
使用相对路径加载文件时,最终文件名的解析取决于当前工作目录。相对路径附加到该工作目录。当前工作目录不一定与您的应用程序路径相同;它将是启动应用程序的周围环境的路径(或者可以专门为大多数 IDE 中的调试环境设置)。
当您 运行 它 而不是 来自 IDE 时,您没有具体说明 运行 您的程序 - 只是 double-clicking 可能是可执行文件?您也不告诉我们与您的源相关的可执行文件是在哪里构建的?
特别是 运行ning 来自 Visual Studio,您可以在项目属性的“调试”部分中设置工作目录。
对于更灵活的解决方案,我通常做的是确定可执行文件的路径,然后将加载资源的相对路径附加到该路径。
基本上,完整的可执行路径存储在 argv[0]
中(如果您有 int main(int argc, char** argv) {...}
,即主函数第二个参数的第一个元素)。有关这方面的更多信息,请参阅 the answers to this other question.
示例
我是 Cmake 的新手。我尝试使用 Cmake 构建我的项目。
在我的项目中,我需要在运行时间内加载一些资源。例如:
string inFileName = "../Resources/resource.txt";
// string inFileName = "../../Resources/resource.txt";
ifstream ifs;
ifs.open(inFileName.c_str());
if (ifs) {
....
}
但是当我在project/build中使用命令行cmake ../
和cmake --build . --config Release
时。我的文件路径应该是相对于 ${PROJEDCT_BINARY}
,即 inFileName = "../resources/resource.txt"
.
但是当我使用 cmake ../
并用 VS2019 打开 sln 文件然后右键单击构建和 运行 时,我的文件路径应该是相对于可执行文件的,即 inFileName = "../../resources/resource.txt"
.
不知道为什么会这样,网上搜了一下,好像没人遇到过这种傻问题...
下面是我的文件结构。
|--3rdParty
|----CmakeLists.txt
|--include
|----header.h
|--source
|----source.cpp
|----CmakeLists.txt
|--resources
|----resource.txt
|--CmakeLists
和我的根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
...
)
通过生成 MSVS 解决方案文件,您 (CMake) 为生成解决方案(和项目)的 MSVS 创建工作环境。因此,与那里相关的所有内容都与生成的文件有关,就 MSVS 而言,该目录是世界的中心。这就是为什么你应该努力使用绝对路径而不是相对路径。
要实现这一点,CMake 有一堆变量,您使用的 PROJECT_SOURCE_DIR
就是其中之一。但是,有一个似乎更适合您的情况:CMAKE_SOURCE_DIR
.
因此,每当您需要使用资源时,请在 CMake 脚本中使用以下路径:"${CMAKE_SOURCE_DIR}/resources/resources.txt"
如果您需要在运行时加载资源,那么它超出了 CMake 及其功能。您应该将这些资源与生成的二进制文件相关联,因为它们在项目中的位置不再重要。 CMake 通过提供 install
and file(COPY ...)
来帮助它。前者主要用于应用程序的打包过程,而后者可能用于开发过程以减轻负担。
例如,您可以在项目 (source/CmakeLists.txt) CMake 文件中包含以下内容:
file(COPY "${CMAKE_SOURCE_DIR}/resources" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
应该将 resources
文件夹放在创建二进制文件的位置。
使用相对路径加载文件时,最终文件名的解析取决于当前工作目录。相对路径附加到该工作目录。当前工作目录不一定与您的应用程序路径相同;它将是启动应用程序的周围环境的路径(或者可以专门为大多数 IDE 中的调试环境设置)。
当您 运行 它 而不是 来自 IDE 时,您没有具体说明 运行 您的程序 - 只是 double-clicking 可能是可执行文件?您也不告诉我们与您的源相关的可执行文件是在哪里构建的?
特别是 运行ning 来自 Visual Studio,您可以在项目属性的“调试”部分中设置工作目录。
对于更灵活的解决方案,我通常做的是确定可执行文件的路径,然后将加载资源的相对路径附加到该路径。
基本上,完整的可执行路径存储在 argv[0]
中(如果您有 int main(int argc, char** argv) {...}
,即主函数第二个参数的第一个元素)。有关这方面的更多信息,请参阅 the answers to this other question.