#cmake
#cmake
Вопрос:
Я использую пользовательскую команду для генерации лексеров и синтаксических анализаторов C из грамматик ANTLR4. Прямо сейчас у меня есть следующее:
set(MY_PARSER_INC
${PROJECT_SOURCE_DIR}/Headers/MyParser/MyLexer.h
${PROJECT_SOURCE_DIR}/Headers/MyParser/MyParser.h
${PROJECT_SOURCE_DIR}/Headers/MyParser/MyParserBaseVisitor.h
${PROJECT_SOURCE_DIR}/Headers/MyParser/MyParserVisitor.h
)
set(MY_PARSER_SRC
${PROJECT_SOURCE_DIR}/Sources/MyParser/MyLexer.cpp
${PROJECT_SOURCE_DIR}/Sources/MyParser/MyParser.cpp
)
add_custom_command(
OUTPUT ${MY_PARSER_INC} ${MY_PARSER_SRC}
DEPENDS ${PROJECT_SOURCE_DIR}/Grammars/MyGrammar.g4
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/Headers/MyParser/
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_SOURCE_DIR}/Sources/MyParser/
COMMAND java -cp "${ANTLR_CLASSPATH}" "org.antlr.v4.Tool" -Dlanguage=Cpp -visitor -no-listener -package MY::NESTED::NAMESPACE -encoding iso-8859-1 -o ${PROJECT_SOURCE_DIR}/Sources/MyParser/ ${PROJECT_SOURCE_DIR}/Grammars/MyGrammar.g4
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/Sources/MyParser/*.h ${PROJECT_SOURCE_DIR}/Headers/MyParser/
COMMAND ${CMAKE_COMMAND} -E remove -f ${PROJECT_SOURCE_DIR}/Sources/MyParser/*.h
COMMENT "generating sources for My Parser"
)
и затем я использую выходные файлы в своей add_library
команде для поддержания зависимости.
Это делает именно то, что я ожидаю от него. Он правильно создает лексеры и синтаксические анализаторы. Он также правильно поддерживает зависимость между этими источниками и целевой библиотекой. Только одна проблема: он запускается каждый раз! Даже если файл грамматики не был изменен (я проверил дату файла в грамматике и сгенерировал лексеры / синтаксические анализаторы, чтобы быть уверенным)! Я видел несколько похожих вопросов в Интернете, но до сих пор не могу понять, почему это происходит.
Есть какие-нибудь подсказки ?!
ПРАВКА1:
Добавляю больше информации, поскольку она все еще может быть неясной. После у add_custom_command
меня есть следующее:
include_directories(${PROJECT_SOURCE_DIR}/Headers/MyParser/)
add_library(MyLibrary SHARED
${MY_PARSER_INC} ${MY_PARSER_SRC}
other_files.hpp other_files.cpp)
я предполагаю, что это создает прямую зависимость между сгенерированными исходными файлами и моей целевой библиотекой.
Комментарии:
1. Признаки того, что некоторые ВЫХОДНЫЕ файлы не будут восстановлены пользовательской командой. На самом деле,
*.h
не работает вcmake -E copy
command, см. Документацию . Поскольку вы знаете все файлы, созданные antlr, вы можете просто перечислить их для этой команды.2. @Tsyvarev Я не совсем понимаю первое утверждение. Однако команда копирования работает нормально. Файлы есть, они обновляются правильно, если я обновляю грамматику, и я включаю их в другие файлы, я бы обязательно заметил, если копия не удалась.
3.Вы можете попытаться самостоятельно устранить причину перестройки файлов. Например, если вы используете
make
утилиту для сборки проекта, затем передайте ей-d
option.4. Вы создали пользовательскую цель?
5. Как указывалось,
cmake -E copy
не поддерживает подстановочные знаки иcmake -E remove
устарел. Я предполагаю, что ваш скрипт завершается некорректно и не обновляет файл временных меток, который некоторые генераторы используют при отслеживании пользовательских команд. Вероятно, это зависимость, которая вышла из строя и вызывает повторные запуски, которые вы видите. Но без подробной информации об используемом генераторе и инструментах я не могу сказать наверняка.
Ответ №1:
Вот мое предположение.
Вам нужно создать пользовательскую цель.
https://cmake.org/cmake/help/latest/command/add_custom_target.html ?выделите =custom_target
add_custom_target(custom_target_create_parser_code DEPENDS
${MY_PARSER_INC} ${MY_PARSER_SRC}
)
Это создаст цель, которая зависит от пользовательской команды, которую вы написали.
Теперь cmake есть к чему присоединить вашу команду.
Теперь вам нужно добавить зависимость в вашу статическую библиотеку, о которой вы упомянули. https://cmake.org/cmake/help/latest/command/add_dependencies.html
add_dependency(your_static_library custom_target_create_parser_code)
Теперь cmake не должен каждый раз повторно запускать ваш пользовательский код команды.
РЕДАКТИРОВАТЬ КСТАТИ:
В книге Крейга Скотта на самом деле есть подраздел, посвященный этой теме:
https://crascit.com/professional-cmake/
Глава 18 Пользовательские цели
Глава 18.3 Команды, генерирующие файлы
РЕДАКТИРОВАТЬ #2:
Если все остальное не удается, попробуйте официальный дискурс cmake: https://discourse.cmake.org /
Ваш вопрос правильно сформулирован, и разработчики cmake ищут их вопросы. Итак, вы должны получить ответ.
Комментарии:
1. Но чем это отличается от включения сгенерированных источников и заголовков в строку add_library моей общей библиотеки?
2. Насколько я понимаю, цель заключается в создании фактической цепочки зависимостей, которая будет проверять наличие временных меток. Я думаю, что я прав, но уже поздно, поэтому я могу ошибаться, трудно сказать, не видя всего проекта. Но у меня также есть сгенерированные файлы в нашем проекте, и в основном это то, что мы делаем.
3. Попробовав ваше предложение сейчас, вы вернетесь с результатами
4. К сожалению, ваше предложение ничего не изменило, я все же взгляну на эту ссылку.
5. Вы не обязаны использовать
add_custom_target()
при использованииadd_custom_command()
. Но есть определенные условия, при которых использованиеadd_custom_target()
является предпочтительным. Например, когдаadd_custom_command()
генерируется вывод, который будет использоваться в нескольких целях.