C / C ++ライブラリをJavaScript(xml.js)に移植する

この記事は、記事「 HOWTO:C / C ++ライブラリをJavaScript(xml.js)に移植する 」(著者: azakai )の更新版です。 元の記事の著者は、C / C ++ライブラリをJavaScriptに移植した経験が豊富です。 特に、 lzma.jssql.jsの移植に成功しました。 彼の記事では、XML検証用のオープンライブラリであるlibxmlの例を使用して、C / C ++コードを移植するための一般的なスキームについて説明しています。



さらに、この記事には、Ubuntu 12.04環境でlibxmlを移植するために必要な手順の完全なシーケンスが含まれています。 必要な環境設定とemscriptenを含めます。



Emscriptenをインストールして構成する



Emscriptenは、JavaScriptのLLVMバイトコードからのコンパイラです。 C / C ++コードは、 clangコンパイラを使用してLLVMバイトコードにコンパイルできます。 他の言語にもLLVMバイトコードコンパイラがあります。 バイトコードに基づいたEmscriptenは、最新のブラウザーなどのJavaScriptインタープリターで実行できる適切なJavaScriptコードを生成します。 emscriptenを使用して、Mozillaのスタッフは最近Doomの移植に成功しました。



Emscriptenは以下を提供します。emconfigure-環境をセットアップし、その後./configureを起動するためのユーティリティ。 emmake-環境を構成してからmakeを実行するユーティリティ。 emcc -JavaScriptのLLVMコンパイラ。



それでは、emscriptenを操作するための環境をセットアップしましょう( マニュアルを参照)。



clang + llvmをインストール(> = 3.0):

wget llvm.org/releases/3.0/clang+llvm-3.0-i386-linux-Ubuntu-11_10.tar.gz

tar xfv clang + llvm-3.0-i386-linux-Ubuntu-11_10.tar.gz


node.jsをインストールします(> = 0.5.5):

sudo apt-get install nodejs


emscriptenの現在のバージョンをアンロードします。

git clone git://github.com/kripken/emscripten.git

cd emscripten


clangの正常性の確認:

../clang+llvm-3.0-i386-linux-Ubuntu-11_10/bin/clang tests / hello_world.cpp

./a.out

>>こんにちは、世界!


node.jsの正常性の確認:

ノードテスト/ hello_world.js

>>こんにちは、世界!


emccを初めて実行して、構成ファイル「 〜/ .emscripten 」を作成します。

./emcc


構成ファイルで、clang + llvmディレクトリーとemscriptenインストールディレクトリーを指定する必要があります。

EMSCRIPTEN_ROOT = os.path.expanduser( ' 〜/ path / emscripten ')#これはemscriptenを使用するプロジェクトが見つけるのに役立ちます

LLVM_ROOT = os.path.expanduser( ' 〜/パス/ clang + llvm-3.0-i386-linux-Ubuntu-11_10 / bin ')


emccを再度実行して、正しく構成されていることを確認する必要があります。 この場合、「 emcc:no input files 」というメッセージが表示されます

./emcc

>> emcc:入力ファイルなし


emccを使用してhello_wolrd.cppをコンパイルすることにより、すべてが正しく機能することを確認できます。

./emcc tests / hello_world.cpp

ノードa.out.js

>>こんにちは、世界


パート1:C / C ++ソースのコンパイル



移植を開始する前に、プロジェクトのソースコードがC / C ++コンパイラによってエラーなしでコンパイルされていることを確認する必要があります。



リポジトリからlibxmlをアンロードしてコンパイルします。

git clone git://git.gnome.org/libxml2

cd libxml2

git checkout v2.7.8

CC =〜/パス/ clang + llvm-3.0-i386-linux-Ubuntu-11_10 / bin / clang ./autogen.sh --without-debug --without-ftp --without-http --without-python-正規表現なし-スレッドなし-モジュールなし

作る


Libxmlには、xmlスキーマを検証するためのxmllintコンソールユーティリティが含まれています。 コンパイルされたコードの正しい動作を検証するために使用できます。 このようなチェックを実行する必要があります。これには、元のバージョンと移植されたバージョンが等しく正しく動作することを確認することも含まれます。 xmllintでのテストは次のようになります。

$。/ xmllint --noout --schema test.xsd test.xml

>> test.xml検証


すべてが正常に機能する場合、test.xmlファイルにいくつかの変更を加えると、xmllintがエラーメッセージを表示します。



パート2:構成



次のコマンドでemscriptenを使用して、プロジェクトをコンパイル用に構成できます。

〜/ path / emscripten / emconfigure ./autogen.sh --without-debug --without-ftp --without-http --without-python --without-regexps --without-threads --without-modules


emconfigureは、。/ configureがgccまたはclangの代わりにemccコンパイラーを使用するように環境変数を設定します。 ./configureが正しく機能するように環境を設定します(構成テスト(ネイティブコードをコンパイルする)を含む)。



デフォルトの構成結果(フラグなし)には、この段階での多くの不必要な機能(HTTPおよびFTPサポートなど)が含まれます。 xml-schemesを検証するだけなので、プロジェクトを構成して、不要な機能を排除する必要があります。 一般に、移植する際に不要な機能を除外することをお勧めします。 これにより、コードのサイズが小さくなり、ネットワーク環境にとって重要になります。 さらに、一部のヘッダーファイルでは、手動編集が必要な場合があります(glibcではなく、newlibを使用するファイル)。



