{"id":11,"date":"2011-05-16T20:15:53","date_gmt":"2011-05-17T01:15:53","guid":{"rendered":"http:\/\/www.playwithlua.com\/?p=11"},"modified":"2020-05-22T13:19:12","modified_gmt":"2020-05-22T18:19:12","slug":"convenient-lua-features-package-preload","status":"publish","type":"post","link":"http:\/\/www.playwithlua.com\/?p=11","title":{"rendered":"Convenient Lua Features: package.preload"},"content":{"rendered":"<p>Lua is designed for embedding into larger host programs. Last time I talked about how to make C functions available to Lua, now I want to talk about how to bundle Lua libraries in with your host program.<\/p>\n<p>First, we have to understand what it means to load a library. Most Lua libraries are packaged into modules (which I&#8217;ll get into later), one module per file. You call <code>require<\/code> and pass it a module name, and it returns the module (usually as a table containing some functions).<\/p>\n<p>Notably, you&#8217;re not passing a file name to <code>require<\/code>, you&#8217;re passing a module name. The fact that these modules map to files is just sort of coincidence. In actuality, <code>require<\/code> looks in several different places (locations on <code>package.path<\/code>, C libraries on <code>package.cpath<\/code>, and so on) for a function that will evaluate to the module.<\/p>\n<p>A function that evaluates to a module is called a <em>loader<\/em>. <em>Searchers<\/em> try to find loaders, so there&#8217;s a searcher that looks in files and returns functions that call <code>dofile<\/code> on them, for example. Each searcher that Lua uses is stored in the confusingly-named <code>package.loaders<\/code>, so one way to find this would be to add a searcher that will look for a particularly-named function (exposed from C) and call it, like if I try to load &#8220;foo&#8221; that means try to call &#8220;<code>load_foo_from_c()<\/code>&#8220;.<\/p>\n<p>But, even before it starts calling searchers, it checks if you&#8217;ve provided a loader for that module by hand. You can do that by putting it in a table, <code>package.preload<\/code>. If you only want one module this is much easier to do.<\/p>\n<p><!--more-->Let&#8217;s say you have a module, Penlight, in pl.lua. You want to embed this in your app. So, you store it in your binary as a string, and provide a C function that returns the string (actually you&#8217;d use some kind of data file, but I&#8217;m keeping this simple). The first place it&#8217;ll look for the loader is <code>package.preload['pl']<\/code>, so put this there:<\/p>\n\n<div class=\"my_syntax_box\"><div class=\"my_syntax\"><div class=\"code\"><pre class=\"lua\" style=\"font-family:monospace;\">package<span style=\"color: #66cc66;\">.<\/span>preload<span style=\"color: #66cc66;\">&#91;<\/span><span style=\"color: #ff6666;\">'pl'<\/span><span style=\"color: #66cc66;\">&#93;<\/span> <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #aa9900; font-weight: bold;\">function<\/span><span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n    <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> str <span style=\"color: #66cc66;\">=<\/span> load_pl_from_c<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n    <span style=\"color: #aa9900; font-weight: bold;\">local<\/span> fn <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #0000aa;\">loadstring<\/span><span style=\"color: #66cc66;\">&#40;<\/span>str<span style=\"color: #66cc66;\">&#41;<\/span>\n    <span style=\"color: #aa9900; font-weight: bold;\">return<\/span> fn<span style=\"color: #66cc66;\">&#40;<\/span><span style=\"color: #66cc66;\">&#41;<\/span>\n<span style=\"color: #aa9900; font-weight: bold;\">end<\/span><\/pre><\/div><\/div><\/div>\n\n<p>Now, when you call <code>require 'pl'<\/code> it will execute this function, read the text of the pl library from wherever the host stored it, and run it. And, if you&#8217;re testing your script outside the host program, it will still work; just don&#8217;t add anything to preload and it will just read the file from the path.<\/p>\n<p>It&#8217;s easy to see how you could build a whole package system with this: byte-compile the files first and run them through zlib, put them all in a data file, since <code>package.preload<\/code> is a table that means you can put a metatable on it, etc. One idea I had was to tie this to curl and have it load packages from a repository over http.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Lua is designed for embedding into larger host programs. Last time I talked about how to make C functions available to Lua, now I want to talk about how to bundle Lua libraries in with your host program. First, we have to understand what it means to load a library. Most Lua libraries are packaged [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts\/11"}],"collection":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=11"}],"version-history":[{"count":0,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=\/wp\/v2\/posts\/11\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=11"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=11"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.playwithlua.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=11"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}