【发布时间】:2020-03-25 06:28:03
【问题描述】:
我有一个在 CMake 构建过程中生成的文件列表。之后我想使用“add_library”编译这些文件,但在生成之前我不知道生成了哪些文件。有没有办法将它构建到 CMake 脚本中?
【问题讨论】:
标签: cmake
我有一个在 CMake 构建过程中生成的文件列表。之后我想使用“add_library”编译这些文件,但在生成之前我不知道生成了哪些文件。有没有办法将它构建到 CMake 脚本中?
【问题讨论】:
标签: cmake
嗯,我认为这是可能的,所以我将分享我所做的。我的问题是我必须编译几个 CORBA idl 以用作项目源代码的一部分,而且我不想手动列出每个文件。我认为最好找到文件。所以我这样做了:
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、*C.h、*S.cpp 和 *S.h),则 GENERATED 属性很有用,因此构建命令不会抱怨文件没有'不存在。
【讨论】:
嗯,可以使用 CMake 的 CMAKE_CONFIGURE_DEPENDS 目录属性来做到这一点。如果任何给定文件发生更改,这将强制 CMake 重新配置。
以下代码显示了单个模型文件的方法,该文件用作代码生成的输入:
set(MODEL_FILE your_model_file)
set_directory_properties(PROPERTIES CMAKE_CONFIGURE_DEPENDS ${MODEL_FILE})
set(GENERATED_SOURCE_DIR ${CMAKE_CURRENT_BINARY_DIR}/${MODEL_FILE})
file(REMOVE_RECURSE ${GENERATED_SOURCE_DIR})
file(MAKE_DIRECTORY ${GENERATED_SOURCE_DIR})
execute_process(COMMAND your_code_generation_tool -o ${GENERATED_SOURCE_DIR} ${MODEL_FILE})
file(GLOB LIBGENERATED_FILES ${GENERATED_SOURCE_DIR}/*)
add_library(libgenerated ${LIBGENERATED_FILES})
target_include_directories(libgenerated ${GENERATED_SOURCE_DIR})
使用上述方法,每次模型文件更改时,CMake 都会重新配置,从而重新生成模型。
简单解决方案的问题在于,即使是模型中可能发生的最小变化,也必须重新构建生成文件的整个依赖关系。
高级方法使用 CMake 的 copy_if_different 功能,仅让受模型更改影响的生成文件显示为已修改,从而缩短构建时间。为了实现这一点,我们使用暂存目录作为生成器的目标,然后将内容与之前编译运行的生成器输出同步:
set(MODEL_FILE your_model_file)
set(GENERATOR_STAGING_DIR ${CMAKE_CURRENT_BINARY_DIR}/${MODEL_FILE}.staging)
set(GENERATOR_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/${MODEL_FILE})
set_directory_properties(PROPERTIES CMAKE_CONFIGURE_DEPENDS ${MODEL_FILE})
# Create fresh staging/final output directory
file(REMOVE_RECURSE ${GENERATOR_STAGING_DIR})
file(MAKE_DIRECTORY ${GENERATOR_STAGING_DIR})
file(MAKE_DIRECTORY ${GENERATOR_OUTPUT_DIR})
# Run code generation
execute_process(COMMAND your_code_generation_tool -o ${GENERATOR_STAGING_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/${MODEL_FILE}")
# Remove stale files from final generator output directory
file(GLOB GENERATED_FILES RELATIVE "${GENERATOR_OUTPUT_DIR}/" "${GENERATOR_OUTPUT_DIR}/*")
foreach(FILE ${GENERATED_FILES})
if(NOT EXISTS "${GENERATOR_STAGING_DIR}/${FILE}")
file(REMOVE "${GENERATOR_OUTPUT_DIR}/${FILE}")
endif()
endforeach()
# Copy modified files from staging to final generator output directory
file(GLOB GENERATED_FILES RELATIVE "${GENERATOR_STAGING_DIR}/" "${GENERATOR_STAGING_DIR}/*")
foreach(FILE ${GENERATED_FILES})
execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${GENERATOR_STAGING_DIR}/${FILE}" "${GENERATOR_OUTPUT_DIR}")
endforeach()
file(GLOB LIBGENERATED_FILES "${GENERATOR_OUTPUT_DIR}/*")
add_library(libgenerated ${LIBGENERATED_FILES})
target_include_directories(libgenerated PUBLIC ${GENERATOR_OUTPUT_DIR})
【讨论】:
如果您不知道将要生成的文件的名称,您可以“glob”它们所在的文件夹。
file( GLOB_RECURSE MY_SRC dest_folder/*.cpp )add_library( libname SHARED ${MY_SRC} )
现在我不确定是什么触发了这些文件的生成。 “globbing”只会在您手动运行 cmake 时发生:它无法自动检测到新文件是否存在。
【讨论】:
将此视为非答案,仅提供更多信息:
我最近不得不为一个案例做一些事情,我有一个自动生成的 .cpp 文件,但我不知道如何让 CMake 构建然后编译它的 Visual Studio 项目文件。我不得不求助于一些非常臭的东西:我不得不从位于${CMAKE_CURRENT_SOURCE} 目录下的另一个文件中创建#include <the_generated.cpp> 文件。这对您的情况没有多大帮助,因为我怀疑您有多个 .cpp 文件,因此这种方法不可扩展。
另外,我发现GENERATED 源文件属性在添加到文件时根本没有帮助。
我认为这种情况是 Visual Studio 中的错误(在我的情况下是 VS2008 SP1),或者 CMake 如何生成 .vcproj 文件,或两者兼而有之。
【讨论】: