CMake编译生成的文件

时间:2010-11-19 05:22:04

标签: cmake

我有一个在CMake构建过程中生成的文件列表。我想在之后使用“add_library”编译这些文件,但我不知道哪些文件在生成之后才生成。无论如何将它构建为CMake脚本?

4 个答案:

答案 0 :(得分:12)

嗯,我认为这是可能的,所以我会分享我所做的。我的问题是我必须编译几个CORBA idls作为项目源的一部分,我不想手动列出每个文件。我觉得找文件会更好。所以我这样做了:

file(GLOB IDLS "idls/*.idl")
set(ACE_ROOT ${CMAKE_FIND_ROOT_PATH}/ace/ACE-${ACE_VERSION})
foreach(GENERATE_IDL ${IDLS})
   get_filename_component(IDLNAME ${GENERATE_IDL} NAME_WE)
   set(OUT_NAME ${CMAKE_CURRENT_SOURCE_DIR}/idls_out/${IDLNAME})

   list(APPEND IDL_COMPILED_FILES ${OUT_NAME}C.h ${OUT_NAME}C.cpp ${OUT_NAME}S.h ${OUT_NAME}S.cpp)

   add_custom_command(OUTPUT ${OUT_NAME}C.h ${OUT_NAME}C.cpp ${OUT_NAME}S.h ${OUT_NAME}S.cpp
                      COMMAND ${ACE_ROOT}/bin/tao_idl -g ${ACE_ROOT}/bin/ace_gperf -Sci -Ssi -Wb,export_macro=TAO_Export -Wb,export_include=${ACE_ROOT}/include/tao/TAO_Export.h -Wb,pre_include=${ACE_ROOT}/include/ace/pre.h -Wb,post_include=${ACE_ROOT}/include/ace/post.h -I${ACE_ROOT}/include/tao -I${CMAKE_CURRENT_SOURCE_DIR} ${GENERATE_IDL} -o ${CMAKE_CURRENT_SOURCE_DIR}/idls_out/
                      COMMENT "Compiling ${GENERATE_IDL}")
endforeach(GENERATE_IDL)

set_source_files_properties(${IDL_COMPILED_FILES}
                            PROPERTIES GENERATED TRUE)

set(TARGET_NAME ${PROJECT_NAME}${DEBUG_SUFFIX})

add_executable(
   ${TARGET_NAME}
   ${SOURCE} 
   ${IDL_COMPILED_FILES}
)

如果没有创建我的一个idl编译输出(* C.cpp,* Ch,* S.cpp和* Sh),那么GENERATED属性很有用,因此build命令不会抱怨该文件没有不存在。

答案 1 :(得分:10)

嗯,使用CMake的ExternalProject功能可以使用两个CMake脚本。

简单的解决方案

在主CMake脚本中,您需要添加一个生成源文件的自定义目标,如下所示,并引用第二个(外部)CMake 项目:

# Main CMakeLists.txt    
add_custom_target(
    code_generation
    COMMAND your_code_generation_tool -o ${CMAKE_CURRENT_BINARY_DIR}/libgenerated/
)

include(ExternalProject)
ExternalProject_Add(
    libgenerated
    DEPENDS code_generation
    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/path/to/external/project/
    BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/libgenerated-build
    CMAKE_ARGS -DGENERATED_SOURCE_DIR=${CMAKE_CURRENT_BINARY_DIR}/libgenerated
    BUILD_ALWAYS 1
    INSTALL_CMD ""
)

add_executable(
    ${PROJECT_NAME}
    ...
)

target_link_libraries(
    ${PROJECT_NAME} 
    ${CMAKE_CURRENT_BINARY_DIR}/libgenerated-build/libgenerated.a
)

add_dependencies(${PROJECT_NAME} libgenerated)

现在,您可以在第二个(外部)CMake脚本中执行文件通配,并将找到的所有文件链接到静态库中:

# External project CMakeLists.txt
project(libgenerated)
file(GLOB_RECURSE SOURCES ${GENERATED_SOURCE_DIR}/*)
add_library(${PROJECT_NAME} ${SOURCES})

在这个简单的解决方案中,即使没有任何更改,每次运行构建步骤时都会生成并构建文件。如果您想避免这种情况,可以将标记文件添加到自定义目标,如以下改进的解决方案:

图章文件解决方案

# Main CMakeLists.txt    
add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/libgenerated-stamp
    COMMAND your_code_generation_tool -o ${CMAKE_CURRENT_BINARY_DIR}/libgenerated/
    COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/libgenerated-stamp
    DEPENDS the_input_file(s)_you_generate_your_code_from
)

add_custom_target(
    code_generation
    DEPENDS ${CMAKE_CURRENT_BUILD_DIR}/libgenerated-stamp
)

...

如果代码生成器的输入文件中的更改未必导致所有生成的文件发生更改,则可以通过在外部项目中使用CMake的copy_if_different命令来进一步改进解决方案,例如以下高级解决方案:

高级解决方案

# External project CMakeLists.txt
project(libgenerated)
file(GLOB_RECURSE SOURCES ${GENERATED_SOURCE_DIR}/*)

add_custom_target(
    make_directory
    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/generated
)

foreach(FILE ${SOURCES})
    get_filename_component(BASENAME ${FILE} NAME)
    list(APPEND ACTUAL_SOURCES "${CMAKE_CURRENT_BINARY_DIR}/generated/${BASENAME}")
    add_custom_target(
        copy_${BASENAME}_if_different
        COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FILE}     ${CMAKE_CURRENT_BINARY_DIR}/generated
    )
    add_dependencies(make_directory copy_${BASENAME}_if_different)
endforeach()

add_library(${PROJECT_NAME} ${ACTUAL_SOURCES})
add_dependencies(${PROJECT_NAME} make_directory)

在此解决方案中,所有生成的文件都会被复制到另一个位置(${CMAKE_CURRENT_BINARY_DIR}/generated),如果它们已经更改或已添加并从那里构建。这种方法只会导致更改文件的构建(但在删除文件时需要清理)。

答案 2 :(得分:2)

如果你不知道将要生成的文件的名称,你可以“全局”它们所在的文件夹。

file( GLOB_RECURSE MY_SRC dest_folder/*.cpp )
add_library( libname SHARED ${MY_SRC} )

现在我不确定是什么触发了这些文件的生成。只有在手动运行cmake时才会出现“globbing”:它将无法自动检测到新文件是否存在。

答案 3 :(得分:1)

将此视为非答案,更多信息:

我最近不得不为一个案例做一些事情,我有一个自动生成的.cpp文件,但我无法弄清楚如何让CMake构建Visual Studio项目文件然后编译它。我不得不采取一些非常臭的东西:我必须从另一个位于#include <the_generated.cpp>目录下的文件中${CMAKE_CURRENT_SOURCE}文件。这对你的情况没什么帮助,因为我怀疑你有几个.cpp文件,所以这种方法不可扩展。

另外,我发现GENERATED源文件属性在添加到文件时根本没有帮助。

我认为这种情况要么是Visual Studio中的错误(在我的情况下是VS2008 SP1),要么是CMake如何生成.vcproj文件,或两者兼而有之。