11

我是 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 上工作。

我会很高兴有一些提示可以为我指明正确的方向。

4

2 回答 2

18

您可以主要使用 CMakefilefunction命令创建连接文件。

首先,创建一个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)

写入临时文件的原因是真正的目标文件只有在其内容发生变化时才会更新。请参阅此答案,了解为什么这是一件好事。

您应该注意,如果您通过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”后,文件才会最终从构建根目录复制到安装位置。

于 2013-03-07T22:33:10.797 回答
5

从 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})

解决方案的其余部分类似于弗雷泽的回应。您可以使用configure_file因此生成的文件仅在必要时更新。

configure_file(final.sql.in final.sql COPYONLY)

您仍然可以使用install相同的方式安装文件:

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/final.sql
    DESTINATION ${INSTALL_PATH})
于 2020-06-13T16:46:32.093 回答