如何借助CMake在不复制资源文件的情况下运行可执行文件?
我太懂这种烦恼了!每次构建都要让CMake把资源文件夹从源码目录复制到build目录,小文件的时候还好,等资源文件夹越来越大,不仅构建速度变慢,磁盘还平白多了一份重复文件,简直闹心。之前我也试过把编译输出的二进制文件挪到源码目录,结果各种编译生成的垃圾混在源码里,版本管理的时候又得费劲排除,完全得不偿失。
给你几个亲测有效的方案,不用复制资源也能正常运行程序:
方案一:指定运行时的工作目录
这个方法最直接,就是让你的可执行文件运行时的工作目录指向项目源码根目录,这样程序里写的相对路径就会自动从源码目录找资源,而不是build目录。
如果你用的是Visual Studio,可以在CMake里给目标设置调试工作目录:
set_target_properties(Core PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" )
如果是其他IDE(比如CLion),也可以通过类似的目标属性设置,或者直接在IDE的运行配置里手动把工作目录改成项目根目录。
要是你习惯用命令行运行,那每次启动可执行文件的时候,先切换到项目根目录再运行就行,比如:
cd /path/to/your/project ./build/Core/Core
这样程序里的相对路径Shaders/xxx.glsl就会对应源码目录里的资源。
方案二:通过CMake传递资源根目录宏
这个方法更灵活,不管可执行文件在哪个目录运行,都能精准找到资源。核心思路是在CMake里把源码目录的路径作为预处理器宏传给代码,程序里直接用这个宏拼接资源路径。
在CMake里给你的目标添加编译定义:
target_compile_definitions(Core PRIVATE ASSET_ROOT="${CMAKE_CURRENT_SOURCE_DIR}" )
然后在你的C++代码里,直接用这个宏来构建资源路径:
std::string vertexShaderPath = std::string(ASSET_ROOT) + "/Shaders/vertex.glsl";
这样不管你在哪运行可执行文件,都会直接从源码目录读取资源,完全不用复制。
方案三:调整可执行文件输出目录到项目根目录下的独立文件夹
如果你不想改工作目录也不想改代码,可以把可执行文件输出到项目根目录下的bin文件夹里,这样程序里的相对路径只需要往上跳一级就能找到资源。
在CMake里设置全局的运行时输出目录:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin")
这样编译出来的可执行文件会放在项目根目录的bin文件夹里,程序里用../Shaders/xxx.glsl就能定位到源码里的资源文件夹,同样不用复制任何文件。
对比你现在用的copy_directory方法,这几个方案都能避免重复复制资源,尤其是方案二,几乎没有副作用,不管是调试还是发布都能稳定工作。
内容来源于stack exchange

