Les scripts compilés de Lua sont à peu près le bytecode brut déposé après un court en-tête. L'en-tête documente certaines des propriétés de la plate-forme utilisée pour compiler le bytecode, mais le chargeur vérifie seulement que la plate-forme actuelle a les mêmes propriétés.
Malheureusement, cela crée des problèmes lors du chargement de bytecode compilé sur une autre plateforme, même si compilé par la même version de Lua. Bien sûr, on ne peut s'attendre à ce que les scripts compilés par différentes versions de Lua fonctionnent, et puisque le numéro de version de Lua est inclus dans l'en-tête bytecode, la tentative de chargement est interceptée par le noyau.
La réponse simple est simplement de ne pas compiler des scripts. Si Lua compile le script lui-même, vous n'avez qu'à vous préoccuper des éventuelles incompatibilités de version entre les cœurs Lua dans vos différentes versions de votre application, et ce n'est pas difficile à gérer.
Actuellement, la compatibilité croisée complète pour le bytecode compilé est not easy. Dans ce courriel, Mike Pall a identifié les questions suivantes:
endianess: échange sur la production selon les besoins.
sizeof(size_t)
, affecte d'énormes constantes de chaîne: vérifier le dépassement lorsque déclassement.
sizeof(int)
, affecte MAXARG_Bx
et MAXARG_sBx
: vérifier débordement lors déclassement. : Facile en C, mais seulement lorsque l'hôte et la cible suivent la même norme FP; précision perte lors de la mise à niveau (cas rare); avertir des nombres non entiers lorsque rétrogradant à int32
.
De toutes les discussions que je l'ai vu au sujet de cette question sur la liste de diffusion, je vois deux approches viables probablement, en supposant que vous n'êtes pas disposé à envisager l'expédition les anciens scripts Lua non compilés. Le premier serait de fixer l'ordre des octets lorsque les scripts compilés sont chargés. Cela s'avère plus facile à faire que prévu, car cela peut être fait en remplaçant la fonction de bas niveau qui lit le fichier de script sans recompiler le noyau lui-même. En fait, il peut même être fait en pur Lua, en fournissant votre propre fonction chunk reader à lua_load(). Cela devrait fonctionner tant que le seul problème de compatibilité sur vos plates-formes est l'ordre des octets.
La seconde consiste à patcher le noyau lui-même pour utiliser une représentation commune pour les scripts compilés sur toutes les plateformes. Cela a été décrit comme possible par Luiz Henrique de Figueiredo:
.... Je suis convaincu que la meilleure route à l'ordre octet ou la compilation croisée est benne tiers/paires undump. Les fichiers ldump.c et lundump.c sont complètement remplaçables; ils exportent un point d'entrée unique, bien défini, . Le format des morceaux précompilés n'est pas sacré du tout; vous pouvez utiliser n'importe quel format, tant que ldump.c et lundump.c sont d'accord à ce sujet. (Par exemple, le lac Rici est compte écrire un format de texte pour morceaux précompilés.) ....
Personnellement, je recommande d'envisager sérieusement de ne pas pré-compilation des scripts et éviter ainsi la les problèmes de portabilité de plate-forme entièrement.
Modifier: J'ai mis à jour ma description de l'en-tête bytecode grâce au commentaire de lhf. Je n'avais pas encore lu cette partie de la source de Lua, et j'aurais probablement dû la vérifier avant d'être si sûre de savoir quelles informations sont ou ne sont pas présentes dans l'en-tête.
Voici le fragment de lundump.c
qui forme une copie de l'en-tête correspondant à la plate-forme en cours de réalisation pour comparaison avec le bytecode en cours de chargement. Il est simplement comparé avec memcmp()
pour une correspondance exacte avec l'en-tête du fichier, de sorte que toute incompatibilité entraînera le rejet du fichier par le chargeur de stock (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? */
}
Comme on peut le voir, l'en-tête est de 12 octets et contient une signature (4 octets, "<esc>Lua
"), les codes de version et le format, un octet de drapeau pour boutisme, les tailles des types int
, size_t
, Instruction
et lua_Number
, et un drapeau indiquant si lua_Number
est un type intégral.
Ceci permet à la plupart des distinctions de plate-forme d'être prises, mais n'essaie pas de saisir toutes les façons dont les plates-formes peuvent différer.
Je suis toujours d'accord avec les recommandations ci-dessus: d'abord, expédier des sources compilables; ou en second lieu, personnalisez ldump.c
et lundump.c
pour stocker et charger un format commun, avec la note supplémentaire que tout format personnalisé doit redéfinir l'octet LUAC_FORMAT de l'en-tête afin de ne pas être confondu avec le format bytecode stock.
Plus d'informations nécessaires: des messages d'erreur sur ce défaut de chargement? –