Является ли Cmake установленной переменной рекурсивно?

Я пытаюсь изменить флаги компилятора для всех каталогов ниже определенного каталога (т.е. рекурсивно для всех текущих подкаталогов каталогов и всех их подкаталогов). Поэтому я нашел здесь два пути:

add_directory(dir1)
# ...
add_directory(dirN)

add_compile_options(flag1 flag2 ...)
# or for CMake versions < 3.0 to do something more like:
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} flag1 flag2 ...")

Справочная страница для add_compile_options очень ясно заявив, что эффект будет "текущий каталог и ниже" (что я и хочу), но для set(CMAKE_CXX_FLAGS ...) Я не так уверен.

Является ли Cmake установленной переменной рекурсивно?

1 ответ

Короткий ответ заключается в том, что каждый подкаталог имеет свою собственную область переменных, инициализированную копией текущих значений переменных во время add_subdirectory() вызов.

Подробный ответ смотрите в разделе Что такое синтаксис CMake для установки и использования переменных?

Свойства каталога и цели по сравнению с (глобальными) переменными

Есть разница между тем, как add_compile_options() а также CMAKE_CXX_FLAGS обрабатываются CMake:

  • Все, что вы указываете add_compile_options() добавляется к COMPILE_OPTIONS свойство каталога. Затем "это свойство используется для инициализации COMPILE_OPTIONS свойство target при создании цели add_library() или же add_executable(),

    А текущее состояние свойств каталога используется для инициализации свойств подкаталога, когда анализатор получает add_subdirectory() вызов.

  • CMAKE_CXX_FLAGS глобальная кэшированная переменная Вы можете расширить / перезаписать его, определив локальную переменную области каталогов (скрывая глобально кэшированную).

    Контекст этих переменных копируется в область подкаталогов на add_subdirectory() (распространение в подкаталогах).

    И CMake смотрит на его значение в конце каждого CMakeLists.txt файл и применяет это ко всем целям в том же CMakeLists.txt (с учетом поздних деклараций см. также " Полная формула и тестовый код" ниже)

  • Так что для CMake версий < 3.0 эквивалентно add_compile_options() было add_definitions(), Функциональность все еще там, но было странно смешивать определения с опциями компиляции. Так add_compile_options() было изобретено.

Полная формула генератора для флагов компилятора

Это в коде CMake (см. cmCommonTargetGenerator::GetFlags(), cmLocalGenerator::AddCompileOptions() а также cmLocalGenerator::AddLanguageFlags()).

Этот пример показывает DEBUG построить библиотеку конфигурации без экспорта, не принимая во внимание флаги на основе возможностей или что-то подобное CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES или же CMAKE_QUOTE_INCLUDE_PATHS:

  CMAKE_CXX_FLAGS       // as set at the end of target's CMakeLists.txt
+ CMAKE_CXX_FLAGS_DEBUG

+ Include Directories   // pefixed with CMAKE_INCLUDE_FLAG_CXX/CMAKE_INCLUDE_SYSTEM_FLAG_CXX

    (CMAKE_INCLUDE_CURRENT_DIR) ? 
        + CMAKE_CURRENT_SOURCE_DIR + CMAKE_CURRENT_BINARY_DIR
    + CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES
    + Target[INCLUDE_DIRECTORIES]
    + DependingTargets[INTERFACE_INCLUDE_DIRECTORIES] 

+ Define Flags         // compiler flags given with add_definitions()
+ Target[COMPILE_FLAGS] // deprecated
    - Filtered by CMAKE_CXX_FLAG_REGEX
+ Target[COMPILE_OPTIONS]
+ DependingTargets[INTERFACE_COMPILE_OPTIONS]

Тестовый код

Для лучшего понимания вот мой код для тестирования опций компилятора и полученных результатов:

Примечание: обычно я бы использовал add_definitions() а также target_compile_definitions() вместо add_compile_options() а также target_compile_options() установить определения компилятора, но продемонстрировать распространение опций компилятора, которые я (неправильно) использовал -D флаги.

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

project(CxxFlagsTest)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DCXX_FLAG")
add_compile_options("-DCOMPILE_OPTION")

add_subdirectory(lib)

file(WRITE main.cpp "int main() { return 0; }")
add_executable(main main.cpp)
target_link_libraries(main lib)

target_compile_options(main PRIVATE "-DMAIN_COMPILE_OPTION")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLATE_CXX_FLAG")

get_target_property(_main_compile_options main COMPILE_OPTIONS)
message(STATUS "main COMPILE_OPTIONS: ${_main_compile_options}")
get_directory_property(_root_compile_options COMPILE_OPTIONS)
message(STATUS "root COMPILE_OPTIONS: ${_root_compile_options}")
message(STATUS "root CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")

Библиотека /CMakeLists.txt

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSUB_CXX_FLAG")
add_compile_options("-DSUB_COMPILE_OPTION")

file(WRITE lib.cpp "")
add_library(lib lib.cpp)

target_compile_options(lib PUBLIC "-DLIB_COMPILE_OPTION")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLATE_SUB_CXX_FLAG")

get_target_property(_lib_compile_options lib COMPILE_OPTIONS)
message(STATUS "lib COMPILE_OPTIONS: ${_lib_compile_options}")
get_directory_property(_sub_compile_options COMPILE_OPTIONS)
message(STATUS "sub COMPILE_OPTIONS: ${_sub_compile_options}")
message(STATUS "sub CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")

Результатом будут следующие сообщения:

-- lib COMPILE_OPTIONS: -DCOMPILE_OPTION;-DSUB_COMPILE_OPTION;-DLIB_COMPILE_OPTION
-- sub COMPILE_OPTIONS: -DCOMPILE_OPTION;-DSUB_COMPILE_OPTION
-- sub CMAKE_CXX_FLAGS:  ... -DCXX_FLAG -DSUB_CXX_FLAG -DLATE_SUB_CXX_FLAG
-- main COMPILE_OPTIONS: -DCOMPILE_OPTION;-DMAIN_COMPILE_OPTION
-- root COMPILE_OPTIONS: -DCOMPILE_OPTION
-- root CMAKE_CXX_FLAGS:  ... -DCXX_FLAG -DLATE_CXX_FLAG

И следующие определения препроцессора устанавливаются:

Lib

CXX_FLAG
SUB_CXX_FLAG
LATE_SUB_CXX_FLAG
COMPILE_OPTION
SUB_COMPILE_OPTION
LIB_COMPILE_OPTION

главный

CXX_FLAG
LATE_CXX_FLAG
COMPILE_OPTION
MAIN_COMPILE_OPTION
LIB_COMPILE_OPTION

Интересные части здесь LATE Флаги CXX и LIB Опция compile распространяется по связанной библиотеке.

Рекомендации

Другие вопросы по тегам