txt online not how found descarga cmakelists c++ cmake

c++ - online - descarga cmake



CMake: elimina una marca de compilación para una sola unidad de traducción (3)

Me gustaría eliminar una marca de compilación establecida para una unidad de traducción única. ¿Hay alguna forma de hacer esto? (por ejemplo, usando set_property ?)

Nota: el indicador de compilación no tiene ninguna negación -fno-name (por cualquier motivo).

He intentado:

get_property(FLAGS TARGET target PROPERTY COMPILE_FLAGS) string(REPLACE "-fname" "" FLAGS ${FLAGS}) set_property(TARGET target PROPERTY COMPILE_FLAGS ${FLAGS})

sin suerte La propiedad que quiero eliminar es parte de CMAKE_CXX_FLAGS y, por lo tanto, esto no funciona.


Esta solución particular (?) .cpp tanto para objetivos como para unidades de traducción individuales (un solo .cpp .cpp). Requerirá CMake 3.7 o más reciente, ya que debemos recorrer todas las targes existentes utilizando la propiedad BUILDSYSTEM_TARGETS , que se agregó en 3.7 . Si no puede usar 3.7 o más reciente, puede adaptar apply_global_cxx_flags_to_all_targets() para tomar una lista de objetivos y especificarlos manualmente. Tenga en cuenta que debe considerar las siguientes macros como prueba de concepto. Probablemente necesitarán algunos ajustes y mejoras para cualquier proyecto que no sea muy pequeño.

El primer paso es recorrer todos los destinos existentes y aplicar CMAKE_CXX_FLAGS a cada uno de ellos. Cuando se hace esto, CMAKE_CXX_FLAGS . A continuación encontrarás una macro que hará esto. Probablemente esta macro debería llamarse en algún lugar al final de su CMakeLists.txt nivel CMakeLists.txt , cuando se hayan creado todos los objetivos, se hayan establecido todos los indicadores, etc. Es importante tener en cuenta que el comando get_property(_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS) funciona en el directorio nivel, por lo que si usa add_subdirectory() , debe llamar a esta macro en el nivel superior CMakeLists.txt de ese subdirectorio.

# # Applies CMAKE_CXX_FLAGS to all targets in the current CMake directory. # After this operation, CMAKE_CXX_FLAGS is cleared. # macro(apply_global_cxx_flags_to_all_targets) separate_arguments(_global_cxx_flags_list UNIX_COMMAND ${CMAKE_CXX_FLAGS}) get_property(_targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS) foreach(_target ${_targets}) target_compile_options(${_target} PUBLIC ${_global_cxx_flags_list}) endforeach() unset(CMAKE_CXX_FLAGS) set(_flag_sync_required TRUE) endmacro()

Esta macro primero crea una lista de CMAKE_CXX_FLAGS , luego obtiene una lista de todos los destinos y aplica CMAKE_CXX_FLAGS a cada uno de los objetivos. Finalmente, se borra CMAKE_CXX_FLAGS . _flag_sync_required se usa para indicar si necesitamos forzar una reescritura de las variables en caché.

El siguiente paso depende de si desea eliminar una bandera de un objetivo o de una unidad de traducción en particular. Si desea eliminar una bandera de un destino, puede utilizar una macro similar a esta:

# # Removes the specified compile flag from the specified target. # _target - The target to remove the compile flag from # _flag - The compile flag to remove # # Pre: apply_global_cxx_flags_to_all_targets() must be invoked. # macro(remove_flag_from_target _target _flag) get_target_property(_target_cxx_flags ${_target} COMPILE_OPTIONS) if(_target_cxx_flags) list(REMOVE_ITEM _target_cxx_flags ${_flag}) set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "${_target_cxx_flags}") endif() endmacro()

Eliminar una bandera de una unidad de traducción en particular es un poco más complicado (a menos que haya pasado algo por alto). De todos modos, la idea es obtener primero las opciones de compilación del destino al que pertenece el archivo, y luego aplicar dichas opciones a todos los archivos de origen en ese objetivo, lo que nos permite manipular los indicadores de compilación para archivos individuales. Hacemos esto manteniendo una lista en caché de banderas de compilación para cada archivo del que queremos eliminarlas, y cuando se solicita una eliminación, la eliminamos de la lista en caché y luego volvemos a aplicar las banderas restantes. Las opciones de compilación para el objetivo en sí están desactivadas.

