Назад в будущее с WebAssembly +12


Привет, Хабр! Представляю вашему вниманию перевод статьи «Back To The Future With WebAssembly» автора Attila Vago.

Данный пост является переводом статьи, в которой рассказывается о свойствах WebAssemly и Emscripten. Оригинал статьи на английском языке.


Автор статьи Аттила Ваго — senior разработчик ПО в HMH. Пишет код, блоги и штуки в интернете. Полиглот языков программирования, прагматичный деятель, со страстью к JavaScript и легкому доступу. Легко вдохновляемый и вдохновляющий человек с сильным пристрастием к вещам для ботаников, отличной еде, крафтовому пиву и Lego. Пользуется Mac. Делает зарядку в 6 утра.

В 2011 году я написал свою первую независимую строку кода не на HTML (с ним я работал в 2007 году), и она была написана на том самом старом добром С, который преподавал профессор Дэвид Дж. Малан из Гарвардского университета. Он навсегда останется моим вдохновителем не только на изучение программирования, но и на программное мышление. Также запомнилось то, что приготовить бутерброд с арахисовым маслом просто для меня, однако это невероятно сложная задача для компьютера и одинаково трудная для человека, притворяющегося компьютером.



Если вы посмотрели видео, хотя бы первые 18 минут (я знаю, что это долго, но программирование требует времени), то Вы поймете, почему по сей день C близок моему сердцу. К моему разочарованию, я так и не обучился ему, потому что, давайте посмотрим правде в глаза, для веб-разработчика C – это наименьший из приоритетов. У меня никогда не было реальной причины погружаться глубоко в этот язык, несмотря на покупку бесчисленных курсов Udemy и книг по C, я никогда не прикасался к ним (держите свои осуждающие взгляды при себе, Вы делали также) или лгать себе, что если я куплю смарт часы Pebble, которые работают на C, то обязательно напишу для них код. Да, точно! Ни одна из этих причин не была достаточно веской.


Что такое WebAssembly и в чем он обгоняет JS?


WebAssembly (сокращенно Wasm) – это бинарный формат инструкций для стековой виртуальной машины.

«Wasm разработан как переносимая платформа для компиляции языков высокого уровня, таких как C/C++/Rust, что позволяет развертывать в интернете клиентские и серверные приложения»
– любезно объясняет webassembly.org


Иными словами, вышеизложенное означает, что Вы можете писать модули, которые работают в интернете, в браузере/сервере, но написаны на таких языках, как C, скомпилированы в двоичный файл и поэтому невероятно быстры, поскольку они работают непосредственно на аппаратном обеспечении машины. В сравнении с ними, скриптовые языки, такие как JavaScript, имеют несколько уровней абстракции между кодом и оборудованием, что, среди прочего, делает их медленными. Конечно, это не всегда имеет значение, и каждый из них имеет свое место в программе или даже веб-экосистеме.


Исходя из этого, Wasm по строению (изначально) поддерживает только целые числа и числа с плавающей точкой, что дает большую вычислительную мощность и, следовательно, часто используется для реализаций типа canvas. Важно понимать, что WebAssembly не представляет угрозы для JavaScript — во всяком случае, пока — и, как вы увидите далее в этой статье, C и JavaScript могут на самом деле жить очень счастливо в одном проекте и могут запускать код друг друга. Да, что-то вроде того.



Emscripten «склеивает» C и JS


А теперь держитесь! Я знаю, что говорю. Нельзя произносить такие вещи, как ”запуск C в JS и наоборот", и ожидать, что мир не отреагирует. Как бы странно это ни звучало, я не обманываю. Оказывается, Emscripten — это цепочка инструментов для компиляции в asm.js и WebAssembly, спроектированные с использованием LLVM (Боже мой, половину этих вещей я узнал, пока набирал текст статьи), что позволяет запускать C и C++ в интернете на почти родной скорости без плагинов.


Хорошо, вот то, что необходимо из этого выделить для себя. Emscripten поможет Вам скомпилировать код, написанный на C в WebAssembly, предоставив дополнительные инструменты для облегчения нагрузки на разработчика, когда дело доходит до общения между двумя языками, и поможет запустить Wasm в Вашем веб-проекте. Базовая команда компиляции Emscripten выглядит следующим образом:


emcc lib/strings.c -s WASM=1 -o public/strings.js

В то время как не базовая команда запускается так:

emcc lib/imports.c -s WASM=1 -s EXPORTED_FUNCTIONS="['_getNum', '_main', '_getDoubleNum', '_greet']" -o public/imports.js

Настройка Emscripten не самая простая вещь, но и не запуск ракеты. Единственное, что усложняет настройку – это то, что она имеет множество зависимостей, таких как Python, Node, xCode, Git и cMake. Все инструкции можно найти на странице установки и легко следовать им.
Поэтому Emscripten:

  • является отличным инструментом для переноса, позволяющий компилировать существующие проекты, написанные на C или C++ и запускать их во всех современных браузерах. Кыш отсюда, Internet Explorer!
  • отлично подходит для API, поскольку конвертирует OpenGL в WebGL и позволяет использовать знакомые API, такие как SDL или напрямую HTML5. О да!
  • И это чертовски быстро: благодаря LLVM, Emscripten, asm.js и WebAssembly, код работает на почти собственной скорости. Беги, кролик, беги!


