WebAssembly - C++との連携

こんにちは、未來のプログラマーさんたち!今回はWebAssemblyとC++の世界にご案内するのがとても楽しみです。私がコンピュータサイエンスを教えて10年以上経つものですが、このトピックは初めて聞くと難しいように思えるかもしれませんが、私たちはそれを小さなかみverdに分解して、完全な初心者でも消化できるようにします。では、腕をまくって一緒に潜りましょう!

WebAssembly - Working with C++

WebAssemblyとは?

コードに飛び込む前に、まずWebAssemblyとは何かを理解しましょう。あなたが自分の言語を理解していない人に話しかけようとする場合、翻訳者が必要ですよね?WebAssemblyは、あなたのウェブブラウザのためのその翻訳者です。C++などの言語で書かれたプログラムが、近いネイティブスピードでウェブブラウザ内で動作できるようにします。すごいですね?

なぜC++とWebAssembly?

「なぜC++?」と思うかもしれませんね。C++はプログラミング言語の中のスイスアーミーナイフのように、強力で柔軟であり、長い間存在してきました。WebAssemblyと組み合わせることで、ハイパフォーマンスなアプリケーションをウェブに持ってくることができます。まるでウェブサイトをターボチャージするようなものです!

環境の設定

最初のコードを書く前に、ワークスペースを設定する必要があります。心配しないでください、私はあなたをステップバイステップで案内します:

  1. Emscriptenをインストールします:これは私たちの魔法の杖で、C++をWebAssemblyに変換します。
  2. テキストエディタを設定します:Visual Studio Codeをお勧めしますが、他のテキストエディタでも構いません。
  3. ターミナルを開きます:コードをコンパイルするために使用します。

最初のWebAssemblyプログラム

簡単な「Hello, World!」プログラムから始めましょう。以下のコードを見てください:

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

extern "C" {
EMSCRIPTEN_KEEPALIVE
void sayHello() {
printf("Hello, WebAssembly World!\n");
}
}

これを分解してみましょう:

  • #include <emscripten/emscripten.h>: この行はEmscriptenのヘッダーファイルをインクルードし、WebAssembly関連の関数にアクセスできるようにします。
  • extern "C": これはコンパイラに、私たちの関数に対してCスタイルの名前を使用するように指示します。
  • EMSCRIPTEN_KEEPALIVE: これは私たちの関数に「消さないでください」というサインを立て、JavaScriptからアクセスできるようにします。
  • void sayHello(): これは挨拶を表示する関数です。

コードのコンパイル

魔法の杖を振る時がやってきました!ターミナルで以下のコマンドを実行します:

emcc hello.cpp -o hello.html -s NO_EXIT_RUNTIME=1 -s "EXPORTED_RUNTIME_METHODS=['ccall']"

このコマンドはまるでハリー・ポッターの魔法の呪文のようですが、説明します:

  • emcc: これは私たちのコンパイラです。
  • hello.cpp: 私たちのソースファイルです。
  • -o hello.html: これはHTMLファイルを生成し、ブラウザで開けるようにします。
  • 残りの部分は、JavaScriptとWebAssemblyがうまく連携するようにする特別なフラグです。

WebAssemblyの実行

生成された hello.html をブラウザで開き、コンソールを開いて以下のコードを入力します:

Module.ccall('sayHello', null, null, null);

コンソールに「Hello, WebAssembly World!」が表示されれば、おめでとうございます!あなたは刚刚ブラウザ内でC++を実行しました!

より複雑な例:フィボナッチ数の計算

初めての経験を消化した後、少し難しいものに挑戦しましょう - フィボナッチ数の計算です。

#include <emscripten/emscripten.h>

extern "C" {
EMSCRIPTEN_KEEPALIVE
int fibonacci(int n) {
if (n <= 1) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
}

この関数は、n番目のフィボナッチ数を再帰的に計算します。これは最も効率的な方法ではありませんが、デモンストレーションには適しています!

同じようにコンパイルし、以下のようにJavaScriptから呼び出します:

console.log(Module.ccall('fibonacci', 'number', ['number'], [10]));

これは10番目のフィボナッチ数(55)を表示するはずです。

配列との連携

レベルアップして配列を扱ってみましょう。以下は配列の合計を計算する関数です:

#include <emscripten/emscripten.h>

extern "C" {
EMSCRIPTEN_KEEPALIVE
int sumArray(int* arr, int size) {
int sum = 0;
for (int i = 0; i < size; i++) {
sum += arr[i];
}
return sum;
}
}

JavaScriptからこれを使用するためには、少し作業が必要です:

let arr = new Int32Array([1, 2, 3, 4, 5]);
let buffer = Module._malloc(arr.length * arr.BYTES_PER_ELEMENT);
Module.HEAP32.set(arr, buffer >> 2);
let sum = Module.ccall('sumArray', 'number', ['number', 'number'], [buffer, arr.length]);
Module._free(buffer);
console.log(sum);  // 15と表示されるはずです

これは以下の手順を行っています:

  1. JavaScriptで配列を作成します。
  2. WebAssemblyのヒープにメモリを割り当てます。
  3. 配列をそのメモリにコピーします。
  4. 関数を呼び出します。
  5. 割り当てたメモリを解放します。

結論

おめでとうございます!あなたはC++とWebAssemblyの世界への最初の一歩を踏み出しました。私たちは多くのことをカバーしましたが、基本的な「Hello, World!」から配列の操作までです。コードを学ぶことは新しい言語を学ぶのと同じで、練習と忍耐が必要です。すぐにすべてを理解できない場合でもがっかりしないでください。実験を続け、コーディングを続け、そして最も重要なのは、楽しむことです!

以下に、私たちが使用した主要なメソッドをまとめた表を示します:

メソッド 説明
emcc Emscriptenコンパイラコマンド
EMSCRIPTEN_KEEPALIVE 関数が最適化されないようにするマクロ
Module.ccall JavaScriptメソッドでC++関数を呼び出す
Module._malloc WebAssemblyヒープにメモリを割り当てる
Module._free 割り当てたメモリを解放する
Module.HEAP32 WebAssemblyメモリのInt32Arrayビュー

WebAssemblyとC++はウェブ開発の可能性を広げます。空の限界はありません!コーディングを続け、学び続け、もしかしたら数年後、あなたがこのコースを教えるかもしれませんね!

Credits: Image by storyset