LINUX.ORG.RU

CMake: Получить список определений препроцессора

 ,


0

1

В ходе компиляции проекта CMakeLists.txt запускает мой Python скрипт, который парсит некоторые исходники и извлекает оттуда некоторую мета-информацию (которая затем используется для генерации части других исходников проекта). Проблема в том, что для корректного парсинга исходников нужно знать объявленные директивы препроцессора. Например, в релизном билде CMAKE добавляет определение NDEBUG. Также какие-то определения могут добавлять используемые библиотеки и, наконец, я сам через add_definitions и target_add_definitions.

Хочется получить полный набор определений, которые добавлены именно через CMake, дефолтные определения компилятора не интересны, потому что я выполняю препроцессинг его же силами (с помощью опции -E) и с ними проблем нет.

get_property(GLOBAL_COMPILE_DEFINITIONS GLOBAL PROPERTY COMPILE_DEFINITIONS)
get_property(DIR_COMPILE_DEFINITIONS DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY COMPILE_DEFINITIONS)
get_property(TARGET_COMPILE_DEFINITIONS TARGET MyProgram PROPERTY COMPILE_DEFINITIONS)
message(STATUS "COMPILE_DEFINITIONS ${TARGET_COMPILE_DEFINITIONS} ${DIR_COMPILE_DEFINITIONS} ${GLOBAL_COMPILE_DEFINITIONS}")

Выдаёт мне объявления добавленные с помощью add_definitions и target_add_definitions, но игнорирует встроенные определения CMake такое как NDEBUG в релизной сборке. Можно ли как-то получить NDEBUG или только хардкодить проверку типа билда? Насколько мой способ получения в целом полный, не пропустит ли он как-нибудь хитро добавленное определение какой-нибудь гипотетической библиотекой?

★★★★★

Ответ на: комментарий от XMs

Да, это то что нужно.

Теперь возникает второй вопрос - как это прикрутить к add_custom_command, чтобы в разных конфигурациях передавать разные параметры скрипту.

KivApple ★★★★★
() автор топика
Ответ на: комментарий от KivApple

В разных конфигурациях сборки?

Вот код из моего проекта, может возьмёшь что-то на заметку.

