
Pre-Loading Script Libraries
If you plan to embed a Lua script library like LOOP in a C/C++ application you may prefer to generate a C library with your library's script files already pre-compiled. To do so, you may use the scripts precompiler.lua
and preloader.lua
provided in the LOOP package. Such scripts work as a sort of replacement for the old bin2c
application that used to be included in the Lua distribution, however they are primarily intended to pre-compile and pre-load scripts that implement modules following the Lua 5.1 package model. For pre-compilation of ordinary scripts check out bin2c or other implementations of the old bin2c
application. Anyway, the scripts provided in the LOOP package are very general and may be used to generate pre-compiled libraries for any set of Lua scripts.
- WARNING:
- The current version of these scripts require class Argument Processor to handle command-line options. So it might be necessary to make the LOOP library available in the
LUA_PATH
. Alternatively, you may simply redefine your commands as:lua -epackage.path=[[<LOOP_HOME>/?.lua]] <LOOP_HOME>/precompiler.lua
lua -epackage.path=[[<LOOP_HOME>/?.lua]] <LOOP_HOME>/preloader.lua
Anyway, these scripts are very easy to read and modify, so feel free to change them in any way to better fit your demands.
On the other hand, these concerns are not valid if you installed LOOP's rock through LuaRocks. In such case, you can use these scripts simply through commandsprecompiler.lua
andpreloader.lua
.
Pre-Compilation
To generate pre-compiled libraries, first select the script files that should be included in the library. Next, use the precompiler.lua
script to generate the C source file that includes the pre-compiled scripts. This script receives a list of optional parameters and the path of all the script files that should be pre-compiled. The path to these script files must follow the same hierarchy of the packages that they implement so the package name shall be correctly inferred from the provided Lua path. The options precompiler.lua
script accepts are the following:
- -b, -bytecodes
- Flag that indicates the provided arguments are file paths containing bytecodes (e.g. instead of source code), like the output of the
luac
compiler. When this flag is used no compilation is performed by this script. - -d, -directory
- Directory where the output files should be generated. Its default is the current directory.
- -l, -luapath
- Sequence os path templates used to infer package names from file paths and vice versa. These templates follows the same format of the
package.path
field of Lua. Its default is the value ofpackage.path
. - -n, -names
- Flag that indicates provided input names are actually package names and the real file path should be inferred from the path defined by -luapath option. This flag can be used in conjunction with the -bytecodes flag to indicate that inferred file paths contains bytecodes instead of source code.
- -o, -output
- Name used to form the name of the files generated. Two files are generated: a source code file with the sufix
.c
with the pre-compiled scripts and a header file with the suffix.h
with function signatures. Its default isprecompiled
. - -p, -prefix
- Prefix added to the signature of the functions generated. Its default is LUAOPEN_API.
Example
> lua precompiler.lua -o loop -l lua/?.lua \ lua/loop/base.lua \ lua/loop/cached.lua \ lua/loop/multiple.lua \ lua/loop/scoped.lua \ lua/loop/simple.lua \ lua/loop/table.lua \ lua/loop/collection/MapWithArrayOfKeys.lua \ lua/loop/collection/ObjectCache.lua \ lua/loop/collection/OrderedSet.lua \ lua/loop/collection/PriorityQueue.lua \ lua/loop/collection/UnorderedArray.lua \ lua/loop/collection/UnorderedArraySet.lua \ lua/loop/compiler/Arguments.lua \ lua/loop/compiler/Conditional.lua \ lua/loop/compiler/Expression.lua \ lua/loop/debug/Inspector.lua \ lua/loop/debug/Matcher.lua \ lua/loop/debug/Verbose.lua \ lua/loop/debug/Viewer.lua \ lua/loop/object/Exception.lua \ lua/loop/object/Wrapper.lua \ lua/loop/serial/FileStream.lua \ lua/loop/serial/Serializer.lua \ lua/loop/serial/SocketStream.lua \ lua/loop/serial/StringStream.lua \ lua/loop/thread/CoSocket.lua \ lua/loop/thread/IOScheduler.lua \ lua/loop/thread/Scheduler.lua \ lua/loop/thread/SocketScheduler.lua \ lua/loop/thread/Timer.lua
The package name is inferred by matching the provided path with the Lua path patterns defined with option -luapath
and no path expansion is performed. Therefore precompiler.lua
won't be able to figure out the package name of file mypacks/loop/base.lua
if the provided Lua path is /home/user/mypacks/?.lua
even though the current directory is /home/user
. However if the Lua path is set to mypacks/?.lua
the inferred package name would be loop.base
. When the Lua path defines multiple patterns, the last (i.e. rightmost) that matches the file path is used to define the package name.
Alternatively, you shall provide the flag -names
to precompiler.lua
and provide package names instead of file paths. In such case, the provided Lua path is used to figure out the file that contains the actual package implementation. This is useful when package name cannot be correctly inferred from the file path like in case-insensitive file systems. Therefore the above example could be rewritten like below:
Example
> lua precompiler.lua -o loop -l lua/?.lua -n \ loop.base \ loop.cached \ loop.multiple \ loop.scoped \ loop.simple \ loop.table \ loop.collection.MapWithArrayOfKeys \ loop.collection.ObjectCache \ loop.collection.OrderedSet \ loop.collection.PriorityQueue \ loop.collection.UnorderedArray \ loop.collection.UnorderedArraySet \ loop.compiler.Arguments \ loop.compiler.Conditional \ loop.compiler.Expression \ loop.debug.Inspector \ loop.debug.Matcher \ loop.debug.Verbose \ loop.debug.Viewer \ loop.object.Exception \ loop.object.Wrapper \ loop.serial.FileStream \ loop.serial.Serializer \ loop.serial.SocketStream \ loop.serial.StringStream \ loop.thread.CoSocket \ loop.thread.IOScheduler \ loop.thread.Scheduler \ loop.thread.SocketScheduler \ loop.thread.Timer
Additionally, if the flag -bytecodes
is used with the precompiler.lua
script then it assumes that the provided files contain bytecodes instead of source code. This is useful to create source files with scripts pre-compiled with luac
in platforms other than the one where the application is being written.
Finally, if no additional parameter is provided other than the options listed above, then the file paths or package names are read from the standard input. Therefore, if the list of package to be compiled is stored in file loop.lpk
and they are already compiled in directory compiled
in files with extension .lo
that follow the same hierarchy of the packages then the compilation command could be:
Example
> lua precompiler.lua -o loop -l compiled/?.lo -n -b < loop.lpk
As a result of the examples above you will get the files loop.c
and loop.h
that can be compiled to produce a library that offers functions that load each one of the scripts pre-compiled. Such functions follow the pattern defined by the Lua package model. Examples are:
int luaopen_loop_base(lua_State*); int luaopen_loop_simple(lua_State*); int luaopen_loop_collection_ObjectCache(lua_State*); int luaopen_loop_collection_OrderedSet(lua_State*);
Note: Since these function signatures comply with the standard defined by Lua package model then loop.c
can be used to generate a dynamic C library that exports all functions defined in loop.h
and is able to load all LOOP packages if properly installed in the directory for C packages (see field package.cpath
).
Pre-Loading
However, to effectively load such scripts in an application, you have to call these operations provided by the library in the right loading sequence that respects each package dependencies. Alternatively, you may pre-load such scripts by registering these functions in the package.preload
table so they are executed when each package is first required. This can be automatically done by the code generated with script preloader.lua
. This script receives a list of optional parameters and the path of the headers of libraries that should be pre-loaded. The options preloader.lua
script accepts are the following:
- -d, -directory
- Directory where the output files should be generated. Its default is the current directory.
- -I, -i, -includes
- Adds a directory to the list of paths where the header files of pre-compiled libraries are searched.
- -f, -funcname
- Name of the generated function that pre-loads all library modules. Its default is
luapreload_
plus the name defined by option-output
. - -n, -names
- Flag that indicates provided input names are actually package names and not header files.
- -o, -output
- Name used to form the name of the files generated. Two files are generated: a source code file with the sufix
.c
with the pre-loading code and a header file with the suffix.h
with the function that pre-loads the scripts. Its default ispreload
. - -p, -prefix
- Prefix added to the signature of the functions generated. Its default is LUAPRELOAD_API.
Example
> lua preloader.lua -o looplib -f luapreload_loop loop.h
As a result you will get the files looplib.c
and looplib.h
that can be compiled with the files loop.c
and loop.h
to produce a library that offers a function with the following signature:
int luapreload_loop(lua_State*);
This function registers all the functions defined by loop.h
header with the names of the corresponding packages. This way, function luapreload_loop
can be used to pre-load all scripts previously compiled in loop.c
so they are automatically loaded when required.
The preloader.lua
script also works with header files of Lua libraries written in C/C++. For example, to generate a library that pre-loads the full LuaSocket library, including its script files you can use the following commands.
> lua precompiler.lua -o luasocketscripts -l "?.lua" \ socket.lua \ socket/ftp.lua \ socket/http.lua \ socket/smtp.lua \ socket/tp.lua \ socket/url.lua
> lua preloader.lua -o fullluasocket -I <LUASOCKET_HOME>/include \ luasocket.h \ luasocketscripts.h
These commands produces files luasocketscripts.c
, luasocketscripts.h
, fullluasocket.c
, and fullluasocket.h
that shall be compiled with the C source files of the LuaSocket library to produce a library that provides operation int luapreload_fullluasocket(lua_State*)
that may be used to pre-load into the provided Lua state the full LuaSocket library, including its script files.
Alternatively, you can provide the names of the packages that should be pre-loaded instead of header files that contains signature of the package opening functions. To do so, just provide the flag -names
to the preloader.lua
script. This is useful when package name cannot be inferred correctly from the luaopen_*
function. For example a package named my_lib.my_package
is loaded by function luaopen_my_lib_my_package
that preloader.lua
script would register under the name my.lib.my.package
. To avoid this, use the package name like in the example below.
> lua preloader.lua -o mylib -n my_lib.my_package
Similar to the precompiler.lua
script, if no additional argument is provided then the list of header files or package names is read from the standard input.
Copyright (C) 2004-2008 Tecgraf, PUC-RioThis project is currently being maintained by Tecgraf at PUC-Rio.