Skip to content

コンパイル方法

概要

Duktapeのコンパイルには、2つの基本ステップがあります。

  • コンフィギュレーション: tools/configure.py を使って、コンパイルのために Duktape のソース・ファイルやヘッダー・ファイルを準備します。要求される Duktape の設定は、configure.py のコマンドライン・オプションを使って記述します。例えば
sh
$ python2 tools/configure.py --output-directory /tmp/output -DDUK_USE_FASTINT -UDUK_USE_ES6_PROXY
$ ls /tmp/output/
duk_config.h  duk_source_meta.json  duktape.c  duktape.h
  • コンパイル: 生成されたヘッダーファイルがコンパイラのインクルード検索パスにあることを確認し、生成されたソースファイル(複数可)をアプリケーションのビルドに含めます;公式のDuktapeビルドスクリプトやMakefileはありません。例えば
sh
$ gcc -O2 -Wall -otest -I/tmp/output /tmp/output/duktape.c my_application.c -lm

Duktapeは通常、アプリケーションと一緒にコンパイルされますが、静的ライブラリや共有ライブラリとしてビルドすることも可能です。Duktapeは、システム全体のライブラリとしてインストールすることもできます。system-install.rstを参照してください。

DUK_OPT_xxx 機能オプションは、Duktape 2.x ではサポートされなくなりました。 すべての設定情報は、duk_config.h や自動生成されたソースやヘッダに埋め込まれています。

コンフィギュレーション

事前設定されたソースとデフォルトの構成

Duktapeの配布物には、いくつかのバリエーションを持つ事前設定済みのソースとヘッダが含まれています。

  • src/: duk_config.h, duktape.h, duktape.c からなる単一のソース・ファイル・バージョンです。
  • src-noline/: src/ と同じですが、結合されたソースファイルに #line 命令がありません。これは環境によっては重要です。https://github.com/svaarala/duktape/pull/363 を参照してください。
  • src-separate/: duk_config.h, duktape.h と別々のソースファイルから構成されるバージョン。単一のソースファイル版が望ましいのですが、ツールチェインによっては別ファイルの方がうまくいく場合もあります。

これらの設定済みソースは、プラットフォーム、コンパイラ、アーキテクチャの自動検出を行い、Duktapeのデフォルト設定を使用します。

  • ECMAScript E5/E5.1完全準拠(オプションのAnnex B機能を含む)、ただし意図的な実世界の互換性逸脱を除く(カスタム動作参照)
  • ES2015 型付け配列と Node.js Buffer のサポート
  • ECMAScript 2015 (E6) と ECMAScript 2016 (E7) からのいくつかの機能
  • 利用可能な場合はパックされた値表現(1値あたり8バイト)、利用できない場合はパックされていない値表現(通常1値あたり16バイト)。
  • 参照カウントとマーク・アンド・スイープ・ガベージコレクション
  • 完全なエラーメッセージとトレースバック
  • デバッグ出力やアサートなどはありません。
  • すべてのポータブルな高速パスが有効

事前設定されたソースは、DuktapeをWindowsのDLLにビルドするためには使用できません。そのためには configure.py に --dll オプションを付けて実行してください。

Duktapeの設定をカスタマイズするためにconfigure.pyを実行する

configure.pyユーティリティは、コマンドラインオプションで記述された特定の設定に対応するDuktapeソースとヘッダファイルを準備します。例えば、fastint サポートを有効にし、ECMAScript 6 Proxy オブジェクトのサポートを無効にして、DLL ビルドのための Duktape ソースを準備する場合です。

sh
# Default output format is single source file (--separate-sources for separate
# sources) and no #line directives (--line-directives to enable them).

$ python2 tools/configure.py \
      --output-directory /tmp/output \
      --dll \
      -DDUK_USE_FASTINT \
      -UDUK_USE_ES6_PROXY

# The output directory /tmp/output contains the header and source files to
# be included in your build.

$ ls /tmp/output
duk_config.h  duk_source_meta.json  duktape.c  duktape.h

