cmake - español - qgis girona
CMake compilando archivos generados (4)
Bueno, creo que es posible, así que compartiré lo que he hecho. Mi problema fue que tuve que compilar varios identificadores de CORBA para usar como parte de la fuente de un proyecto y no quería enumerar manualmente cada archivo. Pensé que sería mejor encontrar los archivos. Así lo hice así:
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}
)
Las propiedades GENERADAS son útiles en caso de que no se cree una de mis salidas de compilación idl (* C.cpp, * Ch, * S.cpp y * Sh), por lo que el comando de compilación no se queja de que el archivo no existe .
Tengo una lista de archivos que se generan durante el proceso de construcción de CMake. Quiero compilar estos archivos usando "add_library" después, pero no sabré qué archivos se generan hasta después de que se generen. ¿Hay alguna forma de construir esto en un script CMake?
Bueno, es posible hacerlo con dos scripts CMake usando la función ExternalProject de CMake.
La solucion simple
En la secuencia de comandos principal de CMake, debe agregar un objetivo personalizado que genere los archivos de origen de la siguiente manera y una referencia al segundo proyecto CMake (externo):
# 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)
Ahora puede realizar el agrupamiento de archivos en el segundo script CMake (externo) y vincular todos los archivos encontrados en una biblioteca estática:
# External project CMakeLists.txt
project(libgenerated)
file(GLOB_RECURSE SOURCES ${GENERATED_SOURCE_DIR}/*)
add_library(${PROJECT_NAME} ${SOURCES})
En esta solución simple, sus archivos se generan y construyen cada vez que ejecuta el paso de compilación, incluso si nada cambia. Si desea evitar esto, puede agregar un archivo de sello a su destino personalizado como en la siguiente solución mejorada:
La solución de archivo de sello
# 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
)
...
Si un cambio en los archivos de entrada para su generador de código no resulta necesariamente en un cambio de todos los archivos generados, puede mejorar aún más la solución utilizando el comando copy_if_different
de CMake en el proyecto externo, como en la siguiente solución avanzada:
La solucion avanzada
# 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)
En esta solución, todos los archivos generados se copian en otra ubicación ( ${CMAKE_CURRENT_BINARY_DIR}/generated
) si se han cambiado o se han agregado y se han creado desde allí. Este enfoque da como resultado una compilación de archivos modificados solamente (pero requiere una limpieza cuando se eliminan los archivos).
Si no sabe el nombre de los archivos que se generarán, puede "agrupar" las carpetas donde se encuentran.
file( GLOB_RECURSE MY_SRC dest_folder/*.cpp )
add_library( libname SHARED ${MY_SRC} )
Ahora no estoy seguro de lo que desencadena la generación de estos archivos. El "globbing" ocurrirá solo cuando ejecute manualmente cmake: no podrá detectar automáticamente que hay nuevos archivos presentes.
Trate esto como una no-respuesta, solo más información:
Hace poco tuve que hacer algo en un caso en el que tenía un archivo .cpp que se generó automáticamente, pero no pude averiguar cómo hacer que CMake construya el archivo de proyecto de Visual Studio que luego lo compilaría. Tuve que recurrir a algo bastante apestoso: tuve que #include <the_generated.cpp>
de otro archivo que se encontraba en el directorio ${CMAKE_CURRENT_SOURCE}
. Eso no te ayudará mucho en tu caso porque sospecho que tienes varios archivos .cpp, por lo que este enfoque no es escalable.
Además, encontré que la propiedad del archivo de origen GENERATED
, cuando se agrega al archivo, no ayuda en absoluto.
Considero que esta condición es un error en Visual Studio (en mi caso fue VS2008 SP1), o en cómo CMake genera los archivos .vcproj, o ambos.