В моей последней статье Введение в WebAssembly я показал вам некоторые основы работы с модулем WebAssembly с использованием Emscripten.

Эта статья является результатом некоторых исследований и экспериментов, направленных на то, чтобы увидеть, можно ли создать модуль WebAssembly с использованием Emscripten, но не иметь никакого связующего кода.

Например, если бы мы создали следующий файл C с помощью следующей командной строки, результатом был бы файл HTML размером 101 КБ, файл JS размером 80,2 КБ и файл wasm размером 9,4 КБ!

#include <stdio.h>   
#include "../emscripten/emscripten.h"    

int main() { return 0; }    

int EMSCRIPTEN_KEEPALIVE add(int x, int y) { return x + y; }

emcc test.c -s WASM = 1 -s NO_EXIT_RUNTIME = 1 -O1 -o hello.html

Иметь всю эту сантехнику очень удобно, потому что это позволяет вам сразу же начать экспериментировать с модулями WebAssembly, но что, если нам нужен только минимум и мы сами будем обрабатывать HTML и JavaScript?

К счастью, есть способ указать Emscripten выводить только чистый файл wasm.

Давайте сначала сократим C-файл до минимума. В этом случае нам нужен только метод add:

int add(int x, int y) { return x + y; }

Если мы воспользуемся следующей командной строкой, мы получим только файл wasm размером всего 202 байта!

emcc test.c -s WASM=1 -s SIDE_MODULE=1 -O1 -o test.wasm

Флаг SIDE_MODULE указывает Emscripten компилировать только наши методы и ничего больше, что означает, что у вас также не будет доступа к таким вещам, как printf или malloc.

Если не указан, используется флаг оптимизации по умолчанию: -O0 (заглавная буква o и цифра 0), но это приводит к появлению следующей ошибки при попытке загрузить модуль:

LinkError: import object field 'DYNAMICTOP_PTR' is not a Number

Добавление любого флага оптимизации, кроме -O0, устранит проблему, поэтому в этом примере мы выбрали -O1 (заглавная буква o и цифра 1).

Однако следует отметить, что буква O чувствительна к регистру. Различные доступные флаги оптимизации можно найти здесь: https://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html

Нам также необходимо указать имя выходного файла в командной строке, потому что, если мы этого не сделаем, Emscripten выведет файл с именем a.out.wasm.

Поскольку мы решили не использовать программный код Emscripten, нам нужно написать собственный HTML и JavaScript. Ниже приведены некоторые примеры HTML и JavaScript для загрузки в модуль:

<!DOCTYPE html>   
<html>
<head>
  <meta charset="utf-8"/>
</head>     
<body>
  <input type="button" value="test" onclick="javascript:OnClickTest();" />         

    <script type="text/javascript">
      var gModule = null;
      var importObject = {
        'env': {
          'memoryBase': 0,             
          'tableBase': 0,             
          'memory': new WebAssembly.Memory({initial: 256}),             
          'table': new WebAssembly.Table({initial: 0, element: 'anyfunc'})
        }
      };          

      fetch('test.wasm').then(response =>
        response.arrayBuffer()
      ).then(bytes =>
        WebAssembly.instantiate(bytes, importObject)
      ).then(results => {
        // Hold onto the module's instance so that we can reuse it
        gModule = results.instance;
      });           

      function OnClickTest(){
        alert(gModule.exports._add(1, 2));
      }
   </script>
  </body>
</html>

Возможно, вы заметили, что наш вызов метода C отличается от того, что мы делали в предыдущем сообщении в блоге, - это то, что мы не используем Module.ccall или Module.cwrap. Это вспомогательные методы Emscripten. Здесь мы вызываем метод C.

Еще нужно знать, что ваш JavaScript должен включать символ подчеркивания перед именем метода. Например, в нашем случае наш метод называется add. Когда вы вызываете метод добавления в JavaScript, вы должны использовать _add (1, 2); вместо добавления (1, 2);

Хотя этот подход не может быть решением, которое будет работать в каждой ситуации, учитывая, что у вас нет доступа к таким вещам, как malloc, он может быть полезным способом создания вспомогательной библиотеки, если вы делаете такие вещи, как обработка чисел и Мне не нужны все накладные расходы, связанные с сантехникой Emscripten.