Refactored e to Event
[twcon.git] / configure.lua
blobb96c629d5d16b0292ff2c19e2134f1a2f37259f5
2 --[[@GROUP Configuration@END]]--
4 --[[@FUNCTION
5 TODO
6 @END]]--
7 function NewConfig(on_configured_callback)
8 local config = {}
10 config.OnConfigured = function(self)
11 return true
12 end
14 if on_configured_callback then config.OnConfigured = on_configured_callback end
16 config.options = {}
17 config.settings = NewSettings()
19 config.NewSettings = function(self)
20 local s = NewSettings()
21 for _,v in pairs(self.options) do
22 v:Apply(s)
23 end
24 return s
25 end
27 config.Add = function(self, o)
28 table.insert(self.options, o)
29 self[o.name] = o
30 end
32 config.Print = function(self)
33 for k,v in pairs(self.options) do
34 print(v:FormatDisplay())
35 end
36 end
38 config.Save = function(self, filename)
39 print("saved configuration to '"..filename.."'")
40 local file = io.open(filename, "w")
42 -- Define a little helper function to save options
43 local saver = {}
44 saver.file = file
46 saver.line = function(self, str)
47 self.file:write(str .. "\n")
48 end
50 saver.option = function(self, option, name)
51 local valuestr = "no"
52 if type(option[name]) == type(0) then
53 valuestr = option[name]
54 elseif type(option[name]) == type(true) then
55 valuestr = "false"
56 if option[name] then
57 valuestr = "true"
58 end
59 elseif type(option[name]) == type("") then
60 valuestr = "'"..option[name].."'"
61 else
62 error("option "..name.." have a value of type ".. type(option[name]).." that can't be saved")
63 end
64 self.file:write(option.name.."."..name.." = ".. valuestr.."\n")
65 end
67 -- Save all the options
68 for k,v in pairs(self.options) do
69 v:Save(saver)
70 end
71 file:close()
72 end
74 config.Load = function(self, filename)
75 local options_func = loadfile(filename)
76 local options_table = {}
78 if not options_func then
79 print("auto configuration")
80 self:Config(filename)
81 options_func = loadfile(filename)
82 end
84 if options_func then
85 -- Setup the options tables
86 for k,v in pairs(self.options) do
87 options_table[v.name] = {}
88 end
89 setfenv(options_func, options_table)
91 -- this is to make sure that we get nice error messages when
92 -- someone sets an option that isn't valid.
93 local mt = {}
94 mt.__index = function(t, key)
95 local v = rawget(t, key)
96 if v ~= nil then return v end
97 error("there is no configuration option named '" .. key .. "'")
98 end
100 setmetatable(options_table, mt)
102 -- Process the options
103 options_func()
105 -- Copy the options
106 for k,v in pairs(self.options) do
107 if options_table[v.name] then
108 for k2,v2 in pairs(options_table[v.name]) do
109 v[k2] = v2
111 v.auto_detected = false
114 else
115 print("error: no '"..filename.."' found")
116 print("")
117 print("run 'bam config' to generate")
118 print("run 'bam config help' for configuration options")
119 print("")
120 os.exit(1)
124 config.Config = function(self, filename)
125 print("")
126 print("configuration:")
127 if _bam_targets[1] == "print" then
128 self:Load(filename)
129 self:Print()
130 print("")
131 print("notes:")
132 self:OnConfigured()
133 print("")
134 else
135 self:Autodetect()
136 print("")
137 print("notes:")
138 if self:OnConfigured() then
139 self:Save(filename)
141 print("")
146 config.Autodetect = function(self)
147 for k,v in pairs(self.options) do
148 v:Check(self.settings)
149 print(v:FormatDisplay())
150 self[v.name] = v
154 config.PrintHelp = function(self)
155 print("options:")
156 for k,v in pairs(self.options) do
157 if v.PrintHelp then
158 v:PrintHelp()
163 config.Finalize = function(self, filename)
164 if _bam_targets[0] == "config" then
165 if _bam_targets[1] == "help" then
166 self:PrintHelp()
167 os.exit(0)
170 self:Config(filename)
172 os.exit(0)
175 self:Load(filename)
176 bam_update_globalstamp(filename)
179 return config
183 -- Helper functions --------------------------------------
184 function DefaultOptionDisplay(option)
185 if not option.value then return "no" end
186 if option.value == 1 or option.value == true then return "yes" end
187 return option.value
190 function IsNegativeTerm(s)
191 if s == "no" then return true end
192 if s == "false" then return true end
193 if s == "off" then return true end
194 if s == "disable" then return true end
195 if s == "0" then return true end
196 return false
199 function IsPositiveTerm(s)
200 if s == "yes" then return true end
201 if s == "true" then return true end
202 if s == "on" then return true end
203 if s == "enable" then return true end
204 if s == "1" then return true end
205 return false
208 function MakeOption(name, value, check, save, display, printhelp)
209 local o = {}
210 o.name = name
211 o.value = value
212 o.Check = check
213 o.Save = save
214 o.auto_detected = true
215 o.FormatDisplay = function(self)
216 local a = "SET"
217 if self.auto_detected then a = "AUTO" end
218 return string.format("%-5s %-20s %s", a, self.name, self:Display())
221 o.Display = display
222 o.PrintHelp = printhelp
223 if o.Display == nil then o.Display = DefaultOptionDisplay end
224 return o
228 -- Test Compile C --------------------------------------
229 function OptTestCompileC(name, source, compileoptions, desc)
230 local check = function(option, settings)
231 option.value = false
232 if ScriptArgs[option.name] then
233 if IsNegativeTerm(ScriptArgs[option.name]) then
234 option.value = false
235 elseif IsPositiveTerm(ScriptArgs[option.name]) then
236 option.value = true
237 else
238 error(ScriptArgs[option.name].." is not a valid value for option "..option.name)
240 option.auto_detected = false
241 else
242 if CTestCompile(settings, option.source, option.compileoptions) then
243 option.value = true
248 local save = function(option, output)
249 output:option(option, "value")
252 local printhelp = function(option)
253 print("\t"..option.name.."=on|off")
254 if option.desc then print("\t\t"..option.desc) end
257 local o = MakeOption(name, false, check, save, nil, printhelp)
258 o.desc = desc
259 o.source = source
260 o.compileoptions = compileoptions
261 return o
265 -- OptToggle --------------------------------------
266 function OptToggle(name, default_value, desc)
267 local check = function(option, settings)
268 if ScriptArgs[option.name] then
269 if IsNegativeTerm(ScriptArgs[option.name]) then
270 option.value = false
271 elseif IsPositiveTerm(ScriptArgs[option.name]) then
272 option.value = true
273 else
274 error(ScriptArgs[option.name].." is not a valid value for option "..option.name)
279 local save = function(option, output)
280 output:option(option, "value")
283 local printhelp = function(option)
284 print("\t"..option.name.."=on|off")
285 if option.desc then print("\t\t"..option.desc) end
288 local o = MakeOption(name, default_value, check, save, nil, printhelp)
289 o.desc = desc
290 return o
293 -- OptInteger --------------------------------------
294 function OptInteger(name, default_value, desc)
295 local check = function(option, settings)
296 if ScriptArgs[option.name] then
297 option.value = tonumber(ScriptArgs[option.name])
301 local save = function(option, output)
302 output:option(option, "value")
305 local printhelp = function(option)
306 print("\t"..option.name.."=N")
307 if option.desc then print("\t\t"..option.desc) end
310 local o = MakeOption(name, default_value, check, save, nil, printhelp)
311 o.desc = desc
312 return o
316 -- OptString --------------------------------------
317 function OptString(name, default_value, desc)
318 local check = function(option, settings)
319 if ScriptArgs[option.name] then
320 option.value = ScriptArgs[option.name]
324 local save = function(option, output)
325 output:option(option, "value")
328 local printhelp = function(option)
329 print("\t"..option.name.."=STRING")
330 if option.desc then print("\t\t"..option.desc) end
333 local o = MakeOption(name, default_value, check, save, nil, printhelp)
334 o.desc = desc
335 return o
338 -- Find Compiler --------------------------------------
339 --[[@FUNCTION
340 TODO
341 @END]]--
342 function OptCCompiler(name, default_driver, default_c, default_cxx, desc)
343 local check = function(option, settings)
344 if ScriptArgs[option.name] then
345 -- set compile driver
346 option.driver = ScriptArgs[option.name]
348 -- set c compiler
349 if ScriptArgs[option.name..".c"] then
350 option.c_compiler = ScriptArgs[option.name..".c"]
353 -- set c+= compiler
354 if ScriptArgs[option.name..".cxx"] then
355 option.cxx_compiler = ScriptArgs[option.name..".cxx"]
358 option.auto_detected = false
359 elseif option.driver then
360 -- no need todo anything if we have a driver
361 -- TODO: test if we can find the compiler
362 else
363 if ExecuteSilent("cl") == 0 then
364 option.driver = "cl"
365 elseif ExecuteSilent("g++ -v") == 0 then
366 option.driver = "gcc"
367 else
368 error("no c/c++ compiler found")
371 --setup_compiler(option.value)
374 local apply = function(option, settings)
375 if option.driver == "cl" then
376 SetDriversCL(settings)
377 elseif option.driver == "gcc" then
378 SetDriversGCC(settings)
379 else
380 error(option.driver.." is not a known c/c++ compile driver")
383 if option.c_compiler then settings.cc.c_compiler = option.c_compiler end
384 if option.cxx_compiler then settings.cc.cxx_compiler = option.cxx_compiler end
387 local save = function(option, output)
388 output:option(option, "driver")
389 output:option(option, "c_compiler")
390 output:option(option, "cxx_compiler")
393 local printhelp = function(option)
394 local a = ""
395 if option.desc then a = "for "..option.desc end
396 print("\t"..option.name.."=gcc|cl")
397 print("\t\twhat c/c++ compile driver to use"..a)
398 print("\t"..option.name..".c=FILENAME")
399 print("\t\twhat c compiler executable to use"..a)
400 print("\t"..option.name..".cxx=FILENAME")
401 print("\t\twhat c++ compiler executable to use"..a)
404 local display = function(option)
405 local s = option.driver
406 if option.c_compiler then s = s .. " c="..option.c_compiler end
407 if option.cxx_compiler then s = s .. " cxx="..option.cxx_compiler end
408 return s
411 local o = MakeOption(name, nil, check, save, display, printhelp)
412 o.desc = desc
413 o.driver = false
414 o.c_compiler = false
415 o.cxx_compiler = false
417 if default_driver then o.driver = default_driver end
418 if default_c then o.c_compiler = default_c end
419 if default_cxx then o.cxx_compiler = default_cxx end
421 o.Apply = apply
422 return o
425 -- Option Library --------------------------------------
426 --[[@FUNCTION
427 TODO
428 @END]]--
429 function OptLibrary(name, header, desc)
430 local check = function(option, settings)
431 option.value = false
432 option.include_path = false
434 local function check_compile_include(filename, paths)
435 if CTestCompile(settings, "#include <" .. filename .. ">\nint main(){return 0;}", "") then
436 return ""
439 for k,v in pairs(paths) do
440 if CTestCompile(settings, "#include <" .. filename .. ">\nint main(){return 0;}", "-I"..v) then
441 return v
445 return false
448 if ScriptArgs[option.name] then
449 if IsNegativeTerm(ScriptArgs[option.name]) then
450 option.value = false
451 elseif ScriptArgs[option.name] == "system" then
452 option.value = true
453 else
454 option.value = true
455 option.include_path = ScriptArgs[option.name]
457 option.auto_detected = false
458 else
459 option.include_path = check_compile_include(option.header, {})
460 if option.include_path == false then
461 if option.required then
462 print(name.." library not found and is required")
463 error("required library not found")
465 else
466 option.value = true
467 option.include_path = false
472 local save = function(option, output)
473 output:option(option, "value")
474 output:option(option, "include_path")
477 local display = function(option)
478 if option.value then
479 if option.include_path then
480 return option.include_path
481 else
482 return "(in system path)"
484 else
485 return "not found"
489 local printhelp = function(option)
490 print("\t"..option.name.."=disable|system|PATH")
491 if option.desc then print("\t\t"..option.desc) end
494 local o = MakeOption(name, false, check, save, display, printhelp)
495 o.include_path = false
496 o.header = header
497 o.desc = desc
498 return o