Условный препроцессор CMake определяет код
Я переношу проект makefile в CMake. Человек, который написал makefile в первый раз, сделал модуль для записи определенных значений в include файле.
Там находится главный файл config.h, который включает config_in.h. Файл config.h содержит примерно следующее:
#ifndef USE_FEATURE_A
#define USE_FEATURE_A 0
#endif
#ifndef USE_FEATURE_B
#define USE_FEATURE_B 0
#endif
В make файле есть поддельная цель вроде with_feature_a
, которая записывает в config_in.h
#define USE_FEATURE_A 1
Таким образом, кто-то может напечатать
make with_feature_a
make
чтобы получить правильную сборку.
Я хочу реплицировать что-то вроде этого, используя эту базу кода, но используя CMake. Я попробовал пару подходов, предложенных в сети, но я не получил его работать.
set_target_properties(with_feature_a PROPERTIES COMPILE_DEFINITIONS
"WITH_FEATURE_A=1"
)
Это не работает, потому что если я запустил
make with_feature_a
Я не вижу with_feature_a
в командной строке препроцессора.
Вторая попытка, которую я сделал, - записать файл напрямую с содержимым, установленным на все, что захочу, но я не понял, как подключить команду file()
к моей цели.
Я поместил это в свой CMakeLists.txt
file(WRITE
local/config_in.h
"#define WITH_FEATURE_A 1"
)
но это не выполняется каждый раз, и я не знаю, как установить его в одну цель.
Любая помощь приветствуется. Спасибо, что прочитали все это. Извините за длинную историю:)
ОБНОВЛЕНИЕ
Решение, предоставленное здесь, является большим улучшением на пути к решению. Проблема в том, что это не позволяет рекурсивные определения. Я показываю пример:
в CMakeLists.txt Я разместил:
if (WITH_FEATURE_A)
MESSAGE(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
add_definitions(-DWITH_FEABURE_B=1)
endif()
if (WITH_FEABURE_B)
MESSAGE(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_D=1)
endif()
if (WITH_FEABURE_C)
MESSAGE(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_D=1)
endif()
if (WITH_FEABURE_D)
MESSAGE(STATUS "WITH_FEATURE_D")
endif()
в этом случае, если я исполняю cmake с -DWITH_FEATURE_A = 1, мне бы хотелось увидеть на выходе:
WITH_FEATURE_A
WITH_FEATURE_B
WITH_FEATURE_D
на самом деле этот код печатает только
WITH_FEATURE_A
Ответы
Ответ 1
Вы можете упростить ситуацию, избегая создания фиктивных целей и удаления файла конфигурации. Вместо этого, если вы передадите требования через командную строку при вызове CMake (или через графический интерфейс CMake), вы можете запустить make только один раз.
Например, вы можете добавить следующее к вашему CMakeLists.txt:
option(WITH_FEATURE_A "Option description" ON)
option(WITH_FEATURE_B "Option description" OFF)
if(WITH_FEATURE_A)
add_definitions(-DUSE_FEATURE_A)
endif()
if(WITH_FEATURE_B)
add_definitions(-DUSE_FEATURE_B)
endif()
По умолчанию, если вы просто запустите CMake, он установит переменную CMake WITH_FEATURE_A
в ON
, которая, следовательно, добавит USE_FEATURE_A
в качестве определения препроцессора в сборку. USE_FEATURE_B
undefined в коде.
Это будет эквивалентно выполнению #define USE_FEATURE_A
в вашем коде.
Если вам действительно нужен эквивалент
#define USE_FEATURE_A 1
#define USE_FEATURE_B 0
то в вашем CMakeLists.txt вы можете сделать:
option(WITH_FEATURE_A "Option description" ON)
option(WITH_FEATURE_B "Option description" OFF)
if(WITH_FEATURE_A)
add_definitions(-DUSE_FEATURE_A=1)
else()
add_definitions(-DUSE_FEATURE_A=0)
endif()
if(WITH_FEATURE_B)
add_definitions(-DUSE_FEATURE_B=1)
else()
add_definitions(-DUSE_FEATURE_B=0)
endif()
Чтобы изменить эти значения по умолчанию из командной строки, просто выполните (например.):
cmake . -DWITH_FEATURE_A=OFF -DWITH_FEATURE_B=ON
make
Как только переменная была установлена через командную строку таким образом, она кэшируется и останется неизменной до тех пор, пока она не будет перезаписана другим значением в командной строке, или вы удалите файл CMakeCache.txt в своем корне.
Ответ на обновление:
Как отметил @Peter, вы, кажется, смешиваете переменные CMake (теги WITH_FEATURE...
) и определения препроцессора (теги USE_FEATURE...
). Вы можете, как предложили сначала разрешить все зависимости между параметрами, затем установить результирующие определения препроцессора или в этом случае, когда поток достаточно прост, просто выполните все за один раз:
if(WITH_FEATURE_A)
message(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
set(WITH_FEATURE_B ON)
endif()
if(WITH_FEATURE_B)
message(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_B=1)
set(WITH_FEATURE_D ON)
endif()
if(WITH_FEATURE_C)
message(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_C=1)
set(WITH_FEATURE_D ON)
endif()
if(WITH_FEATURE_D)
message(STATUS "WITH_FEATURE_D")
add_definitions(-DUSE_FEATURE_D=1)
endif()
Ответ 2
Похоже, вы хотите ввести отношения между вашими вариантами. Это будет проще, если вы отделите эти шаги. Сначала разрешите отношения, затем задайте значения C для результатов. Помните, что WITH_FEATURE_A - это переменная cmake, а USE_FEATURE_A - препроцессор C, заданный с помощью ADD_DEFINITIONS:
# Specify the inter-feature dependencies
if (WITH_FEATURE_A)
# A requires B because <somereason>
set(WITH_FEATURE_B ON)
endif()
if (WITH_FEATURE_B)
set(WITH_FEATURE_D ON)
endif()
if (WITH_FEATURE_C)
set(WITH_FEATURE_D ON)
endif()
# Now generate the C defines for passing the options to the compiler
if (WITH_FEATURE_A)
MESSAGE(STATUS "WITH_FEATURE_A")
add_definitions(-DUSE_FEATURE_A=1)
endif()
if (WITH_FEATURE_B)
MESSAGE(STATUS "WITH_FEATURE_B")
add_definitions(-DUSE_FEATURE_B=1)
endif()
if (WITH_FEATURE_C)
MESSAGE(STATUS "WITH_FEATURE_C")
add_definitions(-DUSE_FEATURE_C=1)
endif()
if (WITH_FEATURE_D)
MESSAGE(STATUS "WITH_FEATURE_D")
add_definitions(-DUSE_FEATURE_D=1)
endif()
Ответ 3
Я наткнулся на этот вопрос, и я решил, что поделился другим вариантом: TARGET_COMPILE_DEFINITIONS
. У вас может быть две цели в вашем файле CMakeLists.txt, по одному для каждой конфигурации и есть что-то вроде этого
ADD_EXECUTABLE (versionA, ...)
TARGET_COMPILE_DEFINITIONS (versionA, PUBLIC -DWITH_FEATURE_A=1 -DWITH_FEATURE_B=0)
ADD_EXECUTABLE (versionB, ...)
TARGET_COMPILE_DEFINITIONS (versionB, PUBLIC -DWITH_FEATURE_A=0 -DWITH_FEATURE_B=1)
Это означает, что cmake добавляет определения препроцессоров макросов WITH_FEATURE_A
и WITH_FEATURE_B
(с правильным значением), точно так же, как если бы вы определили их в своих * pp файлах. Затем вы можете сказать, какую версию компилировать:
make versionA
make versionB