Luaのコンパイル済みスクリプトは、短いヘッダーの後にダンプされた生のバイトコードとほぼ同じです。ヘッダーには、バイトコードのコンパイルに使用されるプラットフォームのプロパティの一部が記載されていますが、ローダーは、現在のプラットフォームが同じプロパティを持っていることを確認するだけです。
残念ながら、これは、まったく同じバージョンのLuaでコンパイルされた場合でも、別のプラットフォームでコンパイルされたバイトコードをロードするときに問題を引き起こします。もちろん、異なるバージョンのLuaでコンパイルされたスクリプトが機能することは期待できません。また、Luaのバージョン番号がバイトコードヘッダーに含まれているため、それらをロードする試みはコアによってキャッチされます。
簡単な答えは、スクリプトをコンパイルしないことです。Luaがスクリプト自体をコンパイルする場合、アプリケーションのさまざまなビルドでLuaコア間で発生する可能性のあるバージョンの不一致についてのみ心配する必要があり、それを処理するのは難しくありません。
コンパイルされたバイトコードの完全な相互互換性を実際にサポートすることは簡単ではありません。その電子メールで、MikePallは次の問題を特定しました。
エンディアン:必要に応じて出力を交換します。
sizeof(size_t)
、巨大な文字列定数に影響します:ダウングレード時にオーバーフローをチェックします。
sizeof(int)
、影響MAXARG_Bx
およびMAXARG_sBx
:ダウングレード時にオーバーフローをチェックします。
typeof(lua_Number)
:Cでは簡単ですが、ホストとターゲットが同じFP標準に従っている場合に限ります。アップグレード時の精度の低下(まれなケース)。にダウングレードするときに、整数以外の数値について警告し int32
ます。
メーリングリストでこの問題について私が見たすべての議論から、コンパイルされていないLuaスクリプトを出荷することだけを検討したくないと仮定すると、2つの実行可能なアプローチがわかります。
1つ目は、コンパイルされたスクリプトがロードされるときにバイト順序を修正することです。これは、コア自体を再コンパイルせずにスクリプトファイルを読み取る低レベルの関数を置き換えることで実行できるため、予想よりも簡単であることがわかります。実際、 lua_load()に独自のチャンクリーダー関数を提供することで、純粋なLuaで実行することもできます。プラットフォームでの互換性の問題がバイトオーダーのみである限り、これは機能するはずです。
2つ目は、コア自体にパッチを適用して、すべてのプラットフォームでコンパイルされたスクリプトに共通の表現を使用することです。これは、ルイス・エンリケ・デ・フィゲイレドによって可能な限り説明されています。
....バイトオーダーまたはクロスコンパイルへの最適なルートは、サードパーティのダンプ/アンダンプのペアであると確信しています。ファイルldump.cとlundump.cは完全に置き換え可能です。それらは、明確に定義された単一のエントリポイントをエクスポートします。プリコンパイルされたチャンクの形式はまったく神聖ではありません。ldump.cとlundump.cが同意する限り、任意の形式を使用できます。(たとえば、Rici Lakeは、プリコンパイルされたチャンクのテキスト形式を作成することを検討しています。)...。
個人的には、スクリプトを事前にコンパイルしないことを真剣に検討し、プラットフォームの移植性の問題を完全に回避することをお勧めします。
編集: lhfのコメントのおかげで、バイトコードヘッダーの説明を更新しました。私はまだLuaソースのこの部分を読んでいなかったので、ヘッダーにどのような情報が存在するか、または存在しないかについて非常に断定する前に、おそらくそれをチェックする必要がありました。
lundump.c
これは、ロードされているバイトコードと比較するために、実行中のプラットフォームに一致するヘッダーのコピーを形成するフラグメントです。これは、ファイルのヘッダーと完全に一致するかどうかと単純に比較されるmemcmp()
ため、不一致があると、ストックローダー(luaU_undump()
)がファイルを拒否します。
/*
* make header
*/
void luaU_header (char* h)
{
int x=1;
memcpy(h,LUA_SIGNATURE,sizeof(LUA_SIGNATURE)-1);
h+=sizeof(LUA_SIGNATURE)-1;
*h++=(char)LUAC_VERSION;
*h++=(char)LUAC_FORMAT;
*h++=(char)*(char*)&x; /* endianness */
*h++=(char)sizeof(int);
*h++=(char)sizeof(size_t);
*h++=(char)sizeof(Instruction);
*h++=(char)sizeof(lua_Number);
*h++=(char)(((lua_Number)0.5)==0); /* is lua_Number integral? */
}
ご覧のとおり、ヘッダーの長さは12バイトで、署名(4バイト、 " <esc>Lua
")、バージョンコードとフォーマットコード、エンディアンのフラグバイト、タイプのサイズ、、、、、、およびint
であるかどうかを示すフラグが含まれています。一体型。size_t
Instruction
lua_Number
lua_Number
これにより、ほとんどのプラットフォームの区別を把握できますが、プラットフォームが異なる可能性のあるすべての方法を把握しようとはしません。
私はまだ上記の推奨事項を支持しています。まず、コンパイル可能なソースを出荷します。または、次に、カスタマイズldump.c
しlundump.c
て共通フォーマットを保存およびロードします。さらに、カスタムフォーマットは、ストックバイトコードフォーマットと混同しないように、ヘッダーのLUAC_FORMATバイトを再定義する必要があることに注意してください。