我有一个 git 存储库,其中另一个存储库作为子模块。我希望将子模块中的单个文件符号链接到我的存储库中,而不是在 CMakeLists.txt 中维护 file(COPY ...) 行。由于它是一个存储库,因此符号链接必须是相对的。
是否可以告诉 cmake,在复制之前将符号链接解析为绝对路径,或者复制链接文件?
我正在寻找一个通用选项。如果我必须为每个文件添加特定命令,我不妨使用 file(COPY ...)
使用的cmake版本是3.16.3
一些背景:
我们有一个服务器应用程序,可以针对各种前端构建。每个前端都需要自己的配置,但它们共享一些文件。
为了自动化配置,我们使用配置生成器脚本。该脚本使用一组文件和目录,这些文件和目录是由 cmake 从源中准备的。
我想通过添加由应用程序开发人员维护的配置存储库作为我的配置存储库的子模块,在这些配置之间共享一些文件。
对我来说,符号链接更容易维护并且更明显。部分原因是,除了更改版本之外,更新期间通常不会触及 CMakeLists.txt。一些要链接的文件在其他源文件中引用,并且在开发过程中可能需要引用。如果开发人员不知道该文件是在构建生成期间从其他地方复制的,则丢失的文件可能会导致一些混乱。
示例:
<repository>/shared/dir/file
<repository>/dir
cd <repository>/dir
ln -s ../shared/dir/file .
project(example NONE)
set(${PROJECT_NAME}_MAJOR_VERSION 00)
set(${PROJECT_NAME}_MINOR_VERSION 01)
set(${PROJECT_NAME}_PATCH_VERSION 00)
include(cmake/set_version_numbers.cmake)
include(cmake/config_generator_project.cmake)
cmake <path_to_repository>
结果:损坏的符号链接
<build-dir>/dir/file
,而不是文件或符号链接。
简短的回答是:是的,这是可能的,但并不容易。 较长的答案:
首先我要解释一下我的一个误解。我非常习惯使用这个项目模板,我认为将源文件复制到构建目录是 cmake 的固有过程。它不是。它实际上在项目模板中的 cmake 脚本之一中进行了描述。
其次,没有单个命令或选项可以告诉 cmake 通过复制链接文件来解析链接(至少在 cmake 版本 3.16 之前)。相反,我替换了以下命令:
file(COPY "${PROJECT_SOURCE_DIR}" DESTINATION "${PROJECT_BINARY_DIR}")
有了这个功能:
function(copy_with_resolved_links source_dir target_dir)
file(GLOB_RECURSE file_list LIST_DIRECTORIES true "${source_dir}/*")
file(MAKE_DIRECTORY "${target_dir}/temp")
foreach(file ${file_list})
file(RELATIVE_PATH rpath_file "${PROJECT_SOURCE_DIR}" ${file})
get_filename_component(rpath_dir ${rpath_file} DIRECTORY)
if(IS_DIRECTORY ${file})
file(MAKE_DIRECTORY "${target_dir}/${rpath_file}")
elseif(IS_SYMLINK ${file})
file(READ_SYMLINK "${file}" link)
get_filename_component(fn_target "${file}" NAME)
get_filename_component(fn_link "${link}" NAME)
if(NOT IS_ABSOLUTE ${link})
get_filename_component(dir "${file}" DIRECTORY)
file(COPY "${dir}/${link}" DESTINATION "${target_dir}/temp")
file(RENAME "${target_dir}/temp/${fn_link}" "${target_dir}/${rpath_file}")
else()
file(COPY "${link}" DESTINATION "${target_dir}/temp")
file(RENAME "${target_dir}/temp/${fn_link}" "${target_dir}/${rpath_file}")
endif()
else()
file(COPY ${file} DESTINATION "${target_dir}/${rpath_dir}")
endif()
endforeach()
file(REMOVE_RECURSE "${target_dir}/temp")
endfunction()
此函数复制链接文件,而不是链接文件,但将其名称更改为链接文件之一。