configure.py に与えられた設定オプションは、例えば、用意されたヘッダーとソースファイルのいくつかの異なる側面に影響を与えます。

  • Duktape ソースコードのオプション機能は、duk_config.h 設定ヘッダによって提供される設定オプション (DUK_USE_xxx) を使って有効/無効化されます。この設定ヘッダは、プラットフォーム、アーキテクチャ、コンパイラの検出や、プラットフォームの移植性に関する他のすべての側面も処理します。
  • 組み込みオブジェクトと文字列はメタデータファイルから読み込まれ、ビットパックされた組み込み初期化データが生成されます。また、カスタムのメタデータファイルを供給して、カスタムの組み込みバインディングを追加したり、MathやJSONなどの標準組み込みを変更することも可能です。
  • ROMビルトイン "を使用する場合、ビルトインオブジェクトと文字列は、RAMフットプリントを減らすために読み取り専用のコードセクションに配置されます。ビルトインオブジェクトや文字列のイニシャライザに必要なソースコードは、configure.pyによって自動生成されます。また、カスタムのビルトインもリードオンリーコードセクションに配置することができます。
  • Unicodeデータファイル(UnicodeData.txtとSpecialCasing.txt)は、ビットパックされたランタイムユニコードテーブルに変換されます。Unicodeデータファイルは、例えば、Unicodeテーブルのフットプリントを小さくするためにオーバーライドすることも可能です。

configure.py ユーティリティは Python 2.x のサポートが必要です。ビルド環境がPython 2.xをサポートしていない場合、別のプラットフォームでconfigure.pyを実行し、ビルド環境で結果のファイルをコンパイルすることができます。

デフォルトのオプションで問題ない場合でも、事前に設定されたソースを使用する代わりに、ビルドの一部としてconfigure.pyを実行することが推奨されます。カスタムオプションは、例えば低メモリのプラットフォームでは必要かもしれません。より実用的な詳細については、Duktapeのビルドのための設定 を参照してください。

一般的に必要とされる設定オプション

一般的に必要とされる設定オプションをいくつか紹介します。

  • DUK_USE_FATAL_HANDLER, 強く推奨。組み込みのデフォルトの致命的なエラーハンドラは、デバッグログメッセージを書き (stdout と stderr には何も書きません)、次に abort() を呼び出します。これが失敗すると、無限ループに入り、致命的なエラーの後に実行が再開されないことを確認します。これは通常、より優れた致命的なエラーの回復メカニズムを持っている可能性のある実運用アプリケーションにとって、最良の動作ではありません。デフォルトの致命的なハンドラを置き換えるには、致命的なエラーを処理する方法を参照してください。
  • 長い制御転送:setjmp/longjmp と C++ 例外。デフォルトでは、Duktapeは内部の長い制御転送にsetjmp()とlongjmp()(またはその亜種)を使用します。C++コンパイラーでコンパイルする場合は、DUK_USE_CPP_EXCEPTIONSを使用すると、Duktapeが長い制御転送にC++例外を使用し、Duktape/C関数におけるスコープベースのリソース管理(自動デストラクタなど、RAIIと呼ばれることもあります)が期待通りに機能するようになります。MSVCでは、/EHsc例外モデルを避けるように注意してください(代わりに/EHsなどを使用してください)。なぜなら、"c "オプションは、MSVCがextern C関数がC++例外を投げられないと仮定してしまうからです。
  • Windows DLL のビルド。Windows DLL ビルドでは、DLL ライブラリーのシンボルに対して declspec() 宣言が必要です。Duktapeのシンボルに対してこれらを有効にするには、configure.pyの実行時に-dllオプションを使用します。
  • 強制的なバイト順やアライメント。Duktapeの自動機能検出が(まだ)機能していないプラットフォームでDuktapeを使う場合、設定段階で特定のバイト順やアライメントの要件を強制的に指定する必要があるかもしれません。
  • エキゾチック・プラットフォームでの日付ビルトイン。新しいプラットフォームやエキゾチックなプラットフォームに移植する場合、Duktapeの組み込み日付サポートが、そのプラットフォームで動作しないことがあります。このような場合、外部の「Dateプロバイダ」を実装することで、Duktapeの変更なしに、必要な日付/時刻プリミティブを提供することができます。datetime.rstを参照してください。
  • ネイティブ・スタック・チェック・マクロ。ターゲットが小さなスタックを持っている場合、DUK_USE_NATIVE_STACK_CHECK() マクロを定義すると便利です。これは、スタックフレームのサイズを考慮できないスタック深さの制限よりも、スタック枯渇に対するより良い保護策を提供します。

メモリ管理方法の選択肢