Примечание: Вам не нужен Emscripten для генерации Wasm, поскольку во все новые браузеры встроен API для поддержки Wasm в том же окне, что выполняет Emscripten в качестве верхнего слоя, что делает жизнь разработчика намного легче. Например, Emscripten будет подстраивать объем памяти под Вас, что может быть утомительным через С.


Примеры… примеры повсюду!


Вы знаете, как говорится «строка кода стоит тысячи слов», – ОК, это прерогатива рассказчика и все такое, поэтому без лишних слов давайте взглянем на какой-нибудь реальный код. Комментарий не по теме: в тот день я не мог преодолеть синтаксис C. Он не компилировался половину времени, потому что мой код был бы шатким. И через восемь лет я такой: «Да это же похоже на JavaScript”.


Ребята, если кто-то начнет видеть код C в моем React, просто верните меня к реальности, хорошо?


Еще немного не по теме, вот вам действующий код на C:


image

И, соответственно, на JavaScript:


image

ОК, что именно происходит в этих файлах? На самом деле довольно много, так что я перечислю.

  1. Важно понимать, что main (), если не указано иное, всегда запускается первым и также компилируется по умолчанию. Если вы хотите скомпилировать другую функцию, вам нужно будет специально установить ее в флаге массива EXPORTED_FUNCTIONS, как показано в предыдущем разделе.
  2. Вы пишете свой код на C, как обычно, импортируя его обычные библиотеки, но поверх этого Вы получаете синтаксический сахар Emscripten, а также больше методов/функций, чем с каким-либо другим инструментом.
  3. Файл imports.js (имя произвольное, но всегда совпадающее с файлом на С), на который ссылается HTML, – это не что иное, как “клей” Emscripten, который автоматически генерируется при компиляции. Не нужно беспокоиться об этом, просто убедитесь, что на него действительно ссылаются.
  4. Printf – это просто заурядный оператор C, регистрирующий строку на консоли. Ничего особенного, двигаемся дальше.
  5. Строки 14 и 17 представляют собой анти-шаблон, но хороший пример запуска JS в вашем коде на C. Единственное реальное различие между emscripten_run_script и emscripten_async_run_script заключается в том, что последний позволяет запускать JS в C асинхронно. В основном при помощи setTimeout (). Причина, по которой я сказал, что это анти-шаблон в том, что так оно и есть. Вся идея WebAssembly состоит в том, чтобы запустить C в JS, а не JS в C, и, следовательно,…
  6. Строки 20 и 24 и связанные с ними функции JS в файле index.html представляют правильный шаблон, а именно объявление вашего JS в вашем JS и возврат чего-либо для С.
  7. EM_JS, который затем запускает jsFunction, – это просто более простой способ –для достижения аналогичной цели, как в пунктах 4 и 5.

Предсказуемый результат вышесказанного таков:


image

Дамы вперед!


Как и во всяком коде, в WebAssembly также есть порядок выполнения. Не возимся с очередью! Порядок в этом случае является стандартным для С порядком. Все запускается в Main() и всякий раз, когда main() готов, готов и Wasm. Однако что произойдет, если вам нужна статическая функция для вызова во время выполнения? Ну, просто немного синтаксического сахара Emscripten, и все идет как по маслу:


image

Собираем мух с торта


Это хорошо написанный код, особенно простые штуки, проиллюстрированные в предыдущих разделах, но мы все знаем, что реальный мир намного больше, чем “Hello World”, и половина времени каждого разработчика тратится на то, чтобы выяснить, почему код не делает то, что должен. Баги просто неизбежны и в каком-то смысле являются частью жизни.


При запуске C в JS или любого Wasm, если на то пошло, все может стать еще более удручающим. К счастью, Emscripten снова приходит на помощь, предоставляя два очень полезных метода отладки:


// browser debugger gets triggered
emscripten_debugger();

// browser console warning with stack-trace
emscripten_log(EM_LOG_WARN, “‘param’ your message”);

На помощь спешит Быстрый Гонсалес


Верьте или нет, создатели Emscripten продумали все. Одна большая фича — и последняя, которую я упомяну в этой статье, так как их слишком много, чтобы поместить их все в одну — это основа для быстрой разработки и тестирования. Вы можете скомпилировать свой Wasm, построить проект и запустить сервер одним махом:


emrun --port 7777 --no_browser public/index.html

Now listening at http://localhost:7777/

The html page you are running is not emrun-capable. Stdout, stderr and exit(returncode) capture will not work. Recompile the application with the --emrun linker flag to enable this, or pass --no_emrun_detect to emrun to hide this check.

Хорошо, двумя махами… приведенный выше пример работает, но следующий работает лучше, что объясняет показанная ошибкой.


<b>// compile as emrun project
emcc lib/strings.c -s WASM=1 --emrun -o public/index.html

// run the emrun server again
emrun --port 7777 --no_browser public/index.html</b>

Я просто оставлю это так. Изучая WebAssembly, я отметил День Святого Патрика и следующий день. Не совсем уверен, что будет дальше, но меня это взволновало достаточно, чтобы сидеть перед монитором в течение двух дней, пытаясь вникнуть в основы WebAssebly, и это должно что-то значить, верно? Это самый код на C, который я написал с 2011 года, и он отлично себя чувствует. Я думаю, что у WebAssembly есть реальное будущее, но я не уверен, что он полностью захватит сеть и убьет JS, как проповедуют некоторые. А Вы как думаете?


image




К сожалению, не доступен сервер mySQL