# # Removes the specified compiler flag from the specified file. # _target - The target that _file belongs to # _file - The file to remove the compiler flag from # _flag - The compiler flag to remove. # # Pre: apply_global_cxx_flags_to_all_targets() must be invoked. # macro(remove_flag_from_file _target _file _flag) get_target_property(_target_sources ${_target} SOURCES) # Check if a sync is required, in which case we''ll force a rewrite of the cache variables. if(_flag_sync_required) unset(_cached_${_target}_cxx_flags CACHE) unset(_cached_${_target}_${_file}_cxx_flags CACHE) endif() get_target_property(_${_target}_cxx_flags ${_target} COMPILE_OPTIONS) # On first entry, cache the target compile flags and apply them to each source file # in the target. if(NOT _cached_${_target}_cxx_flags) # Obtain and cache the target compiler options, then clear them. get_target_property(_target_cxx_flags ${_target} COMPILE_OPTIONS) set(_cached_${_target}_cxx_flags "${_target_cxx_flags}" CACHE INTERNAL "") set_target_properties(${_target} PROPERTIES COMPILE_OPTIONS "") # Apply the target compile flags to each source file. foreach(_source_file ${_target_sources}) # Check for pre-existing flags set by set_source_files_properties(). get_source_file_property(_source_file_cxx_flags ${_source_file} COMPILE_FLAGS) if(_source_file_cxx_flags) separate_arguments(_source_file_cxx_flags UNIX_COMMAND ${_source_file_cxx_flags}) list(APPEND _source_file_cxx_flags "${_target_cxx_flags}") else() set(_source_file_cxx_flags "${_target_cxx_flags}") endif() # Apply the compile flags to the current source file. string(REPLACE ";" " " _source_file_cxx_flags_string "${_source_file_cxx_flags}") set_source_files_properties(${_source_file} PROPERTIES COMPILE_FLAGS "${_source_file_cxx_flags_string}") endforeach() endif() list(FIND _target_sources ${_file} _file_found_at) if(_file_found_at GREATER -1) if(NOT _cached_${_target}_${_file}_cxx_flags) # Cache the compile flags for the specified file. # This is the list that we''ll be removing flags from. get_source_file_property(_source_file_cxx_flags ${_file} COMPILE_FLAGS) separate_arguments(_source_file_cxx_flags UNIX_COMMAND ${_source_file_cxx_flags}) set(_cached_${_target}_${_file}_cxx_flags ${_source_file_cxx_flags} CACHE INTERNAL "") endif() # Remove the specified flag, then re-apply the rest. list(REMOVE_ITEM _cached_${_target}_${_file}_cxx_flags ${_flag}) string(REPLACE ";" " " _cached_${_target}_${_file}_cxx_flags_string "${_cached_${_target}_${_file}_cxx_flags}") set_source_files_properties(${_file} PROPERTIES COMPILE_FLAGS "${_cached_${_target}_${_file}_cxx_flags_string}") endif() endmacro()

Ejemplo

Tenemos esta estructura de proyecto muy simple:

source/ CMakeLists.txt foo.cpp bar.cpp main.cpp

Supongamos que foo.cpp viola -Wunused-variable , y queremos deshabilitar esa bandera en ese archivo en particular. Para bar.cpp , queremos deshabilitar -Werror . Para main.cpp , queremos eliminar -O2 , por el motivo que sea.

CMakeLists.txt

cmake_minimum_required(VERSION 3.7 FATAL_ERROR) project(MyProject) # Macros omitted to save space. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wunused-variable") # CMake will apply this to all targets, so this will work too. add_compile_options("-Werror") add_executable(MyTarget foo.cpp bar.cpp main.cpp) apply_global_cxx_flags_to_all_targets() remove_flag_from_file(MyTarget foo.cpp -Wunused-variable) remove_flag_from_file(MyTarget bar.cpp -Werror) remove_flag_from_file(MyTarget main.cpp -O2)

Si, en cambio, desea eliminar un indicador de un destino, debe usar remove_flag_from_target() , por ejemplo: remove_flag_from_target(MyTarget -O2)

Resultado

Salida antes de aplicar macros.

clang++ -Werror -O2 -Wunused-variable -o foo.cpp.o -c foo.cpp clang++ -Werror -O2 -Wunused-variable -o bar.cpp.o -c bar.cpp clang++ -Werror -O2 -Wunused-variable -o main.cpp.o -c main.cpp

Salida después de aplicar macros.

clang++ -Werror -O2 -o foo.cpp.o -c foo.cpp clang++ -O2 -Wunused-variable -o bar.cpp.o -c bar.cpp clang++ -Werror -Wunused-variable -o main.cpp.o -c main.cpp