メモリ管理の選択肢は2つあります。

  • 参照カウントとマーク&スイープ(デフォルト):ヒープオブジェクトは、到達不可能な参照サイクルに参加しているオブジェクトを除いて、到達不可能になった時点で直ちに解放されます。そのようなオブジェクトは、定期的に自発的に解放され、世界のマークアンドスイープコレクションを停止します。マークアンドスイープは、メモリ割り当てに失敗した場合の緊急ガベージコレクタとしても使用されます。
  • マークアンドスイープのみ: コードフットプリントとメモリーフットプリントを減らしますが (ヒープヘッダが参照カウントを保存する必要がありません)、デフォルトの場合よりもメモリー使用量のばらつきがあります。また、自発的な、世界を停止するマークアンドスイープ収集の頻度は、参照カウントがほぼすべてのメモリ管理を処理することが期待されるデフォルトの場合よりも高くなります。自発的な (緊急でない) mark-and-sweep は config オプションで無効にすることができます。

参照カウントは、参照サイクルを処理するために mark-and-sweep に依存します。例えば、すべての ECMAScript 関数インスタンスは、関数用に作成された自動プロトタイプオブジェクトとの参照ループに入ることが要求されます。必要であれば、このループを手動で解除することができます。内部技術的な理由により、名前付き関数式も参照ループ内にあります。このループはユーザーコードから壊すことができず、mark-and-sweepのみがそのような関数を収集することができます。

コンパイル方法

一般的なガイドライン

Duktapeは公式のMakefileやビルドスクリプトを持っていません:異なる移植性のターゲットの数を考えると、公式のビルドスクリプトを維持することは難しいでしょう。その代わり、最も自然な方法で、既存のビルド・プロセスに Duktape を追加する必要があります。

DuktapeはCまたはC++コンパイラ(C99を推奨)でコンパイルされ、何らかの方法であなたのプログラムにリンクされます。正確な詳細はプラットフォームやツールチェインによって異なります。例えば、以下のようなことが可能です。

  • Duktapeをあなたのプログラムと一緒にコンパイルし、明示的にリンクするステップを省く。
  • Duktapeを静的ライブラリーとしてコンパイルし、その静的ライブラリーをプログラムにリンクする。
  • Duktapeをダイナミック・ライブラリーとしてコンパイルし、ダイナミック・ライブラリーをあなたのプログラムとリンクする。
  • Duktapeをダイナミック・ライブラリーとしてコンパイルし、システム全体にインストールし、いくつかのアプリケーションから使用する。

DuktapeのAPI関数はすべてマクロである可能性があり、あるAPIプリミティブの実装は互換性のあるリリース間でもマクロと実際の関数とで変わる可能性があります。Duktapeの設定オプションの中には、バイナリ互換性に影響を与えるものがあります。バイナリ互換性を確保するために

  • アプリケーション・コードにduktape.hをインクルードしてください。これは一般的に良い習慣ですが、このヘッダーがないと、コンパイラーは全てのDuktape API関数が実際の関数であると誤って判断してしまい、リンクに失敗する原因となります。
  • Duktapeとアプリケーションをコンパイルする際には、用意した同じDuktapeソースとヘッダを使用してください。これにより、Duktapeとあなたのアプリケーションは、全く同じDuktapeのバージョンとコンフィギュレーションでコンパイルされることを保証します。これは、Duktapeがライブラリとして別のコンパイル・ステップでコンパイルされる場合に特に重要です。
  • Duktapeとアプリケーションをコンパイルする際には、同じコンパイラーを使用してください。異なるコンパイラーを使うと、例えばDuktapeのduk_config.hヘッダーの型検出や、関数の呼び出し規則などに影響を与え、バイナリ互換性が損なわれる可能性があります。実際には、コンパイラはある程度混在させることができます。たとえば、GCCとClangは一般に互換性があります。

推奨されるコンパイラのオプション

GCC/clang のための推奨コンパイラー・オプションです。

  • -std=c99: C99のセマンティクスを確保することを推奨。C型の検出を改善し、Duktapeが可変長マクロを使えるようにします。
  • -Wall:潜在的な問題を早期に発見するために推奨します。
  • -Os: Duktapeをエンベッディングする際に必要な、最小のフットプリントを実現するために最適化されます。-O2 は、パフォーマンスを最適化したビルドのための良い妥協点です。
  • -fomit-frame-pointer: フレーム・ポインターを省略します。フットプリントはさらに小さくなりますが、デバッグの妨げになる可能性があります(デバッグ・ビルドからは除外してください)。
  • -fstrict-aliasing: 厳密なエイリアシングルールを使用します。Duktapeはこれらのルールと互換性があり、結果のCコードを改善します。
  • Configure.py の --dll は、Duktape が DLL としてビルドされる場合、少なくとも Windows 用にコンパイルする場合は必要です。

