#c #cmake
#c #cmake #c-препроцессор
Вопрос:
Как мне определить переменную препроцессора через CMake?
Эквивалентный код будет #define foo
.
Ответ №1:
Долгое время у CMake была add_definitions
команда для этой цели. Однако недавно команда была заменена более детализированным подходом (отдельные команды для определений компиляции, включают каталоги и параметры компилятора).
Пример с использованием новых add_compile_definitions:
add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION})
add_compile_definitions(WITH_OPENCV2)
Или:
add_compile_definitions(OPENCV_VERSION=${OpenCV_VERSION} WITH_OPENCV2)
Хорошая часть в этом заключается в том, что он обходит потрепанный трюк, для которого используется CMake add_definitions
. CMake — такая потрепанная система, но они, наконец, обретают здравый смысл.
Найдите больше объяснений о том, какие команды использовать для флагов компилятора здесь: https://cmake.org/cmake/help/latest/command/add_definitions.html
Аналогично, вы можете сделать это для каждой цели, как описано в ответе Джима Ханцикера.
Комментарии:
1. Со связанной страницы: «Обратите внимание, что эта команда была заменена альтернативами: используйте add_compile_definitions() для добавления определений препроцессора». Может быть, этот ответ нуждается в редактировании?
2. В cmake 3.10.2
add_compile_definitions
выдаетCMake Error at CMakeLists.txt:6 (add_compile_definitions): Unknown CMake command "add_compile_definitions".
ошибку . Пришлось использоватьadd_compile_options(-D <your-def>)
вместо этого.3. @mannyglover Я так не думаю, но вы можете установить флаги компилятора с помощью -D, что-то вроде
cmake -D CMAKE_CXXFLAGS='-DDEBUG_CHESSBOARD'
(не проверено)4. Это действительно новое… на самом деле это в более современном CMake (> 3.11). Боль в том, что так трудно понять, когда была введена команда.
5. @Sandburg Вы можете открыть ссылку на последнюю документацию:
https://cmake.org/cmake/help/v3.17/command/add_compile_definitions.html#command:add_compile_definitions
и начать изменять номер версии вниз, пока страница не исчезнет. Это будет версия, в которой она еще не существует. На следующем шаге вы можете перейти кWhats new
разделу, чтобы найти новую команду или функцию. Так что это не так сложно.
Ответ №2:
Чтобы сделать это для конкретной цели, вы можете сделать следующее:
target_compile_definitions(my_target PRIVATE FOO=1 BAR=1)
Вы должны сделать это, если у вас более одной цели, которую вы создаете, и вы не хотите, чтобы все они использовали одни и те же флаги. Также смотрите официальную документацию по target_compile_definitions .
Комментарии:
1. @JimHunziker Чем
target_compile_definitions(my_target PRIVATE FOO=1)
отличается отset_source_files_properties(foo.cpp PROPERTIES COMPILE_DEFINITIONS -DFOO=1)
?2. @JohnStrood Разница заключается в уровне области видимости.
target_compile_definitions
задает значение для ВСЕГО исполняемого файла / библиотеки, где как ‘set_source_files_properties` задает значение только для указанного файла. Последняя команда позволяет компилировать файлы с использованием другого языка; т.е.:set_source_files_properties(compile_me_as_objc.c PROPERTIES -x objective-c
. Обратите внимание, что-x objective-c
здесь указан флаг, специфичный для GCC / Clang .
Ответ №3:
Другие решения, предложенные на этой странице, полезны для некоторых версий Cmake>
3.3.2
. Вот решение для версии, которую я использую (т.Е.3.3.2
). Проверьте версию вашего Cmake с помощью$ cmake --version
и выберите решение, которое соответствует вашим потребностям. Документацию cmake можно найти на официальной странице.
С CMake версии 3.3.2, чтобы создать
#define foo
Мне нужно было использовать:
add_definitions(-Dfoo) # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
add_executable( ....)
target_link_libraries(....)
и для того, чтобы иметь определение макроса препроцессора, подобное этому другому:
#define foo=5
строка настолько изменена:
add_definitions(-Dfoo=5) # <--------HERE THE NEW CMAKE LINE inside CMakeLists.txt
add_executable( ....)
target_link_libraries(....)
ПОЖАЛУЙСТА, ОБРАТИТЕ ВНИМАНИЕ (как предлагает @squareskittles в одном из комментариев): «если вы используете CMake 3.3.2
, вы должны use add_definitions()
или target_compile_definitions()
. Более современная команда, add_compile_definitions()
, не была добавлена до CMake 3.12
.»
Комментарии:
1. Согласно документации , это решение на самом деле является более старым, более устаревшим подходом. Другие ответы предлагают более современные решения.
2. Когда я писал ответ, я попробовал другое решение, но ни одно из них не работало.
3. @squareskittles, есть идеи, почему решение другого ответа не сработало правильно? CMake выдает ошибки, если я их попробую
4. Если вы используете CMake 3.3.2, как вы указали в своем ответе, вы должны использовать
add_definitions()
илиtarget_compile_definitions()
. Более современная команда,add_compile_definitions()
, не была добавлена до CMake 3.12. @Leos3135. @squareskittles, правильно! ответ обновлен вашей информацией!!
Ответ №4:
1.) target_compile_definitions
Если вы используете CMake 3.X, первым выбором для добавления макроса препроцессора должно быть target_compile_definitions .
Причина, по которой вы должны предпочесть этот подход любому другому подходу, заключается в том, что он target
основан на детализации. Т.Е. макрос будет добавлен только в ваш exe / library.
Вот общий пример:
if (WIN32)
target_compile_definitions(my_lib PRIVATE
# Prevents Windows.h from adding unnecessary includes
WIN32_LEAN_AND_MEAN
# Prevents Windows.h from defining min/max as macros
NOMINMAX
)
endif()
2.) add_compile_definitions
Новое в версии 3.12.
Найдите больше объяснений о том, какие команды использовать для флагов компилятора здесь: https://cmake.org/cmake/help/latest/command/add_definitions.html
add_compile_definitions применяет макросы к любым целям, которые определены после вызова.
Здесь та же логика, что и выше, с add_compile_definitions .
add_compile_definitions(WIN32_LEAN_AND_MEAN NOMINMAX)
add_library(my_lib)
Если вы используете этот подход, будьте осторожны, если вы являетесь проектом верхнего уровня.
В противном случае, если пользователи используют вашу библиотеку с помощью add_subdirectory, у них могут возникнуть проблемы.
3.) Другие менее рекомендуемые способы
Эти подходы действительно больше не рекомендуются. Из-за того, что он не является модульным, плохо масштабируется, Не поддерживает выражения генератора и т. Д.
Почему target_compile_definitions лучше / предпочтительнее?
- Читателям вашего кода CMake гораздо понятнее, как это работает.
- При необходимости позволяет использовать PRIVATE / PUBLIC / INTERFACE. Что может облегчить жизнь пользователям вашей библиотеки.
- Он намного более модульный.
Применение флагов препроцессора (или любого флага компилятора) глобально может создать скрытые зависимости в вашей сборке.
По сути, думайте о add_compile_definitions как о глобальных в C / C . Иногда они вам нужны, но будьте осторожны.
Ответ №5:
я хотел бы рекомендовать использовать target_***
операции вместо add_***
операций, когда ваше решение включает в себя много проектов.
Ответ №6:
вот пример, в котором вы можете передавать значения из CMAKE в код C . Скажем, вы хотите передать:
- флаг, здесь: BOOST («true» или «false»)
- строка версии программного обеспечения (например: «1.0.0»)
Я рекомендую передавать их в виде строк. Итак, когда вы создаете программное обеспечение с помощью CMAKE, вы можете передавать параметры, например, если оно было создано с использованием библиотеки boost, версию программного обеспечения, извлеченную из переменной CMAKE (чтобы вы изменили это число только в одном месте), см. Ниже.
В CMakeLists.txt:
add_compile_definitions(BOOST=»${BOOST}» Software_VERSION=»$ {PROJECT_VERSION}» )
В вашем коде .cpp:
std::cout << «Версия программного обеспечения: » << Software_VERSION << » BOOST: » << BOOST << «n»;
Надеюсь, это поможет. С уважением.