Class Models for Lua

# 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 commands `precompiler.lua` and `preloader.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 of `package.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 is `precompiled`.
-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 is `preload`.
-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-Rio

This project is currently being maintained by Tecgraf at PUC-Rio.