summaryrefslogtreecommitdiff
path: root/binary/all_in_one
diff options
context:
space:
mode:
Diffstat (limited to 'binary/all_in_one')
-rwxr-xr-xbinary/all_in_one442
1 files changed, 442 insertions, 0 deletions
diff --git a/binary/all_in_one b/binary/all_in_one
new file mode 100755
index 00000000..de545d04
--- /dev/null
+++ b/binary/all_in_one
@@ -0,0 +1,442 @@
1#!/usr/bin/env lua
2--[[
3
4All-in-one packager for LuaRocks
5 * by Hisham Muhammad <hisham@gobolinux.org>
6 * licensed under the same terms as Lua (MIT license).
7
8Based on:
9
10* srlua.c - Lua interpreter for self-running programs
11 * by Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
12 * 03 Nov 2014 15:31:43
13 * srlua.c is placed in the public domain.
14* bin2c.lua - converts a binary to a C string that can be embedded
15 * by Mark Edgar
16 * http://lua-users.org/wiki/BinTwoCee
17 * bin2c.lua is licensed under the same terms as Lua (MIT license).
18* lua.c - Lua stand-alone interpreter
19 * by Luiz Henrique de Figueiredo, Waldemar Celes, Roberto Ierusalimschy
20 * lua.c is licensed under the same terms as Lua (MIT license).
21* luastatic - builds a standalone executable from a Lua program
22 * by Eric R. Schulz
23 * https://github.com/ers35/luastatic
24 * luastatic is licensed under the CC0 1.0 Universal license
25
26]]
27
28local MAIN_PROGRAM = arg[1] or "src/bin/luarocks"
29local LUA_DIR = arg[2] or "/usr"
30local EXCLUDE = arg[3] or "^src/luarocks/admin/"
31local SYSCONFDIR = arg[4] or "/etc/luarocks"
32local TARGET = arg[5] or "binary-build"
33
34local LUA_MODULES = TARGET .. "/lua_modules"
35local CONFIG_DIR = TARGET .. "/.luarocks"
36
37package.path = "./src/?.lua;" .. package.path
38
39local fs = require("luarocks.fs")
40local cfg = require("luarocks.core.cfg")
41local cmd = require("luarocks.cmd")
42local deps = require("luarocks.deps")
43local util = require("luarocks.util")
44local path = require("luarocks.path")
45local manif = require("luarocks.manif")
46local queries = require("luarocks.queries")
47local persist = require("luarocks.persist")
48
49--------------------------------------------------------------------------------
50
51local function reindent_c(input)
52 local out = {}
53 local indent = 0
54 local previous_is_blank = true
55 for line in input:gmatch("([^\n]*)") do
56 line = line:match("^[ \t]*(.-)[ \t]*$")
57
58 local is_blank = (#line == 0)
59 local do_print =
60 (not is_blank) or
61 (not previous_is_blank and indent == 0)
62
63 if line:match("^[})]") then
64 indent = indent - 1
65 if indent < 0 then indent = 0 end
66 end
67 if do_print then
68 table.insert(out, string.rep(" ", indent))
69 table.insert(out, line)
70 table.insert(out, "\n")
71 end
72 if line:match("[{(]$") then
73 indent = indent + 1
74 end
75
76 previous_is_blank = is_blank
77 end
78 return table.concat(out)
79end
80
81local hexdump
82do
83 local numtab = {}
84 for i = 0, 255 do
85 numtab[string.char(i)] = ("%-3d,"):format(i)
86 end
87 function hexdump(str)
88 return (str:gsub(".", numtab):gsub(("."):rep(80), "%0\n"))
89 end
90end
91
92local c_preamble = [[
93
94#include <lua.h>
95#include <lualib.h>
96#include <lauxlib.h>
97#include <errno.h>
98#include <stdio.h>
99#include <stdlib.h>
100
101/* portable alerts, from srlua */
102#ifdef _WIN32
103#include <windows.h>
104#define alert(message) MessageBox(NULL, message, progname, MB_ICONERROR | MB_OK)
105#define getprogname() char name[MAX_PATH]; argv[0]= GetModuleFileName(NULL,name,sizeof(name)) ? name : NULL;
106#else
107#define alert(message) fprintf(stderr,"%s: %s\n", progname, message)
108#define getprogname()
109#endif
110
111static int registry_key;
112
113]]
114
115local function bin2c_file(out, filename)
116 local content = string.dump(assert(loadfile(filename)))
117 table.insert(out, ("static const unsigned char code[] = {"))
118 table.insert(out, hexdump(content))
119 table.insert(out, ("};"))
120end
121
122local function write_hardcoded_module(dir)
123
124 local system = util.popen_read("uname -s")
125 local processor = util.popen_read("uname -m")
126
127 if processor:match("i[%d]86") then
128 processor = "x86"
129 elseif processor:match("amd64") or processor:match("x86_64") then
130 processor = "x86_64"
131 elseif processor:match("Power Macintosh") then
132 processor = "powerpc"
133 end
134
135 local hardcoded = {
136 SYSTEM = system,
137 PROCESSOR = processor,
138 SYSCONFDIR = SYSCONFDIR,
139 LUA_DIR = cfg.variables.LUA_DIR,
140 LUA_BINDIR = cfg.variables.LUA_BINDIR,
141 LUA_INTERPRETER = cfg.lua_interpreter,
142 }
143
144 local name = dir .. "/luarocks/core/hardcoded.lua"
145 persist.save_as_module(name, hardcoded)
146 return name
147end
148
149local function declare_modules(out, dirs, skip)
150 skip = skip or {}
151 table.insert(out, [[
152 static void declare_modules(lua_State* L) {
153 lua_settop(L, 0); /* */
154 lua_newtable(L); /* modules */
155 lua_pushlightuserdata(L, (void*) &registry_key); /* modules registry_key */
156 lua_pushvalue(L, 1); /* modules registry_key modules */
157 lua_rawset(L, LUA_REGISTRYINDEX); /* modules */
158 ]])
159 for _, dir in ipairs(dirs) do
160 for _, name in ipairs(fs.find(dir)) do
161 local run = true
162 for _, pat in ipairs(skip) do
163 if name:match(pat) then
164 run = false
165 break
166 end
167 end
168 if run then
169 local filename = dir .. "/" .. name
170 if fs.is_file(filename) then
171 print(name)
172 local modname = name:gsub("%.lua$", ""):gsub("/", ".")
173 table.insert(out, ("/* %s */"):format(modname))
174 table.insert(out, ("{"))
175 bin2c_file(out, filename)
176 table.insert(out, ("luaL_loadbuffer(L, code, sizeof(code), %q);"):format(filename))
177 table.insert(out, ("lua_setfield(L, 1, %q);"):format(modname))
178 table.insert(out, ("}"))
179 end
180 end
181 end
182 end
183 table.insert(out, [[
184 lua_settop(L, 0); /* */
185 }
186 ]])
187end
188
189local function nm(filename)
190 local pd = io.popen("nm " .. filename)
191 local out = pd:read("*a")
192 pd:close()
193 return out
194end
195
196local function declare_libraries(out, dir)
197 local a_files = {}
198 local externs = {}
199 local fn = {}
200 table.insert(fn, [[
201 static void declare_libraries(lua_State* L) {
202 lua_getglobal(L, "package"); /* package */
203 lua_getfield(L, -1, "preload"); /* package package.preload */
204 ]])
205 for _, name in ipairs(fs.find(dir)) do
206 local filename = dir .. "/" .. name
207 if name:match("%.a$") then
208 table.insert(a_files, filename)
209 local nmout = nm(filename)
210 for luaopen in nmout:gmatch("[^dD] _?(luaopen_[%a%p%d]+)") do
211
212 -- FIXME what about module names with underscores?
213 local modname = luaopen:gsub("^_?luaopen_", ""):gsub("_", ".")
214
215 table.insert(externs, "extern int " .. luaopen .. "(lua_State* L);")
216 table.insert(fn, "lua_pushcfunction(L, " .. luaopen .. ");")
217 table.insert(fn, "lua_setfield(L, -2, \"" .. modname .. "\");")
218 end
219 end
220 end
221 local pd = io.popen("find " .. dir .. " -name '*.a'", "r")
222 for line in pd:lines() do
223 table.insert(a_files, line)
224 end
225 pd:close()
226 table.insert(fn, [[
227 lua_settop(L, 0); /* */
228 }
229 ]])
230
231 table.insert(out, "\n")
232 for _, line in ipairs(externs) do
233 table.insert(out, line)
234 end
235 table.insert(out, "\n")
236 for _, line in ipairs(fn) do
237 table.insert(out, line)
238 end
239 table.insert(out, "\n")
240
241 return a_files
242end
243
244local function load_main(out, main_program, program_name)
245 table.insert(out, [[static void load_main(lua_State* L) {]])
246 bin2c_file(out, main_program)
247 table.insert(out, ("luaL_loadbuffer(L, code, sizeof(code), %q);"):format(program_name))
248 table.insert(out, [[}]])
249 table.insert(out, [[]])
250end
251
252local c_main = [[
253
254/* custom package loader */
255static int pkg_loader(lua_State* L) {
256 lua_pushlightuserdata(L, (void*) &registry_key); /* modname ? registry_key */
257 lua_rawget(L, LUA_REGISTRYINDEX); /* modname ? modules */
258 lua_pushvalue(L, -1); /* modname ? modules modules */
259 lua_pushvalue(L, 1); /* modname ? modules modules modname */
260 lua_gettable(L, -2); /* modname ? modules mod */
261 if (lua_type(L, -1) == LUA_TNIL) {
262 lua_pop(L, 1); /* modname ? modules */
263 lua_pushvalue(L, 1); /* modname ? modules modname */
264 lua_pushliteral(L, ".init"); /* modname ? modules modname ".init" */
265 lua_concat(L, 2); /* modname ? modules modname .. ".init" */
266 lua_gettable(L, -2); /* modname ? mod */
267 }
268 return 1;
269}
270
271static void install_pkg_loader(lua_State* L) {
272 lua_settop(L, 0); /* */
273 lua_getglobal(L, "table"); /* table */
274 lua_getfield(L, -1, "insert"); /* table table.insert */
275 lua_getglobal(L, "package"); /* table table.insert package */
276 lua_getfield(L, -1, "searchers"); /* table table.insert package package.searchers */
277 if (lua_type(L, -1) == LUA_TNIL) {
278 lua_pop(L, 1);
279 lua_getfield(L, -1, "loaders"); /* table table.insert package package.loaders */
280 }
281 lua_copy(L, 4, 3); /* table table.insert package.searchers */
282 lua_settop(L, 3); /* table table.insert package.searchers */
283 lua_pushnumber(L, 1); /* table table.insert package.searchers 1 */
284 lua_pushcfunction(L, pkg_loader); /* table table.insert package.searchers 1 pkg_loader */
285 lua_call(L, 3, 0); /* table */
286 lua_settop(L, 0); /* */
287}
288
289/* main script launcher, from srlua */
290static int pmain(lua_State *L) {
291 int argc = lua_tointeger(L, 1);
292 char** argv = lua_touserdata(L, 2);
293 int i;
294 load_main(L);
295 lua_createtable(L, argc, 0);
296 for (i = 0; i < argc; i++) {
297 lua_pushstring(L, argv[i]);
298 lua_rawseti(L, -2, i);
299 }
300 lua_setglobal(L, "arg");
301 luaL_checkstack(L, argc - 1, "too many arguments to script");
302 for (i = 1; i < argc; i++) {
303 lua_pushstring(L, argv[i]);
304 }
305 lua_call(L, argc - 1, 0);
306 return 0;
307}
308
309/* fatal error, from srlua */
310static void fatal(const char* message) {
311 alert(message);
312 exit(EXIT_FAILURE);
313}
314
315/* error handler, from luac */
316static int msghandler (lua_State *L) {
317 /* is error object not a string? */
318 const char *msg = lua_tostring(L, 1);
319 if (msg == NULL) {
320 /* does it have a metamethod that produces a string */
321 if (luaL_callmeta(L, 1, "__tostring") && lua_type(L, -1) == LUA_TSTRING) {
322 /* then that is the message */
323 return 1;
324 } else {
325 msg = lua_pushfstring(L, "(error object is a %s value)", luaL_typename(L, 1));
326 }
327 }
328 /* append a standard traceback */
329 luaL_traceback(L, L, msg, 1);
330 return 1;
331}
332
333/* main function, from srlua */
334int main(int argc, char** argv) {
335 lua_State* L;
336 getprogname();
337 if (argv[0] == NULL) {
338 fatal("cannot locate this executable");
339 }
340 L = luaL_newstate();
341 if (L == NULL) {
342 fatal("not enough memory for state");
343 }
344 luaL_openlibs(L);
345 install_pkg_loader(L);
346 declare_libraries(L);
347 declare_modules(L);
348 lua_pushcfunction(L, &msghandler);
349 lua_pushcfunction(L, &pmain);
350 lua_pushinteger(L, argc);
351 lua_pushlightuserdata(L, argv);
352 if (lua_pcall(L, 2, 0, -4) != 0) {
353 fatal(lua_tostring(L, -1));
354 }
355 lua_close(L);
356 return EXIT_SUCCESS;
357}
358
359]]
360
361local function generate(main_program, dir, skip)
362 local program_name = main_program:gsub(".*/", "")
363
364 local hardcoded = write_hardcoded_module(dir)
365
366 local out = {}
367 table.insert(out, c_preamble)
368 table.insert(out, ([[static const char* progname = %q;]]):format(program_name))
369 load_main(out, main_program, program_name)
370 local lua_modules = LUA_MODULES .. "/share/lua/" .. cfg.lua_version
371 declare_modules(out, { dir, lua_modules }, skip)
372 local a_files = declare_libraries(out, LUA_MODULES .. "/lib/lua/" .. cfg.lua_version)
373 table.insert(out, c_main)
374
375 os.remove(hardcoded)
376
377 local c_filename = TARGET .. "/" .. program_name .. ".exe.c"
378 local fd = io.open(c_filename, "w")
379 fd:write(reindent_c(table.concat(out, "\n")))
380 fd:close()
381
382 cmd = table.concat({
383 "gcc", "-o", TARGET .. "/" .. program_name .. ".exe",
384 "-I", cfg.variables.LUA_INCDIR,
385 "-rdynamic",
386 "-Os",
387 c_filename,
388 "-L", cfg.variables.LUA_LIBDIR,
389 table.concat(a_files, " "),
390 cfg.variables.LUA_LIBDIR .. "/" .. cfg.variables.LUALIB:gsub("%.so.*$", ".a"),
391 "-ldl", "-lm"}, " ")
392 print(cmd)
393 os.execute(cmd)
394end
395
396--------------------------------------------------------------------------------
397
398local function main()
399
400 cfg.init(cmd.find_lua(LUA_DIR))
401 fs.init()
402 deps.check_lua(cfg.variables)
403 path.use_tree("./" .. LUA_MODULES)
404
405 local CONFIG_FILE = CONFIG_DIR .. "/config-" .. cfg.lua_version .. ".lua"
406
407 fs.make_dir(CONFIG_DIR)
408 local fd = io.open(CONFIG_FILE, "w")
409 fd:write([[
410 lib_extension = "a"
411 external_lib_extension = "a"
412 variables = {
413 CC = "]] .. fs.current_dir() .. [[/static-gcc",
414 LD = "]] .. fs.current_dir() .. [[/static-gcc",
415 LIB_EXTENSION = "a",
416 LIBFLAG = "-static",
417 }
418 ]])
419 fd:close()
420
421 local dependencies = {
422 md5 = "md5",
423 luazip = "luazip",
424 luasec = "./luasec-0.7alpha-2.rockspec",
425 luaposix = "./luaposix-34.0.4-1.rockspec",
426 luasocket = "luasocket",
427 ["lua-zlib"] = "lua-zlib",
428 luafilesystem = "luafilesystem",
429 }
430
431 fs.make_dir(LUA_MODULES)
432 for name, arg in pairs(dependencies) do
433 local vers = manif.get_versions(queries.from_dep_string(name), "one")
434 if not next(vers) then
435 os.execute("LUAROCKS_CONFIG='" .. CONFIG_FILE .. "' ./luarocks install '--tree=" .. LUA_MODULES .. "' " .. arg)
436 end
437 end
438
439 generate(MAIN_PROGRAM, "src", { EXCLUDE, "^bin/?" })
440end
441
442main()