我是CMake的新手,我有一个问题,我无法找到解决方案.我正在使用CMake编译一个带有一堆可选子目录的项目,并按预期构建共享库文件.这部分似乎工作正常.这些子目录中的每一个都包含一个sql文件.我需要将所有选定的sql文件连接到一个sql头文件并安装结果.所以一个文件像:
sql_header.sql
sub_dir_A.sql
sub_dir_C.sql
sub_dir_D.sql
Run Code Online (Sandbox Code Playgroud)
如果我直接在make文件中执行此操作,我可能会执行类似以下操作,只更智能地处理选定的子目录:
cat sql_header.sql > "${INSTALL_PATH}/somefile.sql"
cat sub_dir_A.sql >> "${INSTALL_PATH}/somefile.sql"
cat sub_dir_C.sql >> "${INSTALL_PATH}/somefile.sql"
cat sub_dir_D.sql >> "${INSTALL_PATH}/somefile.sql"
Run Code Online (Sandbox Code Playgroud)
我有点想出这个,就像我可以使用:
LIST(APPEND PACKAGE_SQL_FILES "some_file.sql")
Run Code Online (Sandbox Code Playgroud)
我假设我可以放在每个子目录CMakeLists.txt文件中以收集文件名.我可以创建一个像:
CAT(IN "${PACKAGE_SQL_FILES}" OUT "${INSTALL_PATH}/somefile.sql")
Run Code Online (Sandbox Code Playgroud)
但是我在CMake最初运行和从make install运行之间迷路了.也许有更好的方法来做到这一点.我需要这个在Windows和Linux上工作.
我会很高兴有一些提示指出我正确的方向.
Fra*_*ser 13
您可以主要使用CMake file和function命令创建连接文件.
首先,创建一个cat函数:
function(cat IN_FILE OUT_FILE)
file(READ ${IN_FILE} CONTENTS)
file(APPEND ${OUT_FILE} "${CONTENTS}")
endfunction()
Run Code Online (Sandbox Code Playgroud)
假设您有变量中的输入文件列表PACKAGE_SQL_FILES,您可以使用如下函数:
# Prepare a temporary file to "cat" to:
file(WRITE somefile.sql.in "")
# Call the "cat" function for each input file
foreach(PACKAGE_SQL_FILE ${PACKAGE_SQL_FILES})
cat(${PACKAGE_SQL_FILE} somefile.sql.in)
endforeach()
# Copy the temporary file to the final location
configure_file(somefile.sql.in somefile.sql COPYONLY)
Run Code Online (Sandbox Code Playgroud)
写入临时文件的原因是真实的目标文件只有在其内容发生变化时才会更新.看到这个答案,为什么这是一件好事.
您应该注意,如果您通过add_subdirectory命令包含子目录,则就CMake变量而言,子目录都有自己的范围.在子目录中,using list仅影响该子目录范围内的变量.
如果要在父作用域中创建可用列表,则需要使用set(... PARENT_SCOPE),例如
set(PACKAGE_SQL_FILES
${PACKAGE_SQL_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/some_file.sql
PARENT_SCOPE)
Run Code Online (Sandbox Code Playgroud)
到目前为止,所有这些只是在构建树的根目录中创建了连接文件.要安装它,您可能希望使用以下install(FILES ...)命令:
install(FILES ${CMAKE_BINARY_DIR}/somefile.sql
DESTINATION ${INSTALL_PATH})
Run Code Online (Sandbox Code Playgroud)
因此,每当CMake运行时(或者因为您手动调用它或者因为它在执行"make"时检测到更改),它将更新构建树中的连接文件.只有运行"make install"后,文件才会从构建根目录复制到安装位置.
从 CMake 3.18 开始,CMake命令行工具可以使用cat. 因此,假设一个PACKAGE_SQL_FILES包含文件列表的变量,您可以cat使用execute_process以下命令运行命令:
# Concatenate the sql files into a variable 'FINAL_FILE'.
execute_process(COMMAND ${CMAKE_COMMAND} -E cat ${PACKAGE_SQL_FILES}
OUTPUT_VARIABLE FINAL_FILE
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
# Write out the concatenated contents to 'final.sql.in'.
file(WRITE final.sql.in ${FINAL_FILE})
Run Code Online (Sandbox Code Playgroud)
其余的解决方案类似于弗雷泽的回应。您可以使用configure_file这样生成的文件仅在必要时更新。
configure_file(final.sql.in final.sql COPYONLY)
Run Code Online (Sandbox Code Playgroud)
你仍然可以用install同样的方式来安装文件:
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/final.sql
DESTINATION ${INSTALL_PATH})
Run Code Online (Sandbox Code Playgroud)