パート3:プロジェクトをビルドする



アセンブリは次のコマンドによって実行されます。

〜/パス/ emscripten / emmake make


emmakeはemconfigureと似ています:環境変数も設定します。 emmakeのおかげで、ビルド中にネイティブコードの代わりにLLVMバイトコードが生成されます。 これは、各オブジェクトファイルとそれに続くレイアウトのJavaScriptコードの生成を回避するために行われます。 代わりに、LLVMバイトコードビルダーが使用されます。



アセンブリの結果、多くの異なるファイルが構築されます。 しかし、それらを実現することはできません。 前述のように、これはLLVMバイトコード(BCを使用して表示できます)であるため、次のステップが必要です。



パート4:JavaScriptへの変換



xmllintはxmllint.oおよびlibxml2.aに依存しています。 LLVMリンカーは動的リンク(遅延バインディング)をサポートせず、emccはそれを無視します。 そのため、リンクするlibxml2.a静的ライブラリを手動で指定する必要があります。



libz (圧縮用のオープンライブラリ)への依存は、それほど明白ではありません。 libz.aなしでビルドすると、gzopen関数を呼び出そうとすると、実行中にエラーが発生します。 したがって、libz.aをビルドする必要があります。

cd〜/パス

wget zlib.net/zlib-1.2.7.ta​​r.gz

tar xfv zlib-1.2.7.ta​​r.gz

cd zlib-1.2.7

〜/ path / emscripten / emconfigure ./configure --static

〜/パス/ emscripten / emmake make


これで、JavaScriptコードをコンパイルできます。

cd〜/パス/ libxml2

〜/ path / emscripten / emcc -O2 xmllint.o .libs / libxml2.a ../zlib-1.2.7/libz.a -o xmllint.test.js --embed-file test.xml --embed-file test.xsd


どこで:





パート5:JavaScriptのテスト



Node.js、SpiderMonkey、またはV8が提供するJavaScriptコンソールを使用して、このコードを実行できます。

ノードxmllint.test.js --noout --schema test.xsd test.xml

>> test.xml検証


結果はネイティブコードとまったく同じになります。 同様に、xmlスキーマにエラーを導入した場合、xmllintはそれらを検出する必要があります。



重要 :ネイティブビルドとJavaScriptビルドに使用されるすべての引数は正確に同一でなければなりません。



パート6:リファクタリングと再利用



現時点では、検証用の2つのファイルがスクリプトにハードコーディングされています。 スキームに従ってXMLファイルを検証するには、一般化された関数が必要です。 実際には簡単ですが、作業が追加されるClosure Compilerを使用してコードが最適化されることを考慮する必要があります。



最初に行うことは、--pre-jsオプションを指定してemccを呼び出すことです。 生成されたコードの前にJavaScriptコードを追加します(それぞれpost-js、後)。 重要なことは、最適化が実行される前であっても--pre-jsがコードを追加することです。 そして、これは正しい最適化に必要なコードが生成されたコードとともに最適化されることを意味します。 一方、Closure Compilerは、必要な関数を未使用として破棄できます。



--pre-jsオプションを使用して含めるスクリプトは次のとおりです。

 モジュール['preRun'] = function(){
     FS.createDataFile(
       「/」、
       「test.xml」、
      モジュール['intArrayFromString'](モジュール['xml'])、
      本当
       true);
     FS.createDataFile(
       「/」、
       「test.xsd」、
      モジュール['intArrayFromString'](モジュール['schema'])、
      本当
       true);
   };
  モジュール['arguments'] = ['--noout'、 '-schema'、 'test.xsd'、 'test.xml'];
  モジュール['return'] = '';
  モジュール['print'] = function(text){
    モジュール['return'] + = text + '\ n';
   }; 


次のスクリプトを検討してください。



したがって、入力ファイルtest.xmlおよびtest.xsdにユーザーが入力した情報が含まれ、検証結果がバッファーに保存されるようになりました。



ただし、それだけではありません。 コードをコンパイルします。

〜/パス/ emscripten / emcc -O2 xmllint.o .libs / libxml2.a ../zlib-1.2.7/libz.a -o xmllint.raw.js --pre-js pre.js


コンパイルコマンドは以前のように見えますが、ファイルを含める必要がなくなりました。 代わりに、-pre-jsフラグを使用してpre.jsを含めます。



コンパイル後、xmllint.raw.jsには最適化および縮小されたコードが含まれます。 使いやすくするために、JavaScript関数でラップします。

 関数validateXML(xml、スキーマ){
     var Module = {
       xml:xml、
      スキーマ:スキーマ
     };
     {{{GENERATED_CODE}}}
     return Module.return;
   } 


GENERATED_CODEは、コンパイル結果(xmllint.raw.js)に置き換える必要があります。 validateXML関数は、適切な引数をxmlおよびスキーマフィールドに割り当てます。 したがって、test.xmlおよびtest.xsdファイルにユーザーデータが含まれていることを確認します。 生成されたコードが実行された後、関数は検証結果を返します。



以上です! xml.jsは、通常のJavaScriptコードから使用できます。 必要なのは、jsファイルをインクルードし、xmlとスキーマでvalidateXML関数を呼び出すだけです。



All Articles