diff options
Diffstat (limited to 'configure.lua')
| -rw-r--r-- | configure.lua | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/configure.lua b/configure.lua new file mode 100644 index 00000000..9df4b82d --- /dev/null +++ b/configure.lua @@ -0,0 +1,489 @@ + +--[[@GROUP Configuration@END]]-- + +--[[@FUNCTION + TODO +@END]]-- +function NewConfig(on_configured_callback) + local config = {} + + config.OnConfigured = function(self) + return true + end + + if on_configured_callback then config.OnConfigured = on_configured_callback end + + config.options = {} + config.settings = NewSettings() + + config.NewSettings = function(self) + local s = NewSettings() + for _,v in pairs(self.options) do + v:Apply(s) + end + return s + end + + config.Add = function(self, o) + table.insert(self.options, o) + self[o.name] = o + end + + config.Print = function(self) + for k,v in pairs(self.options) do + print(v:FormatDisplay()) + end + end + + config.Save = function(self, filename) + print("saved configuration to '"..filename.."'") + local file = io.open(filename, "w") + + -- Define a little helper function to save options + local saver = {} + saver.file = file + + saver.line = function(self, str) + self.file:write(str .. "\n") + end + + saver.option = function(self, option, name) + local valuestr = "no" + if type(option[name]) == type(0) then + valuestr = option[name] + elseif type(option[name]) == type(true) then + valuestr = "false" + if option[name] then + valuestr = "true" + end + elseif type(option[name]) == type("") then + valuestr = "'"..option[name].."'" + else + error("option "..name.." have a value of type ".. type(option[name]).." that can't be saved") + end + self.file:write(option.name.."."..name.." = ".. valuestr.."\n") + end + + -- Save all the options + for k,v in pairs(self.options) do + v:Save(saver) + end + file:close() + end + + config.Load = function(self, filename) + local options_func = loadfile(filename) + local options_table = {} + + if options_func then + -- Setup the options tables + for k,v in pairs(self.options) do + options_table[v.name] = {} + end + setfenv(options_func, options_table) + + -- this is to make sure that we get nice error messages when + -- someone sets an option that isn't valid. + local mt = {} + mt.__index = function(t, key) + local v = rawget(t, key) + if v ~= nil then return v end + error("there is no configuration option named '" .. key .. "'") + end + + setmetatable(options_table, mt) + + -- Process the options + options_func() + + -- Copy the options + for k,v in pairs(self.options) do + if options_table[v.name] then + for k2,v2 in pairs(options_table[v.name]) do + v[k2] = v2 + end + v.auto_detected = false + end + end + else + print("error: no '"..filename.."' found") + print("") + print("run 'bam config' to generate") + print("run 'bam config help' for configuration options") + print("") + os.exit(1) + end + end + + config.Autodetect = function(self) + for k,v in pairs(self.options) do + v:Check(self.settings) + print(v:FormatDisplay()) + self[v.name] = v + end + end + + config.PrintHelp = function(self) + print("options:") + for k,v in pairs(self.options) do + if v.PrintHelp then + v:PrintHelp() + end + end + end + + config.Finalize = function(self, filename) + if _bam_targets[0] == "config" then + if _bam_targets[1] == "help" then + self:PrintHelp() + os.exit(0) + end + + print("") + print("configuration:") + if _bam_targets[1] == "print" then + self:Load(filename) + self:Print() + print("") + print("notes:") + self:OnConfigured() + print("") + else + self:Autodetect() + print("") + print("notes:") + if self:OnConfigured() then + self:Save(filename) + end + print("") + end + + os.exit(0) + end + + self:Load(filename) + bam_update_globalstamp(filename) + end + + return config +end + + +-- Helper functions -------------------------------------- +function DefaultOptionDisplay(option) + if not option.value then return "no" end + if option.value == 1 or option.value == true then return "yes" end + return option.value +end + +function IsNegativeTerm(s) + if s == "no" then return true end + if s == "false" then return true end + if s == "off" then return true end + if s == "disable" then return true end + if s == "0" then return true end + return false +end + +function IsPositiveTerm(s) + if s == "yes" then return true end + if s == "true" then return true end + if s == "on" then return true end + if s == "enable" then return true end + if s == "1" then return true end + return false +end + +function MakeOption(name, value, check, save, display, printhelp) + local o = {} + o.name = name + o.value = value + o.Check = check + o.Save = save + o.auto_detected = true + o.FormatDisplay = function(self) + local a = "SET" + if self.auto_detected then a = "AUTO" end + return string.format("%-5s %-20s %s", a, self.name, self:Display()) + end + + o.Display = display + o.PrintHelp = printhelp + if o.Display == nil then o.Display = DefaultOptionDisplay end + return o +end + + +-- Test Compile C -------------------------------------- +function OptTestCompileC(name, source, compileoptions, desc) + local check = function(option, settings) + option.value = false + if ScriptArgs[option.name] then + if IsNegativeTerm(ScriptArgs[option.name]) then + option.value = false + elseif IsPositiveTerm(ScriptArgs[option.name]) then + option.value = true + else + error(ScriptArgs[option.name].." is not a valid value for option "..option.name) + end + option.auto_detected = false + else + if CTestCompile(settings, option.source, option.compileoptions) then + option.value = true + end + end + end + + local save = function(option, output) + output:option(option, "value") + end + + local printhelp = function(option) + print("\t"..option.name.."=on|off") + if option.desc then print("\t\t"..option.desc) end + end + + local o = MakeOption(name, false, check, save, nil, printhelp) + o.desc = desc + o.source = source + o.compileoptions = compileoptions + return o +end + + +-- OptToggle -------------------------------------- +function OptToggle(name, default_value, desc) + local check = function(option, settings) + if ScriptArgs[option.name] then + if IsNegativeTerm(ScriptArgs[option.name]) then + option.value = false + elseif IsPositiveTerm(ScriptArgs[option.name]) then + option.value = true + else + error(ScriptArgs[option.name].." is not a valid value for option "..option.name) + end + end + end + + local save = function(option, output) + output:option(option, "value") + end + + local printhelp = function(option) + print("\t"..option.name.."=on|off") + if option.desc then print("\t\t"..option.desc) end + end + + local o = MakeOption(name, default_value, check, save, nil, printhelp) + o.desc = desc + return o +end + +-- OptInteger -------------------------------------- +function OptInteger(name, default_value, desc) + local check = function(option, settings) + if ScriptArgs[option.name] then + option.value = tonumber(ScriptArgs[option.name]) + end + end + + local save = function(option, output) + output:option(option, "value") + end + + local printhelp = function(option) + print("\t"..option.name.."=N") + if option.desc then print("\t\t"..option.desc) end + end + + local o = MakeOption(name, default_value, check, save, nil, printhelp) + o.desc = desc + return o +end + + +-- OptString -------------------------------------- +function OptString(name, default_value, desc) + local check = function(option, settings) + if ScriptArgs[option.name] then + option.value = ScriptArgs[option.name] + end + end + + local save = function(option, output) + output:option(option, "value") + end + + local printhelp = function(option) + print("\t"..option.name.."=STRING") + if option.desc then print("\t\t"..option.desc) end + end + + local o = MakeOption(name, default_value, check, save, nil, printhelp) + o.desc = desc + return o +end + +-- Find Compiler -------------------------------------- +--[[@FUNCTION + TODO +@END]]-- +function OptCCompiler(name, default_driver, default_c, default_cxx, desc) + local check = function(option, settings) + if ScriptArgs[option.name] then + -- set compile driver + option.driver = ScriptArgs[option.name] + + -- set c compiler + if ScriptArgs[option.name..".c"] then + option.c_compiler = ScriptArgs[option.name..".c"] + end + + -- set c+= compiler + if ScriptArgs[option.name..".cxx"] then + option.cxx_compiler = ScriptArgs[option.name..".cxx"] + end + + option.auto_detected = false + elseif option.driver then + -- no need todo anything if we have a driver + -- TODO: test if we can find the compiler + else + if ExecuteSilent("g++ -v") == 0 then + option.driver = "gcc" + elseif ExecuteSilent("cl") == 0 then + option.driver = "cl" + else + error("no c/c++ compiler found") + end + end + --setup_compiler(option.value) + end + + local apply = function(option, settings) + if option.driver == "cl" then + SetDriversCL(settings) + elseif option.driver == "gcc" then + SetDriversGCC(settings) + else + error(option.driver.." is not a known c/c++ compile driver") + end + + if option.c_compiler then settings.cc.c_compiler = option.c_compiler end + if option.cxx_compiler then settings.cc.cxx_compiler = option.cxx_compiler end + end + + local save = function(option, output) + output:option(option, "driver") + output:option(option, "c_compiler") + output:option(option, "cxx_compiler") + end + + local printhelp = function(option) + local a = "" + if option.desc then a = "for "..option.desc end + print("\t"..option.name.."=gcc|cl") + print("\t\twhat c/c++ compile driver to use"..a) + print("\t"..option.name..".c=FILENAME") + print("\t\twhat c compiler executable to use"..a) + print("\t"..option.name..".cxx=FILENAME") + print("\t\twhat c++ compiler executable to use"..a) + end + + local display = function(option) + local s = option.driver + if option.c_compiler then s = s .. " c="..option.c_compiler end + if option.cxx_compiler then s = s .. " cxx="..option.cxx_compiler end + return s + end + + local o = MakeOption(name, nil, check, save, display, printhelp) + o.desc = desc + o.driver = false + o.c_compiler = false + o.cxx_compiler = false + + if default_driver then o.driver = default_driver end + if default_c then o.c_compiler = default_c end + if default_cxx then o.cxx_compiler = default_cxx end + + o.Apply = apply + return o +end + +-- Option Library -------------------------------------- +--[[@FUNCTION + TODO +@END]]-- +function OptLibrary(name, header, desc) + local check = function(option, settings) + option.value = false + option.include_path = false + + local function check_compile_include(filename, paths) + if CTestCompile(settings, "#include <" .. filename .. ">\nint main(){return 0;}", "") then + return "" + end + + for k,v in pairs(paths) do + if CTestCompile(settings, "#include <" .. filename .. ">\nint main(){return 0;}", "-I"..v) then + return v + end + end + + return false + end + + if ScriptArgs[option.name] then + if IsNegativeTerm(ScriptArgs[option.name]) then + option.value = false + elseif ScriptArgs[option.name] == "system" then + option.value = true + else + option.value = true + option.include_path = ScriptArgs[option.name] + end + option.auto_detected = false + else + option.include_path = check_compile_include(option.header, {}) + if option.include_path == false then + if option.required then + print(name.." library not found and is required") + error("required library not found") + end + else + option.value = true + option.include_path = false + end + end + end + + local save = function(option, output) + output:option(option, "value") + output:option(option, "include_path") + end + + local display = function(option) + if option.value then + if option.include_path then + return option.include_path + else + return "(in system path)" + end + else + return "not found" + end + end + + local printhelp = function(option) + print("\t"..option.name.."=disable|system|PATH") + if option.desc then print("\t\t"..option.desc) end + end + + local o = MakeOption(name, false, check, save, display, printhelp) + o.include_path = false + o.header = header + o.desc = desc + return o +end + |