2015-05-07 2 views
3

Я пытаюсь использовать CMake для создания пользовательского проекта, который включает использование emscripten для обеспечения привязки javascript для моей библиотеки C++.Проблемы с сборкой CMake

Это то, что я хочу, чтобы мой файл CMakeLists.txt для достижения

  1. Укажите расположение источника для моих файлов (DONE)

  2. Установите соответствующие компилятор для использования, а также флаги компилятора и т. д. (DONE)

  3. Используйте специальную сборку для генерации новых файлов cpp (подробные шаги ниже)

    • использовать пользовательский инструмент (питон скрипт) для создания interface/glue.cpp
    • Создать новый пустой файл interface/glue_wrapper.cpp
    • Для каждого файла заголовка f в ${my_header_files} добавить #include "f" в файл interface/glue_wrapper.cpp
    • Последняя запись в interface/glue_wrapper.cpp должно быть #include "glue.cpp"
  4. Использование пользовательской сборки для генерации m У файла JavaScript с помощью следующей логики:

    • создать переменный $ {ALL_SOURCES}, содержащий все источники, перечисленные выше в пункте 1 и interface/glue_wrapper.cpp на шаге 3 выше
    • компиляции с помощью COMMAND, которое вычисляет: ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_FLAGS} ${ALL_SOURCES} interface/glue_wrapper.cpp --post-js glue.js -o output.js

Я провел последние 7 часов на шагах 3 и 4 - без успеха.

Это то, что я до сих пор (в отношении шагов 3 и 4 выше)

# Build Interface 
ADD_CUSTOM_COMMAND(
       OUTPUT interface/glue.cpp 
       COMMAND cd interface 
       COMMAND python ${PLATFORM_PREFIX}/tools/webidl_binder.py ${myclasses_INTERFACE} glue 
       # Need to loop through list and generate include statements ... 
       #COMMAND echo "#include <glue.cpp>" > glue_wrapper.cpp 
       ) 

# Build JS library 
ADD_CUSTOM_COMMAND(
       OUTPUT ${PROJECT_JS_DIR}/${PROJECT}.js 
       COMMAND ${CMAKE_CXX_COMPILER} # Nothing seems to work anyway .... giving up finally :(
       ) 

Я использую CMake 3.2.1, и здание на Ubuntu 14.0.4. Я пытаюсь создать Unix MakeFiles.

Мой вопрос заключается в следующем:

Как изменить фрагмент кода выше, для того, чтобы реализовать требуемую функциональность, указанную в пунктах 3 и 4?

+0

какая часть 3. работает? –

+0

@ м.с .: Увы, у меня не было никакого успеха с частями 3 и 4. После 7 часов боев я отказался. Я могу построить, если я следую инструкциям, описанным вручную, но я стараюсь использовать CMake вместо полностью ручного процесса. –

ответ

3

Похоже, что содержимое 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, и все будет работать так, как ожидалось.

+0

Спасибо. Но не могли бы вы объяснить, почему glue.cpp находится в инструкции for foreach (заголовок IN LISTS my_header_files ITEMS glue.cpp) 'это ошибка? –

+0

@HomunculusReticulli Нет, это не ошибка. Вы упомянули, что вы хотите, чтобы он был последним '# include' в обертке, не так ли? – Angew

+0

да, извините. Я просто это понял! (возможно, как вы отвечали). 7 часов, когда вы смотрели на аме строчки кода, есть эффект ошеломления мозга :)! –

Смежные вопросы