Похоже, что содержимое glue_wrapper.cpp
не зависит от значений времени сборки, они основаны исключительно на информации, доступной в момент времени CMake (содержимое переменной my_header_files
). Таким образом, вы можете создать файл в CMake время с помощью простой команды file()
:
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp) # erase file if it exists
foreach(header IN LISTS my_header_files ITEMS glue.cpp)
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp "#include \"${header}\"\n")
endforeach()
пользовательской команды для создания.библиотека JS должна работать нормально:
add_custom_command(
OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js
COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js
DEPENDS ${ALL_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp
COMMENT "Building ${PROJECT}.js"
VERBATIM
)
Как и с любой пользовательской команды CMake, он будет включен только в сборке, если что-то зависит от его выхода (я подозреваю, что именно поэтому ваш подход терпел неудачу). Поэтому вы должны добавить пользовательскую цель для управления командой:
add_custom_target(
JsLibrary ALL
DEPENDS ${PROJECT_JS_DIR}/${PROJECT}.js
COMMENT "Building JsLibrary"
)
Это должно быть все, что необходимо.
В качестве примечания стороны обратите внимание, что add_custom_command
имеет аргумент WORKING_DIRECTORY
, который следует использовать вместо COMMAND cd
.
Отношения между CMake пользовательских команд и пользовательских целей может занять некоторое время, чтобы полностью обращал внимания, поэтому я попытаюсь объяснить, что происходит в коде выше.
Пользовательские команды
Команда add_custom_command(OUTPUT x ...)
создает правило сборки, которая производит вывод. В принципе, это говорит о CMake:
Если кому-то понадобится файл x
, вот как вы его создаете.
Эта команда ничего не добавляет к сгенерированной сборке . Он предоставляет информацию CMake только о том, как будет создан файл.
Отдельные компоненты вызова являются:
add_custom_command(
OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js
Файл или файлы, созданные с помощью этой пользовательской команды. В нем говорится: «пользовательская команда создает эти файлы».
COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js
Параметр COMMAND
вводит в командной строке команды для выполнения. В нем говорится: «это то, что вы должны сделать, чтобы создать файлы, перечисленные в OUTPUT
».
DEPENDS ${ALL_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/interface/glue_wrapper.cpp ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp
DEPENDS
разделе представлены зависимости (предпосылки) команды. Каждый элемент, который следует за ним, является одним файлом, который является зависимым от команды. В нем говорится: «Если какой-либо из этих файлов отсутствует, или если из этих файлов новее, чем любых выходных файлов, эта команда должна быть повторно запущена».
Обратите внимание, в частности, на ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp
, я вернусь к нему позже.
COMMENT "Building ${PROJECT}.js"
Это чисто документация — она будет напечатана, когда команда запуска запускается на выполнение (= встроенный).
VERBATIM
)
Это говорит CMake правильно избежать каких-либо специальных символов в разделе COMMAND
для оболочки, которая будет запустившего команду. В принципе, всегда ставьте это в пользовательские команды, если вы точно не знаете, что у вас есть причина не делать этого.
Пользовательские целевой
Как я уже упоминал выше, CMake только добавляет пользовательские команды к buildsystem если что-то просит их выход. Обычная цель (то есть библиотека или исполняемый файл) может сделать это путем перечисления выходного файла среди его исходных файлов. Это типично в случаях, когда пользовательская команда генерирует исходный файл C++, например, из определения IDL.
Пользовательская команда также может отображать вывод другой пользовательской команды в разделе DEPENDS
, в котором создается требуемая зависимость. Однако оба будут снова включены только в том случае, если где-то запрашивается вывод команды «master».
Если сгенерированный файл на самом деле является конечным продуктом, а не только исходным файлом для нормальной цели, явная зависимость от него должна быть указана где-то, чтобы убедиться, что она сгенерирована. Вот где входит пользовательская цель. Это цель (точно так же, как исполняемый файл или библиотека), поэтому она всегда будет присутствовать в сборке. При использовании генератора на основе make-файла пользовательская цель является просто дополнительным правилом. Давайте проанализируем один я ставлю в ответ выше:
add_custom_target(
JsLibrary
JsLibrary
это только символическое имя цели. Это может быть все, что вы хотите. Это имя, которое вы наберете в командной строке, чтобы создать файл .js
: > make JsLibrary
.
ALL
По умолчанию, пользовательские цели являются не часть all
цели, вызываемой make all
; у вас есть make
их явно. Добавление аргумента ALL
делает пользовательскую целевую часть make all
, которую я предположил, что вы захотите здесь.
DEPENDS ${PROJECT_JS_DIR}/${PROJECT}.js
Это ключевая линия и причина, по которой мы создали пользовательскую цель в первую очередь. Это говорит CMake, что пользовательская цель зависит от сгенерированного файла. Теперь CMake видит, что файл требуется чем-то, что является частью сборной системы (т. Е. Пользовательской командой JsLibrary
) и смотрит, знает ли он, как создать такой файл. Он находит пользовательскую команду и гарантирует, что правильные правила будут добавлены в сгенерированную сборку.
COMMENT "Building JsLibrary"
)
Это чистая документация снова — он будет напечатан каждый раз, когда цель получает сделал (даже если все его зависимости находятся в актуальном состоянии и, таким образом, не происходит дальнейшая обработка).
Подытоживая
JsLibrary
будут включены в buildsystem, потому что это обычай цель и пользовательские цели всегда включены. Он будет частью make all
, так как при его создании мы определили ALL
.
JsLibrary
зависит от ${PROJECT_JS_DIR}/${PROJECT}.js
, поэтому правило, созданное пользовательской командой, будет включено в сборку и будет проверяться каждый раз, когда будет построено JsLibrary
. Если он устарел, он будет выполнен.
${PROJECT_JS_DIR}/${PROJECT}.js
в свою очередь, зависит от ${CMAKE_CURRENT_BINARY_DIR}/interface/glue.cpp
, потому что был указан в DEPENDS
разделе пользовательской команды, создающей .js
. Таким образом, правило, описанное в пользовательской команде, создающей glue.cpp
, также будет включено в систему builds, и все будет работать так, как ожидалось.
какая часть 3. работает? –
@ м.с .: Увы, у меня не было никакого успеха с частями 3 и 4. После 7 часов боев я отказался. Я могу построить, если я следую инструкциям, описанным вручную, но я стараюсь использовать CMake вместо полностью ручного процесса. –