2013-03-07 89 views
8

我是新来的CMake和我有,我不能想出一个解决问题的办法。我正在使用CMake编译一个项目,其中包含一系列可选的子目录,并按预期构建共享库文件。这部分似乎工作正常。这些子目录中的每一个都包含一个sql文件。我需要将所有选定的sql文件连接到一个sql头文件并安装结果。所以一个文件,如:使用cmake,我怎么能Concat的文件,并安装它们

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的初始运行,当它从化妆运行安装之间丢失。也许有更好的方法来做到这一点。我需要这个在Windows和Linux上工作。

我将很高兴与一些提示点我在正确的方向。

回答

10

您可以创建主要使用的CMake的filefunction命令连结文件。

首先,创建一个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 install”后,才会将文件从build root复制到安装位置。

+0

尼斯使用configure_file的... ;-) – DLRdave 2013-03-08 14:48:22

+0

谢谢,这是非常有益的。如果你在多个深度有多个目录,那么让结果冒泡是很棘手的,但是我使用你非常有用的建议来解决它。谢谢! – 2013-03-08 15:16:59

+0

我试过了,它的工作原理...除非文件有分号,在这一点上它会失败,因为分号会被无声地去掉。这是分号作为cmake中列表分隔符的正常结果。显示问题的最简单的测试用例是'set(CONTENTS“a; b; c \ n”) file(WRITE out.txt $ {CONTENTS})'修复是在写入时引用内容, '“$ {CONTENTS}”' – 2014-10-10 01:54:30