-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathlakefile
473 lines (416 loc) · 13.7 KB
/
lakefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
----------------------
-- LuaBuild
-- A highly-configurable Lua 5.2 builder with options to build as
-- executable, shared library/DLL or srlua stub (for both GCC and MSVC)
-- Frequently-used modules may be statically linked into the result;
-- you may exclude standard Lua modules as well.
-- For instance, a static.modules file like this
-- include = 'lfs'
-- exclude = 'debug'
-- will statically link in LuaFileSystem and exclude the standard debug module.
local lfs = require 'lfs'
local append,join,exists = table.insert,path.join,path.exists
-- for our purposes, the distinction is between Lua 5.1 and 5.2, 5.3
local lua52 = not _VERSION:match '5.1'
local quote = path.quote
local build53 = (LUA53 or os.getenv'LUA53') ~= nil
if not build53 then
SRC_DIR = "lua-5.2.2"
VERSION = "5.2"
else
print 'building Lua 5.3.0'
SRC_DIR = "lua-5.3.0/src"
VERSION = "5.3"
end
local load_config
local function load_config (src, env, dont_quit)
local str,err = file.read(src)
if not str then
if dont_quit then return nil,err end
quit (err)
end
local chunk,err
env = env or {}
if not lua52 then
chunk,err = loadstring(str,src)
if not chunk then quit(err) end
setfenv(chunk,env)
else
chunk,err = load(str,src,'t',env)
if not chunk then quit(err) end
end
if not pcall(chunk) then quit(err) end
return env
end
local function remove_targets(r)
for t in list(r.targets) do
utils.remove(t.target)
end
end
local function split (str)
if str then
return utils.split_list(str)
else
return {}
end
end
local function global_name (s) return s:match '^[%u%d_]+$' ~= nil end
local function read_config_file (name,dont_quit)
-- global _variables_ may be read in configuration files
local env = setmetatable({},{
__index = function(self,key)
if global_name(key) then return _G[key]
else quit("config: not defined "..key)
end
end
})
load_config (name,env,dont_quit)
setmetatable(env,nil)
return env
end
local function write_config_file (name,tbl)
local f = io.open(name,'w')
for k,v in pairs(tbl) do
if type(v) == 'string' then
v = '"'..v..'"'
else
v = tostring(v)
end
f:write(('%s = %s\n'):format(k,v))
end
f:close()
end
SRC = SRC_DIR..DIRSEP
PWD = lfs.currentdir()..DIRSEP
LIBDIR = PWD..'lib'..DIRSEP..VERSION..DIRSEP
BINDIR = PWD..'bin'..DIRSEP
MODDIR = PWD..'lua'..DIRSEP
LUADIR = PWD..SRC
LUALIB = LIBDIR.."lua"..VERSION
CORE = [[ lapi lcode lctype ldebug ldump lfunc lgc llex
lmem lobject lopcodes lparser lstate lstring ltable
ltm lundump lvm lzio
]]
LDO = 'ldo'
LIB = [[ lauxlib lbaselib lbitlib lcorolib ldblib liolib
lmathlib loslib lstrlib ltablib linit
]]
if build53 then
LIB = LIB..' lutf8lib'
end
LOADLIB = 'loadlib'
-- the standard Lua modules and their implementation files
LIBNAMES = {
bit32 = 'lbitlib',
coroutine = 'lcorolib',
io = 'liolib',
math = 'lmathlib',
package = 'loadlib',
os = 'loslib',
string = 'lstrlib',
table = 'ltablib',
debug = 'ldblib',
}
if build53 then
LIBNAMES.utf8 = 'lutf8lib'
LIBNAMES.bit32 = nil
end
-- read the manifest of available static modules and the configuration file
local menv = {}
menv.M = menv
local xmodules = load_config ('modules/manifest',menv)
local current_modules = 'current_modules'
local old_config = read_config_file (current_modules,true)
local config_file = CONFIG or 'default.config'
local config = read_config_file(config_file)
-- some defaults
if config.build_shared == nil then config.build_shared = false end
config.name = config.name or 'lua'
if config.readline == nil then config.readline = false end
-- we'll check this on the next run
write_config_file(current_modules,config)
-- any upper-case variables in the config are made global,
-- so for instance you can set PREFIX, DEBUG or CC
-- (but you do have to tell Lake about this possible configuration change)
local globs = {}
for k,v in pairs(config) do
if global_name(k) then globs[k] = v end
end
if next(globs) then lake.set_flags(globs) end
-- what modules must we include or exclude?
local mods = split(config.include)
local ex = split(config.exclude)
for mod in list(mods) do
if not xmodules[mod] then quit(mod.." is not available in Luabuild") end
if mod == 'linenoise' then -- core has implicit dependency on linenoise
config.readline = 'linenoise'
end
end
local excludes = {}
for i,mod in ipairs(ex) do
if not LIBNAMES[mod] then quit(mod.." is not a built-in Lua library") end
excludes[i] = LIBNAMES[mod]
LIBNAMES[mod] = nil -- don't register these chaps
end
local linit_c, linit_c_template = SRC..'linit.c', SRC..'linit.c.in'
-- add our modules to linit.c
target(linit_c,{linit_c_template},function()
-- included external static modules
local dcls, reg = {},{}
if not config.build_shared then
for mod in list(mods) do
-- modules may be dotted, which is converted according to the Lua convention
local name = 'luaopen_'..mod:gsub('%.','_')
append(dcls,'int '..name..'(lua_State *L);')
append(reg,'{"'..mod..'",'..name..'},')
end
end
-- excluded standard modules
local lualibs = {}
for lname in pairs(LIBNAMES) do
append(lualibs,('{"%s",luaopen_%s},'):format(lname,lname))
end
local vars = {}
vars.DECLARATIONS = table.concat(dcls,'\n')
vars.REGISTER_EXTERNAL = table.concat(reg,'\n')
vars.REGISTER_INTERNAL = table.concat(lualibs,'\n')
print 'creating linit.c ...'
local tmpl = file.read (linit_c_template)
file.write(linit_c,utils.substitute(tmpl,vars))
end)
if old_config.include~=config.include or old_config.exclude~=config.exclude
or old_config.build_shared~=config.build_shared
then
utils.remove(linit_c)
end
-- configuring Lua for this platform. By default, we link in readline
-- for non-Windows targets unless config.readline is false.
local needs = 'math '
-- xdefs defines for loadlib.c
-- ldefs defines for lua.c
-- defs defines for the rest of Lua
local compat = config.no_lua51_compat and '' or 'LUA_COMPAT_ALL '
local defs, xdefs, ldefs
if not WINDOWS then
if not config.no_dlink then
needs = needs .. ' dl '
end
if PLAT == 'Linux' or PLAT == 'FreeBSD' then
defs = 'LUA_USE_LINUX'
elseif PLAT == 'Darwin' then
defs = 'LUA_USE_MACOSX'
else
defs = 'LUA_USE_POSIX'
end
defs = compat..defs
if config.readline then
if config.readline == true then
needs = needs..' readline '
ldefs = defs
elseif config.readline == 'linenoise' then
ldefs = compat..'LUA_USE_LINENOISE LUA_USE_ISATTY'
else
quit("readline can either be true or 'linenoise'")
end
else
-- hack: only Lua feature macro used in lua.c
ldefs = compat..'LUA_USE_ISATTY'
end
else
if config.dll then -- ensure that Lua API is exported
defs = compat..'LUA_BUILD_AS_DLL'
else
defs = compat
end
ldefs = defs
end
-- To patch a custom module path, we need only modify luaconf.h for loadlib.c.
-- So the library build is partioned into two groups.
if config.custom_lua_path or config.no_dlink then
if config.custom_lua_path then
local path = config.custom_lua_path
path = path == true and PWD or path
-- to get our path properly converted to a string in luaconf.h
path = path:gsub('\\','\\\\')
xdefs = defs..' '..'LUA_CUSTOM_DIR='..quote(path)
else
xdefs = compat
end
else
xdefs = defs
end
local libs
local def = {base=SRC,dynamic=config.dynamic}
-- gcc 4.6 messes up setjmp/longjmp when optimizing
local ldo = c.group{LDO,defines=defs,args=def,
flags=choose(CC=='gcc','-fno-omit-frame-pointer')
}
-- treat loadib.c specially, since we want to use different flags
local loadlib = c.group{LOADLIB,defines=xdefs,args=def}
-- if these changed, then recompile loadlib.c
if config.custom_lua_path ~= old_config.custom_lua_path
and config.no_dlink ~= old_config.no_dlink
then
remove_targets(loadlib)
end
local luacore = c.group{'core',src=CORE..LIB,exclude=excludes,defines=defs,args=def}
-- build the static Lua library, excluding any unneeded built-in modules;
-- the linked result will inherit any link-time needs...
local lualib,ll = c.library{LUALIB,
inputs = {loadlib,luacore,ldo},needs=needs
}
local modules_tested, current_module, tests = {}
-- create targets for building the modules statically or dynamically
function generate_module_targets(shared)
local modules = {}
tests = io.open(config.name..'.tests','w')
-- an unfortunate global necessity for any .lake files
ARGS = {incdir=quote(LUADIR)}
if shared then -- we link these DLLs against Lua
ARGS.dll = true
ARGS.dynamic = config.dynamic
if shared ~= true then ARGS.deps = {shared} end
modules[1] = loadlib
else
modules[1] = lualib
end
for i,mod in ipairs(mods) do
local moddir, lmod = xmodules[mod]
if BUILD_PLAT=='Windows' then
moddir = moddir:gsub('/','\\')
end
ARGS.base = join("modules",moddir)
current_module = mod
-- this is only needed for MSVC where there's no .def file for a project
if shared then ARGS.llua = mod end
-- a module may have its own special lakefile
local lakefile = join('modules',mod..'.lake')
if exists(lakefile) then
if _DEBUG then dofile(lakefile)
else
ok,lmod = pcall(dofile,lakefile)
if not ok then quit(lakefile..": "..lmod) end
end
else -- we assume it's a single C file with the same name
lmod = c.library {LIBDIR..mod,src=mod,args=ARGS}
-- implicitly provide tests with a test.lua ...
if not modules_tested[current_module] and exists(join(ARGS.base,'test.lua')) then
luabuild.test 'test.lua'
end
end
append(modules,lmod)
end
tests:close()
return modules
end
luabuild = { config = config }
local targets = {}
function luabuild.lua (files,subd)
subd = subd or ''
local g = file.group{ext='.lua',base=ARGS.base,src=files,odir=join(MODDIR,subd)}
append(targets,g)
end
function luabuild.test (file)
local base, tname, deps = path.abs(ARGS.base)
file = join(base,file)
tname = path.abs("test",config.name..'-'..current_module)..'.output'
if config.build_shared then
deps = LIBDIR..current_module:gsub('%.',DIRSEP)..DLL_EXT
else
deps = BINDIR..config.name..EXE_EXT
end
tests:write(current_module,'\t',file,'\t',tname,'\t',deps,'\n')
end
function luabuild.library (spec)
local lang = spec.lang or 'c'
if spec.incdir then -- ensure we can find Lua headers as well
local incdir = spec.incdir
incdir = type(incdir)=='table' and incdir or split(incdir)
for i,dir in ipairs(incdir) do
if dir == '.' then
incdir[i] = path.abs(ARGS.base)
end
incdir[i] = quote(incdir[i])
end
table.insert(incdir,1,quote(LUADIR))
spec.incdir = incdir
end
spec.lang = nil
spec[1] = LIBDIR..spec[1]
spec.odir = VERSION
spec.args = ARGS
return _G[lang].library(spec)
end
function luabuild.write_config_header(file,cfg)
if not file:match '[/\\]' then
file = SRC..'/'..file
end
if not path.exists(file) then
local f = io.open(file,'w')
for flag, value in pairs(cfg) do
if value then
f:write('#define ',flag,' ',type(value)=='string' and '"'..value..'"' or '1','\n')
end
end
f:close()
end
end
-- build the executables and shared libraries
if not config.build_shared then -- build our modules as static libs
libs = generate_module_targets()
else
libs = {lualib}
end
if config.dll then -- generate a DLL/so
table.remove(libs,1)
local dll = c.shared {BINDIR..config.dll,rules=ll,deps=libs,dynamic=config.dynamic}
append(targets, dll)
if config.build_shared then
-- build our modules as DLLs linked against the Lua DLL
local cmods = target.shared(generate_module_targets(dll))
append(targets, cmods)
end
libs = {dll} --> the Lua exe will link against this DLL
end
local name,source,base,export,incdir,xlibs
if not config.srlua then
-- regular Lua executable
name = config.name
source = 'lua'
base = SRC
if not WINDOWS then
export = true
end
else -- we're building a srlua stub executable and bin/glue!
name = join('srluab',config.srlua)
source = 'srlua'
base = 'srlua'
incdir = LUADIR
local glue = c.program{BINDIR..'glue',src='srlua/glue'}
append(targets, glue)
if WINDOWS and CC == 'cl' then -- mingw links against this by default
xlibs = 'user32'
end
end
if config.readline == 'linenoise' and not WINDOWS then
local linenoise = c.library {LIBDIR..'linenoiselib',src='linenoise',base='linenoise'}
append(libs,linenoise)
--~ local noisedir = '../linenoise'
--~ if build53 then
--~ noisedir = '../'..noisedir
--~ end
incdir = (incdir or '')..' ./linenoise'
end
local prog,llua = c.program{BINDIR..name,
src=source,deps=libs,defines=ldefs,libs=xlibs,
base=base,export=export,dynamic=config.dynamic,incdir=incdir
}
append(targets, prog)
if config.readline ~= old_config.readline then
remove_targets(llua)
end
if export and config.build_shared then -- usually Unix case; cd be done for Windows...
local cmods = target.shared(generate_module_targets(true))
append(targets, cmods)
end
default (targets)