Короткий ответ
Невозможно присвоить окончательное значение командной строки компилятора переменной в сценарии CMake, работает во всех случаях использования.
Длинный ответ
К сожалению, даже решение, принятое в качестве ответа, по-прежнему не получает все флаги компилятора. Как отмечается в комментариях, есть Требования к переходному использованию. Это современный и правильный способ записи файлов CMake, который становится все более популярным. Также у вас могут быть некоторые параметры компиляции, определенные с помощью выражений генератора (они выглядят как ссылки на переменные, но не расширяются при необходимости).
Рассмотрим следующий пример:
add_executable(myexe ...);
target_compile_definitions(myexe PRIVATE "PLATFORM_$<PLATFORM_ID>");
add_library(mylib ...);
target_compile_definitions(mylib INTERFACE USING_MY_LIB);
target_link_libraries(myexe PUBLIC mylib);
Если вы попытаетесь вызвать предложенный макрос GET_COMPILER_FLAGS с myexe
target, вы получите результат -DPLATFORM_$<PLATFORM_ID>
вместо ожидаемого -DPLATFORM_Linux -DUSING_MY_LIB
.
Это связано с тем, что между вызовом CMake и созданием системы сборки есть два этапа:
- Обработка. На этом этапе CMake считывает и выполняет команды из сценария (-ов) cmake, в частности, значения переменных, которые оцениваются и назначаются. На данный момент CMake просто собирает всю необходимую информацию и готовится создать систему сборки (файлы сборки).
- Генерация. CMake использует значения специальных переменных и properties, оставаясь в конце обработанных сценариев для окончательного решения и сформировать сгенерированный вывод. Здесь он создает финальную командную строку для компилятора в соответствии со своим внутренним алгоритмом, недоступным для сценариев.
Целевые свойства, которые могут быть получены на этапе обработки с помощью get_target_property(...)
или get_property(... TARGET ...)
, не являются полными (даже при вызове в конце сценария). На этапе генерации CMake проходит через каждое целевое дерево зависимостей (рекурсивно) и добавляет значения свойств в соответствии с требованиями транзитивного использования (распространяются значения с тегами PUBLIC
и INTERFACE
).
Хотя есть обходные пути, в зависимости от того, какого конечного результата вы стремитесь достичь. Это можно сделать, применив генератор выражений, позволяющий использовать конечные значения свойств любой цели (определенные на этапе обработки) ... но позже!
Возможны две общие возможности:
- Сгенерируйте любой выходной файл на основе шаблона, содержимое которого содержит ссылки на переменные и / или выражения генератора и определено либо как значение строковой переменной, либо как входной файл. Он не является гибким из-за очень ограниченной поддержки условной логики (то есть вы не можете использовать сложные конкатенации, доступные только с вложенными
foreach()
циклами), но имеет преимущества, заключающиеся в том, что не требуются дополнительные действия и контент, описанный независимым от платформы способом. Используйте вариант команды файл (GENERATE ...). Обратите внимание, что он ведет себя иначе, чем вариант file (WRITE ...)
.
- Добавьте настраиваемую цель (и / или настраиваемую команду), которая реализует дальнейшее использование расширенного значения. Он зависит от платформы и требует, чтобы пользователь дополнительно вызвал
make
(либо с какой-то специальной целью, либо включил в all
цель), но имеет то преимущество, что он достаточно гибкий, потому что вы можете реализовать сценарий оболочки (но без исполняемого бита).
Пример, демонстрирующий решение с объединением этих опций:
set(target_name "myexe")
file(GENERATE OUTPUT script.sh CONTENT "#!/bin/sh\n echo \"${target_name} compile definitions: $<TARGET_PROPERTY:${target_name},COMPILE_DEFINITIONS>\"")
add_custom_target(mycustomtarget
COMMAND echo "\"Platform: $<PLATFORM_ID>\""
COMMAND /bin/sh -s < script.sh
)
После вызова CMake каталог сборки будет содержать файл script.sh
, а вызов make mycustomtarget
выведет на консоль:
Platform: Linux
myexe compile definitions: PLATFORM_Linux USING_MY_LIB
person
Artem Pisarenko
schedule
05.11.2019