我是CMake的新手,我遇到了一个无法找到解决方案的问题。我正在使用CMake编译一个带有一堆可选子目录的项目,并按预期构建共享库文件。这部分似乎工作正常。这些子目录中的每一个都包含一个sql文件。我需要将所有选定的sql文件连接到一个sql头文件并安装结果。所以一个文件如:
sql_header.sql
sub_dir_A.sql
sub_dir_C.sql
sub_dir_D.sql
如果我直接在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"
我有点想出这些,就像我可以使用的那样:
LIST(APPEND PACKAGE_SQL_FILES "some_file.sql")
我假设我可以放在每个子目录CMakeLists.txt文件中以收集文件名。我可以创建一个像:
的宏CAT(IN "${PACKAGE_SQL_FILES}" OUT "${INSTALL_PATH}/somefile.sql")
但是我在CMake最初运行和从make install运行之间迷路了。也许有更好的方法来做到这一点。我需要这个在Windows和Linux上工作。
我会很高兴有一些提示指出我正确的方向。
答案 0 :(得分:13)
您可以主要使用CMake的file
和function
命令创建连接文件。
首先,创建一个cat
函数:
function(cat IN_FILE OUT_FILE)
file(READ ${IN_FILE} CONTENTS)
file(APPEND ${OUT_FILE} "${CONTENTS}")
endfunction()
假设您有变量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)
写入临时文件的原因是真实的目标文件只有在其内容发生变化时才会更新。请参阅this answer了解为什么这是一件好事。
您应该注意,如果您通过add_subdirectory
命令包含子目录,则就CMake变量而言,子目录都有自己的范围。在子目录中,使用list
只会影响该子目录范围内的变量。
如果要在父作用域中创建可用列表,则需要使用set(... PARENT_SCOPE)
,例如
set(PACKAGE_SQL_FILES
${PACKAGE_SQL_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/some_file.sql
PARENT_SCOPE)
到目前为止,所有这些只是在构建树的根目录中创建了连接文件。要安装它,您可能希望使用install(FILES ...)
命令:
install(FILES ${CMAKE_BINARY_DIR}/somefile.sql
DESTINATION ${INSTALL_PATH})
因此,每当CMake运行时(或者因为您手动调用它或者因为它在执行" make"时检测到更改),它将更新构建树中的连接文件。只有在你运行" make install"最终将文件从构建根目录复制到安装位置。
答案 1 :(得分:1)
从CMake 3.18开始,CMake command line tool可以使用cat
连接文件。因此,假设变量PACKAGE_SQL_FILES
包含文件列表,则可以使用execute_process
运行cat
命令:
# 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})
解决方案的其余部分类似于Fraser的响应。您可以使用configure_file
,以便仅在必要时更新结果文件。
configure_file(final.sql.in final.sql COPYONLY)
您仍然可以通过相同的方式使用install
来安装文件:
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/final.sql
DESTINATION ${INSTALL_PATH})