get_property(GEN_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if (GEN_IS_MULTI_CONFIG)
    message(STATUS "Defined build configuration: Multiple")
    if (NOT DEFINED CMAKE_DEFAULT_BUILD_TYPE)
        set(CMAKE_DEFAULT_BUILD_TYPE Release)
    endif()
    message(STATUS "Defined default build type: ${CMAKE_DEFAULT_BUILD_TYPE}")
else()
    message(STATUS "Defined build configuration: Unary")
    if (NOT DEFINED CMAKE_BUILD_TYPE)
        set(CMAKE_BUILD_TYPE Release)
    endif()
    message(STATUS "Defined default build type: ${CMAKE_BUILD_TYPE}")
endif()

Ещё посмотри вот это: Ninja Multi-Config. Приставка «$<CONFIG>» подставляет текущую конфигурацию сборки.

Dr64h ★★
()
Ответ на: комментарий от KivApple

Я пока вижу только что-то вроде (за синтаксическую корректность не ручаюсь)

if (${CMAKE_BUILD_TYPE} STREQUAL "DEBUG")
    do_my_cmd(${CMAKE_CXX_FLAGS_DEBUG})
elseif (${CMAKE_BUILD_TYPE} STREQUAL "RELEASE")
    do_my_cmd(${CMAKE_CXX_FLAGS_RELEASE})
elseif (…)
endif()

XMs ★★★★★
()

Начиная с некоторой версии симейка (3.20 или 3.21) можно пройтись по таргету, доставая из него дефайны с учетом $<CONFIG> и сложить их в сгенерированный файл, который потом прочитать в питон поделке

Stil ★★★★★
()
Ответ на: комментарий от KivApple

С мультиконфигурациями дел не имел, но, полагаю, через те же условные конструкции можно что-то накостылять. Либо через выражения генератора, как тут ещё советуют, хотя я не до конца понимаю, как

XMs ★★★★★
()
Ответ на: комментарий от KivApple

Можно ли использовать $<CONFIG> в имени переменной? Типа ${CMAKE_C_FLAGS_$<CONFIG>}? В каком порядке оно раскрывается?

Неа, подставлять именно к имени переменной нельзя, можно только к строке. Как я понимаю вместо $<CONFIG> подставляется значение только после этапа генерации.

Можно использовать например так:

set(BUILD_CONFIG_DIR ${CMAKE_BINARY_DIR}/$<CONFIG>)
# BUILD_CONFIG_DIR после генерации будет == "/home/username/projects/my_project/build/Debug"

Можно вместо «${CMAKE_C_FLAGS_$<CONFIG>», использовать это:

set(CMAKE_BUILD_TYPE "Debug")
string(TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_UCASE)

message(STATUS "CMAKE_C_FLAGS_<CONFIG> == ${CMAKE_C_FLAGS_${CMAKE_BUILD_TYPE_UCASE}}")

Но надо учитывать, что при этом переменная «CMAKE_BUILD_TYPE» обязательно должна быть определена, иначе будет ошибка.

Dr64h ★★
()
Последнее исправление: Dr64h (всего исправлений: 1)
Ответ на: комментарий от Dr64h

Я придумал вот такую штуку (я передаю аргументы препроцессора своему скрипту через --cpp-arg=XXX):

foreach(BUILD_TYPE ${CMAKE_BUILD_TYPE} ${CMAKE_CONFIGURATION_TYPES})
	string(TOUPPER "${BUILD_TYPE}" BUILD_TYPE)
	set(TMP ${CMAKE_C_FLAGS_${BUILD_TYPE}})
	separate_arguments(TMP)
	list(TRANSFORM TMP PREPEND --cpp-arg=)
	list(APPEND CUR_CONFIG_BUILD_FLAGS $<$<CONFIG:${BUILD_TYPE}>:${TMP}>)
endforeach()

add_custom_command(
		OUTPUT ...
		COMMAND "${Python3_EXECUTABLE}" "..."
		--cpp-path="${CMAKE_C_COMPILER}"
		--cpp-arg=-E
		${CUR_CONFIG_BUILD_FLAGS}
		...
)

Но она не работает, если аргумента больше одного:

ninja: error: build.ninja:188: bad $-escape (literal $ must be written as $$)
KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от Dr64h

Вот такой вариант заработал.

get_property(DIR_DEFS DIRECTORY "${CMAKE_SOURCE_DIR}" PROPERTY COMPILE_DEFINITIONS)
separate_arguments(DIR_DEFS)
get_property(TARGET_DEFS TARGET MyProgram PROPERTY COMPILE_DEFINITIONS)
separate_arguments(TARGET_DEFS)
foreach(FLAG ${DIR_DEFS} ${TARGET_DEFS})
	list(APPEND CUR_CONFIG_BUILD_FLAGS --cpp-arg=-D${FLAG})
endforeach()

foreach(BUILD_TYPE ${CMAKE_BUILD_TYPE} ${CMAKE_CONFIGURATION_TYPES})
	string(TOUPPER "${BUILD_TYPE}" BUILD_TYPE)
	set(TMP ${CMAKE_C_FLAGS_${BUILD_TYPE}})
	separate_arguments(TMP)
	foreach(FLAG ${TMP})
		list(APPEND CUR_CONFIG_BUILD_FLAGS $<$<CONFIG:${BUILD_TYPE}>:--cpp-arg=${FLAG}>)
	endforeach()
endforeach()

add_custom_command(
		OUTPUT ...
		COMMAND "${Python3_EXECUTABLE}" "..."
		--cpp-path="${CMAKE_C_COMPILER}"
		--cpp-arg=-E
		${CUR_CONFIG_BUILD_FLAGS}
		...
)

Только удручает его громздкость. Интересно, можно ли его как-то оптимизировать или это неизбежность с CMake.

KivApple ★★★★★
() автор топика
Последнее исправление: KivApple (всего исправлений: 1)
Ответ на: комментарий от KivApple

Я придумал вот такую штуку (я передаю аргументы препроцессора своему скрипту через --cpp-arg=XXX):

Советую ещё configure_file посмотреть. Он позволяет генерить файлы с подстановкой значений из cmake.

Dr64h ★★
()