lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

Hi Asko,

> Now, why make it so complicated?  Why not just say, that in the
> absence of "luaopen_myfilename()" function, a "luaopen_init()" (or  
> similar) will be called.

What we currently do is to use a different (non-standard) loader that
can handle specially named C modules.  We use that to have e.g. a flat
directory structure (for DLL's) but still use a hierarchical "dotted" 
module name.  You'll find the (pseudo)code below.  Since we don't use
the standard cloader, a boot script typically replaces the package
loaders entries with some of our own.  These special loaders are
statically linked --as byte code-- into our Lua "kernel" to avoid
bootstrap problems.  [BTW Currently the official package system does
not provide a way to gracefully alter the loaders table (e.g. replace
just the cloader) since the loaders can not be identified...  Or am I
missing something here?]  Here is a simple but effective loader
factory that we use (pseudo code):

-- create a C loader.  The split argument is used to split the module
-- name in a name for the binary file and a name for the entry point
-- in the binary.  If split is not specified then the default splitter
-- 'csplitter' is used.  If the split function does not return two
-- parts then the entire loader is skipped.  This allows a loader to
-- only respond to module names that match some special pattern.

local function csplitter(modname)
  local _, _, fname, entry = string.find(modname, "^([^%-]+)%-(.+)")
  if not fname then
    fname = modname
    entry = modname
  fname = string.gsub(fname, "%.", "\\")
  entry = "luaopen_" .. string.gsub(entry, "%.", "_")
  return fname, entry

function package.cloader(path, split)
  split = split or csplitter

  return function(modname)
    local fname, entry = split(modname)

    if fname and entry then
      local fpath = findfile(fname, path)
      if fpath then
        return assert(loadfunc(fpath, entry),
          entry .. " not found in " .. fpath)

Now you can install special loaders like so:

  package.loaders[1] = preloader

  -- a specific binary module loader...
  package.loaders[2] = package.cloader(mypath, mysplitter)

  -- the standard binary module loader
  package.loaders[3] = package.cloader(package.cpath)

This works very well (for us at least) and is quite flexible.