Является ли 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 распространяется по связанной библиотеке.
Рекомендации