CMake 为源文件提供相对路径版本的 __FILE__
CMake 起初有一个 CMAKE_USE_RELATIVE_PATHS 可以用来告诉 CMake 给底层工具传相对路径,但 3.4 版本之后这个变量被移除了,导致这样的代码:
1 | std::cout << __FILE__ << '\n'; |
会输出绝对路径,比如 /home/user/Projects/proj/src/foo.cpp ,前面的一串 /home/user/Projects/proj 都与项目无关,而且包含用户名 user ,一不小心就会像某个腾讯员工一样,在程序文件里塞进了自己的姓名,这是何等的社死。
之前一直没有在乎这种东西,因为一直没有(现在也没有)向别人提供编译好的二进制文件的需求,但最近折腾了 CMake 的各种细节,所以打算想办法解决一下这个问题
1. 拿到相对路径
无论如何要先能在 CMakeLists.txt 里推算出相对路径版本的 __FILE__ , CMake 有 file() 函数(因为我使用 CMake 3.9 ,所以不能使用 cmake_path ):
1 | # 比如源文件为 `src` |
这样输出的 src_relpath 就是相对 project() 函数所在目录的相对路径了
2. 拿到 Target 的所有源文件
要更方便地为 Target 的每个源文件设置相对路径版本的 __FILE__ ,最好是可以通过 Target 拿到每个源文件:
1 | # 比如 Target 为 `target_name` |
这样输出的 target_srcs 就包含了 target_name 的所有源文件了,可以用 foreach() 遍历每个源文件:
1 | foreach(target_src ${target_srcs}) |
3. 为源文件定义相对路径版本的 __FILE__
我个人并不想覆盖掉原汁原味的 __FILE__ ,所以打算另外定义一个 __REL_FILE__ 宏,表示 __FILE__ 的相对路径( RELative path )版本:
点击展开:之前的错误版本
)
1 | set_source_files_properties(${target_src} PROPERTIES COMPILE_DEFINITIONS "__REL_FILE__=\"${target_src_relpath}\"") |
用 set_property(APPEND) 更稳妥一些:
1 | set_property(SOURCE ${target_src} APPEND PROPERTY COMPILE_DEFINITIONS "__REL_FILE__=\"${target_src_relpath}\"") |
4. 跳过本身就是相对路径的源文件
这样拿到的 target_src 是来自 add_executable() 或 add_library() 的,有时可能不是像这样精确的:
1 | add_executable(foo ${PROJECT_SOURCE_DIR}/src/foo.cpp) |
而是直接传相对路径:
1 | add_executable(foo src/foo.cpp) |
这样拿到的 target_src 本身就是相对路径,再对它调用 file(RELATIVE_PATH) 会报错,所以可以跳过这样的路径:
1 | if(NOT IS_ABSOLUTE ${target_src}) |
总结
总结到一起可以定义一个 target_define_relative_path 函数:
1 | # Add a relative path version of the __FILE__ macro named __REL_FILE__ to all source files of the target. |
这样每个源文件都会有一个 __REL_FILE__ 宏,表示自己相对 project_root 的相对路径