 <p>Well according to the <a href="https://www.lua.org/manual/5.2/manual.html#pdf-package.searchers" rel="nofollow">Lua documentation on the require call</a> (using Lua 5.2 here), there are a few places the loader looks for these loadable modules.</p> <p>It seems that <code>require()</code> uses what are called "searchers" (docs linked to in above) to determine where to find these modules. There are four searchers in total. From the docs:</p> <blockquote> <p>The first searcher simply looks for a loader in the package.preload table.</p> <p>The second searcher looks for a loader as a Lua library, using the path stored at package.path. The search is done as described in function package.searchpath.</p> <p>The third searcher looks for a loader as a C library, using the path given by the variable package.cpath. Again, the search is done as described in function package.searchpath. For instance, if the C path is the string <code>"./?.so;./?.dll;/usr/local/?/init.so"</code> the searcher for module foo will try to open the files <code>./foo.so</code>, <code>./foo.dll</code>, and <code>/usr/local/foo/init.so</code>, in that order. Once it finds a C library, this searcher first uses a dynamic link facility to link the application with the library. Then it tries to find a C function inside the library to be used as the loader. The name of this C function is the string "luaopen_" concatenated with a copy of the module name where each dot is replaced by an underscore. Moreover, if the module name has a hyphen, its prefix up to (and including) the first hyphen is removed. For instance, if the module name is a.v1-b.c, the function name will be luaopen_b_c.</p> <p>The fourth searcher tries an all-in-one loader. It searches the C path for a library for the root name of the given module. For instance, when requiring a.b.c, it will search for a C library for a. If found, it looks into it for an open function for the submodule; in our example, that would be luaopen_a_b_c. With this facility, a package can pack several C submodules into one single library, with each submodule keeping its original open function.</p> </blockquote> <p>The searcher of use to us is the third one: it is used for any shared libraries (.dll or .so) which is generally how our custom C modules are built.</p> <p>Using the <em>template</em> string (the one with the question marks), the searcher will look in each of the specified paths, substituting the argument of <code>require()</code> in place of the question mark. In order to specify the path for this third searcher, one must set (or append to) <a href="https://www.lua.org/manual/5.2/manual.html#pdf-package.cpath" rel="nofollow"><code>package.cpath</code></a> and then call <code>require()</code>.</p> <p>So perhaps you have a directory structure as</p> <pre><code>- ROOT |-lua |-bin </code></pre> <p>where <code>lua</code> contains <code>script.lua</code> and <code>bin</code> contains <code>mylib.so</code></p> <p>To load <code>mylib.so</code>, you just need these two lines of code in <code>script.lua</code>:</p> <pre><code>package.cpath = '/ROOT/bin/?.so;' .. package.cpath libfuncs = require('mylib') </code></pre> <p>NOTE: Notice the semicolon. If you append (as opposed to the prepending above), make sure to lead with the semicolon on your added path. It is not there buy default. Otherwise your new path will be merged to the current default cpath, which is just <code>./?.so</code>.</p>