This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.

8.2 – C Packages

Because it is easy to interface Lua with C, it is also easy to write packages for Lua in C. Unlike packages written in Lua, however, C packages need to be loaded and linked with an application before use. In most popular systems, the easiest way to do that is with a dynamic linking facility. However, this facility is not part of the ANSI C specification; that is, there is no portable way to implement it.

Usually, Lua does not include any facility that cannot be implemented in ANSI C. However, dynamic linking is different. We can view it as the mother of all other facilities: Once we have it, we can dynamically load any other facility that is not in Lua. Therefore, in this particular case, Lua breaks its compatibility rules and implements a dynamic linking facility for several platforms, using conditional code. The standard implementation offers this support for Windows (DLL), Linux, FreeBSD, Solaris, and some other Unix implementations. It should not be difficult to extend this facility to other platforms; check your distribution. (To check it, run print(loadlib()) from the Lua prompt and see the result. If it complains about bad arguments, then you have dynamic linking facility. Otherwise, the error message indicates that this facility is not supported or not installed.)

Lua provides all the functionality of dynamic linking in a single function, called loadlib. Its has two string arguments: the complete path of the library and the name of an initialization function. So, a typical call to it looks like the next fragment:

    local path = "/usr/local/lua/lib/"
    local f = loadlib(path, "luaopen_socket")
The loadlib function loads the given library and links Lua to it. However, it does not open the library (that is, it does not call the initialization function); instead, it returns the initialization function as a Lua function, so that we can call it directly from Lua. If there is any error loading the library or finding the initialization function, loadlib returns nil plus an error message. We can improve our previous fragment so that it checks for errors and calls the initialization function:
    local path = "/usr/local/lua/lib/"
    -- or path = "C:\\windows\\luasocket.dll"
    local f = assert(loadlib(path, "luaopen_socket"))
    f()  -- actually open the library

Typically, we could expect a library distribution to include a stub file similar to that previous code fragment. Then, to install the library, we put the actual binary shared library anywhere, edit the stub to reflect the real path, and then add the stub file in a directory in our LUA_PATH. With this setting, we can use the regular require function to open the C library.