Notas finales

Como se mencionó, esto debería verse como una prueba de concepto. Hay algunos problemas inmediatos a considerar:

  • Solo considera CMAKE_CXX_FLAGS (común a todos los tipos de compilación), no CMAKE_CXX_FLAGS_<DEBUG|RELEASE> etc.
  • Las macros solo pueden manejar una bandera a la vez
  • remove_flag_from_file() solo puede manejar un archivo de entrada y destino como entrada a la vez.
  • remove_flag_from_file() espera un nombre de archivo, no una ruta. Pasar, digamos, source/foobar/foobar.cpp no funcionará, ya que source/foobar/foobar.cpp se comparará con foobar.cpp . Esto se puede solucionar utilizando get_source_file_property() y la propiedad LOCATION y colocando una condición previa para que _file sea ​​una ruta completa.
    • ¿Qué sucede si un objetivo tiene dos o más archivos con el mismo nombre?
  • remove_flag_from_file() probablemente se puede optimizar y mejorar mucho.
  • La llamada a separate_arguments() asume Unix.

La mayoría de estos deberían ser bastante fáciles de arreglar.

Espero que esto al menos lo empuje en la dirección correcta para resolver este problema. Déjame saber si necesito agregar algo a la respuesta.


Si no hay una opción de negación de bandera de compilación (que sería la forma estándar de cómo CMake maneja esto para los configuradores que no son IDE), debe eliminar esta bandera de compilación de CMAKE_CXX_FLAGS .

Posibles enfoques

  1. Convierta a COMPILE_FLAGS una propiedad de archivo fuente que se INHERITED de una propiedad de directorio con el mismo nombre. Ahora puede modificar la propiedad COMPILE_FLAGS de cada directorio y archivo de origen individualmente:

    # Remove ''-fname'' from global flags string(REPLACE "-fname" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") define_property( SOURCE PROPERTY COMPILE_FLAGS INHERITED BRIEF_DOCS "brief-doc" FULL_DOCS "full-doc" ) # Add ''-fname'' for directory set_directory_properties(PROPERTIES COMPILE_FLAGS "-fname") add_executable(${PROJECT_NAME} "main.cpp") # Remove ''-fname'' from source file set_source_files_properties("main.cpp" PROPERTIES COMPILE_FLAGS "")

  2. Si alguna propiedad, como COMPILE_OPTIONS , solo está disponible en el nivel de destino, tiene que mover los archivos para los que desea tener configuraciones diferentes a un nuevo destino independiente.

    Esto se puede hacer mediante el uso de bibliotecas OBJECT :

    # Remove ''-fname'' from global flags string(REPLACE "-fname" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") # Set ''-fname'' for directory, but if you also use add_compile_options() be aware that # this will overwrite your previous setting. Append/remove properties instead. set_directory_properties( PROPERTIES COMPILE_OPTIONS "-fname" ) # Remove ''-fname'' from source file(s) in separate object library target add_library(${PROJECT_NAME}_no_name OBJECT "main.cpp") set_target_properties( ${PROJECT_NAME}_no_name PROPERTIES COMPILE_OPTIONS "" ) # Use object library target in e.g. executable target add_executable(${PROJECT_NAME} $<TARGET_OBJECTS:${PROJECT_NAME}_no_name>)

Referencias


Una solución (no escalable y no portátil) está creando un comando personalizado con marcas modificadas. Un ejemplo mínimo que conseguí trabajando es el siguiente:

cmake_minimum_required(VERSION 2.8) project(test) # Some flags set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wall") # Remove unwanted flag string(REPLACE "-Wall" "" CUSTOM_FLAGS ${CMAKE_CXX_FLAGS}) # Split the flags into a cmake list (; separated) separate_arguments(CUSTOM_FLAGS UNIX_COMMAND ${CUSTOM_FLAGS}) # Custom command to build your one file. add_custom_command( OUTPUT out.o COMMAND ${CMAKE_CXX_COMPILER} ARGS ${CUSTOM_FLAGS} -c ${CMAKE_SOURCE_DIR}/out.cpp -o ${CMAKE_BINARY_DIR}/out.o MAIN_DEPENDENCY out.cpp) add_executable(test test.cpp out.o)

Aunque está lejos de ser perfecto, funciona, que es lo que cuenta. Los CUSTOM_FLAGS eran necesarios porque, de lo contrario, todos los espacios en CUSTOM_FLAGS se escaparon (no sé cómo resolverlos rápidamente).