コンパイル時の警告について

Duktapeは、主流のコンパイラー(GCC、Clang、MSVC、MinGWなど)をC99モードで使用し、警告を有効にし(例:gcc/clangの-Wall)、デフォルトのDuktape設定オプションを使用すると、通常警告なしにコンパイルされます。非主流コンパイラー、非常に厳しい警告レベル(gcc/clangの-WextraやMSVCの/W4など)、デフォルトでないDuktape設定オプションを使用した場合、いくつかの警告が発生する可能性があります。すべてのコンパイラとすべての設定オプションの組み合わせについて、コンパイル時の警告をなくすことは非常に困難であり、プロジェクトの目標には明示的になっていません。警告を報告して、可能な限り修正することが推奨されます。

C++コンパイラを使う場合

Duktapeは、CとC++の両方のコンパイラーとアプリケーションで動作します。Duktapeとアプリケーションは、CコンパイラーとC++コンパイラーを自由に組み合わせてコンパイルすることができます。ただし、Duktapeとアプリケーションは、同じコンパイラ(CコンパイラまたはC++コンパイラ)で、同じコンパイラ・オプションでコンパイルすることが推奨されます。

duktape.hヘッダは、これらの組み合わせのすべてを動作させるために必要なグルー(接着剤)を含んでいます。具体的には、DuktapeのパブリックAPIが必要とする全てのシンボルは、extern "C" { ...}の中に入っています。C++コンパイラーでコンパイルする場合は、extern "C" { ...} ラッパーの中に入っています。これにより、そのようなシンボルはC++の名前を混乱させることなく定義され、使用されることが保証されます。具体的には

  • Duktape自身をC++コンパイラーでコンパイルする場合、DuktapeのパブリックAPIが必要とするシンボルはマングルされません。その他のDuktape内部のシンボルはマングルされますが、外部からは見えないので、Cコンパイラーでコンパイルしても問題はありません。
  • C++コンパイラーでアプリケーションをコンパイルする場合、ラッパーは、アプリケーションが使用するDuktapeパブリックAPIシンボルがマングルされずにルックアップされることを保証します。

CとC++のコンパイルが混在している場合、最終的なリンクはC++ツールチェーンで行う必要があります。少なくともgcc/g++を混在させた場合、以下のようなことに遭遇するかもしれません。

sh
$ g++ -c -o duktape.o -Isrc/ src/duktape.c
$ gcc -c -o duk_cmdline.o -Isrc/ examples/cmdline/duk_cmdline.c
$ gcc -o duk duktape.o duk_cmdline.o -lm
duktape.o:(.eh_frame+0x1ab): undefined reference to \`__gxx_personality_v0\'
collect2: error: ld returned 1 exit status

修正方法としては、リンクにg++を使用することです。

sh
$ g++ -c -o duktape.o -Isrc/ src/duktape.c
$ gcc -c -o duk_cmdline.o -Isrc/ examples/cmdline/duk_cmdline.c
$ g++ -o duk duktape.o duk_cmdline.o -lm

duk_config.hはDuktapeが必要とするC/C++データ型を選択し、その他の機能検出も行うため、CとC++コンパイラーを混在させると、理論的にはCとC++コンパイラーが異なる有効な機能やデータ型になってしまう可能性があります。もしそのようなことが起これば、Duktapeとアプリケーションのバイナリに互換性がなくなり、問題を診断するのが非常に困難になります。これは通常、問題にはなりませんが、この可能性を避けるために、Duktapeとアプリケーションを同じコンパイラーでコンパイルしてください。

デフォルトでは、スコープ・ベースのリソース管理(RAIIと呼ばれることもあります)はDuktape/C関数では動作しません。これは、Duktapeが内部の長い制御転送にlongjmp()を使用し、C++スタック巻き戻しメカニズムを回避しているためです。DUK_USE_CPP_EXCEPTIONSを使用すると、Duktapeは内部での長い制御転送にC++の例外を使用するようになり、Duktape/C関数でスコープ・ベースのリソース管理を動作させることができるようになります。MSVCでは、/EHsc例外モデルを避けるように注意してください(代わりに/EHsなどを使用してください)。なぜなら、"c "オプションは、MSVCがextern C関数がC++例外を投げることができないと仮定するからです。MSVCとCMakeを使用する場合、例えば以下のように使用できます。

sh
if (MSVC)
    string( REPLACE "/EHsc" "/EHs" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" )
endif()