diff options
| author | ruki <[email protected]> | 2015-06-09 14:40:11 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2015-06-09 14:40:11 +0800 |
| commit | 2664a11c5ae2444241aa72346e7574279ac6b0bd (patch) | |
| tree | ec924c101d0e089edaa75ecce7a01613215e8ffd /xmake/scripts | |
| parent | d9051004d0b3b24f804e0bfffc5050e260018084 (diff) | |
reimpl project
Diffstat (limited to 'xmake/scripts')
| -rw-r--r-- | xmake/scripts/base/main.lua | 3 | ||||
| -rw-r--r-- | xmake/scripts/base/project.lua | 567 |
2 files changed, 187 insertions, 383 deletions
diff --git a/xmake/scripts/base/main.lua b/xmake/scripts/base/main.lua index 544a15005..38470a909 100644 --- a/xmake/scripts/base/main.lua +++ b/xmake/scripts/base/main.lua @@ -31,7 +31,6 @@ local option = require("base/option") local config = require("base/config") local global = require("base/global") local project = require("base/project") -local preprocessor = require("base/preprocessor") local action = require("action/action") local platform = require("platform/platform") @@ -498,7 +497,7 @@ function main._prepare_project() end -- load xmake.lua file - return project.loadxproj(options.file) + return project.load(options.file) end -- done help diff --git a/xmake/scripts/base/project.lua b/xmake/scripts/base/project.lua index 3cb3cc531..70d31c061 100644 --- a/xmake/scripts/base/project.lua +++ b/xmake/scripts/base/project.lua @@ -28,390 +28,224 @@ local path = require("base/path") local utils = require("base/utils") local table = require("base/table") local config = require("base/config") -local preprocessor = require("base/preprocessor") --- make configure for the given target_name -function project._makeconf_for_target(target_name, target) +-- the current mode is belong to the given modes? +function project._api_modes(env, ...) - -- check - assert(target_name and target) - - -- get the target configure file - local configfile = target.configfile - if not configfile then - return true - end - - -- translate file path - if not path.is_absolute(configfile) then - configfile = path.absolute(configfile, xmake._PROJECT_DIR) - else - configfile = path.translate(configfile) - end - - -- the prefix - local prefix = target_name:upper() .. "_CONFIG" - - -- open the file - local file = io.open(configfile, "w") - - -- make the head - file:write(string.format("#ifndef %s_H\n", prefix)) - file:write(string.format("#define %s_H\n", prefix)) - file:write("\n") - - -- make version - if target.version then - file:write("// version\n") - file:write(string.format("#define %s_VERSION \"%s\"\n", prefix, target.version)) - local i = 1 - local m = {"MAJOR", "MINOR", "ALTER"} - for v in target.version:gmatch("%d+") do - file:write(string.format("#define %s_VERSION_%s %s\n", prefix, m[i], v)) - i = i + 1 - if i > 3 then break end - end - file:write(string.format("#define %s_VERSION_BUILD %d\n", prefix, os.date("%Y%m%d%H%M", os.time()))) - file:write("\n") - end + -- get the current mode + local mode = config.get("mode") + assert(mode) - -- make the undefines - if target.undefines then - file:write("// undefines\n") - for _, undefine in ipairs(utils.wrap(target.undefines)) do - file:write(string.format("#undef %s\n", undefine)) + -- exists this mode? + for _, m in ipairs(utils.wrap(...)) do + if m and type(m) == "string" and m == mode then + return true end - file:write("\n") end +end - -- make the defines - if target.defines then - file:write("// defines\n") - for _, define in ipairs(utils.wrap(target.defines)) do - file:write(string.format("#define %s\n", define)) - end - file:write("\n") - end +-- the current platform is belong to the given platforms? +function project._api_platforms(env, ...) - -- load the switches - local switches = {} - if target.switches then - for _, switch in ipairs(utils.wrap(target.switches)) do - table.insert(switches, switch) - end - end - if target.switchfiles then - for _, switchfile in ipairs(utils.wrap(target.switchfiles)) do - if not path.is_absolute(switchfile) then - switchfile = path.absolute(switchfile, xmake._PROJECT_DIR) - end - local newenv, errors = preprocessor.loadfile(switchfile, "switches", {"defines"}) - if newenv and newenv._CONFIGS then - if newenv._CONFIGS.defines then - for _, switch in ipairs(newenv._CONFIGS.defines) do - table.insert(switches, switch) - end - end - else - -- error - utils.error(errors) - assert(false) - end - end - end + -- get the current platform + local plat = config.get("plat") + assert(plat) - -- make the switches - if #switches ~= 0 then - file:write("// switches\n") - for _, switch in ipairs(switches) do - file:write(string.format("#define %s_%s\n", prefix, switch)) + -- exists this platform? + for _, p in ipairs(utils.wrap(...)) do + if p and type(p) == "string" and p == plat then + return true end - file:write("\n") end +end - -- make the tail - file:write("#endif\n") +-- load all subprojects from the given directories +function project._api_subdirs(env, ...) - -- exit the file - file:close() + -- check + assert(env) - -- ok - return true -end + -- done + for _, subdir in ipairs(utils.wrap(...)) do + if subdir and type(subdir) == "string" then --- make the configure file for the given target and dependents -function project._makeconf_for_target_and_deps(target_name) + -- the project file + local file = subdir .. "/xmake.lua" + if not path.is_absolute(file) then + file = path.absolute(file, xmake._PROJECT_DIR) + end - -- the targets - local targets = project.targets() - assert(targets) + -- load the project script + local script = loadfile(file) + if script then - -- the target - local target = targets[target_name] - assert(target) + -- bind environment + setfenv(script, env) - -- make configure for the target - if not project._makeconf_for_target(target_name, target) then - return false - end - - -- exists the dependent targets? - if target.deps then - local deps = utils.wrap(target.deps) - for _, dep in ipairs(deps) do - if not project._makeconf_for_target_and_deps(dep) then return false end + -- done the project script + local ok, errors = pcall(script) + if not ok then + utils.error(errors) + assert(false) + end + end end end - - -- ok - return true end --- make the given configure to scope -function project._make_configs(scope, configs) +-- load all subprojects from the given files +function project._api_subfiles(env, ...) -- check - assert(configs) - - -- the current mode - local mode = config.get("mode") - assert(mode) - - -- the current platform - local plat = config.get("plat") - assert(plat) + assert(env) -- done - for k, v in pairs(configs) do - - -- check - assert(type(k) == "string") - - -- enter the target configure? - if k == "_TARGET" then - - -- the current - local current = project._CURRENT + for _, subfile in ipairs(utils.wrap(...)) do + if subfile and type(subfile) == "string" then - -- init all targets - for _k, _v in pairs(v) do - - -- init target scope first - current[_k] = current[_k] or {} - - -- make the target configure to this scope - project._make_configs(current[_k], _v) + -- the project file + if not path.is_absolute(subfile) then + subfile = path.absolute(subfile, xmake._PROJECT_DIR) end - -- enter the platform configure? - elseif k == "_PLATFORMS" then - - -- append configure to scope for the current mode - for _k, _v in pairs(v) do - if _k == plat then - project._make_configs(scope, _v) - end - end + -- load the project script + local script = loadfile(subfile) + if script then - -- enter the mode configure? - elseif k == "_MODES" then + -- bind environment + setfenv(script, env) - -- append configure to scope for the current mode - for _k, _v in pairs(v) do - if _k == mode then - project._make_configs(scope, _v) + -- done the project script + local ok, errors = pcall(script) + if not ok then + utils.error(errors) + assert(false) end end - - -- append configure to scope - elseif scope and not k:startswith("_") and k:endswith("s") then - - -- append all - scope[k] = scope[k] or {} - table.join2(scope[k], v) - - -- replace configure to scope - elseif scope and not k:startswith("_") then - - -- the configure item - scope[k] = scope[k] or {} - local item = scope[k] - - -- wrap it first - local values = utils.wrap(v) - if #values > 1 then - utils.error("the %s cannot have multiple values in xmake.xproj!", k) - assert(false) - end - - -- replace it - item[1] = values[1] end end end --- make values for switches -function project._make_for_switches(target, values) +-- switch to the given target +function project._api_target(env, name) -- check - assert(values) + assert(env and name) - -- wrap values first - values = utils.wrap(values) + -- the configs + local configs = env._CONFIGS + assert(configs) - -- done - local newvals = {} - for _, v in ipairs(values) do + -- init the target scope + configs[name] = configs[name] or {} - -- done script - v = v:gsub("%[(.*)%]", function (w) + -- switch to this targe scope + env._TARGET = configs[name] +end - -- load the script - local script = assert(loadstring("return " .. w)) +-- the single configure value +function project._api_value(env, name, value) - -- bind the envirnoment - setfenv(script, target) + -- check + assert(env and name and value) - -- ok? - return script() or "" - end) + -- get the current scope + local scope = env._TARGET or env._CONFIGS._ROOT + assert(scope) - -- insert new value - if v and type(v) == "string" and #v ~= 0 then - table.insert(newvals, v) - end - end - - -- ok? - return newvals + -- update value + scope[name] = value end --- init switches -function project._init_switches(target) - - -- make switches - target._SWITCHES = target._SWITCHES or {} +-- the multiple configure values +function project._api_values(env, name, ...) - -- _if x return v - target["_if"] = function (x, v) + -- check + assert(env and name) - if x and type(x) == "boolean" then return v end - return nil - end + -- get the current scope + local scope = env._TARGET or env._CONFIGS._ROOTS + assert(scope) - -- _if x return a else return b - target["_ifelse"] = function (x, a, b) + -- append values + scope[name] = scope[name] or {} + table.join2(scope[name], ...) +end - if x and type(x) == "boolean" then return a end - return b - end +-- filter the configure value +function project._filter(values) - -- init switches - if target.switches then - for _, switch in ipairs(target.switches) do - target._SWITCHES[switch] = true - end - end + -- check + assert(values) - -- load switches from the xxxx.xswf - if target.switchfiles then - for _, switchfile in ipairs(target.switchfiles) do - if not path.is_absolute(switchfile) then - switchfile = path.absolute(switchfile, xmake._PROJECT_DIR) - end - local newenv, errors = preprocessor.loadfile(switchfile, "switches", {"defines"}) - if newenv and newenv._CONFIGS then - if newenv._CONFIGS.defines then - for _, switch in ipairs(newenv._CONFIGS.defines) do - target._SWITCHES[switch] = true - end - end - else - -- error - utils.error(errors) - assert(false) - end - end + -- filter all + local newvals = {} + for _, v in ipairs(utils.wrap(values)) do + v = v:gsub("%$%((.*)%)", function (w) + if w == "buildir" then + return config.get("buildir") + elseif w == "projectdir" then + return xmake._PROJECT_DIR + end + end) + table.insert(newvals, v) end - -- attempt to get it from the switches - setmetatable(target, - { - __index = function(tbl, key) - - local switches = rawget(tbl, "_SWITCHES") - if switches and switches[key] then - return switches[key] - end - return rawget(tbl, key) - end - }) - -end - --- exit switches -function project._exit_switches(target) - - -- remove it - target._SWITCHES = nil - - -- remove if and ifelse - target["_if"] = nil - target["_ifelse"] = nil + -- ok? + return newvals end -- make the current project configure -function project._make() +function project._make(configs) - -- the configs - local configs = project._CONFIGS + -- check assert(configs) - -- init current + -- init project._CURRENT = project._CURRENT or {} + local current = project._CURRENT - -- make the current configure - local root = {} - project._make_configs(root, configs) + -- make all targets + for k, v in pairs(configs) do + if not k:startswith("_") then + current[k] = v + end + end - -- merge and remove repeat values and unwrap it - for _, target in pairs(project._CURRENT) do + -- merge the root configures to all targets + for _, target in pairs(current) do - -- merge the root configure to all targets - for k, v in pairs(root) do + -- merge the single root configure + for k, v in pairs(configs._ROOT) do if not target[k] then - -- insert it target[k] = v - elseif not k:startswith("_") and k:endswith("s") then - -- join root and target and update it - target[k] = table.join(v, target[k]) end end - -- init switches - project._init_switches(target) + -- merge the multiple root configure + for k, v in pairs(configs._ROOTS) do + if not target[k] then + target[k] = v + else + target[k] = table.join(v, target[k]) + end + end -- remove repeat values and unwrap it for k, v in pairs(target) do - if k and not k:startswith("_") then + -- remove repeat first + v = utils.unique(v) - -- make values for switches - v = project._make_for_switches(target, v) + -- filter values + v = project._filter(v) - -- remove repeat first - v = utils.unique(v) + -- unwrap it if be only one + v = utils.unwrap(v) - -- unwrap it if be only one - v = utils.unwrap(v) - - -- update it - target[k] = v - end + -- update it + target[k] = v end - - -- exit switches - project._exit_switches(target) end end @@ -425,25 +259,55 @@ function project.targets() return project._CURRENT end --- load xproj -function project.loadxproj(file) +-- load the project file +function project.load(file) -- check assert(file) - -- init configures - local configures = { "kind" - , "deps" - , "files" - , "links" - , "headers" + -- load the project script + local script = loadfile(file) + if not script then + return string.format("load %s failed!", file) + end + + -- bind the new environment + local newenv = {_CONFIGS = {_ROOT = {}, _ROOTS = {}}} + setmetatable(newenv, {__index = _G}) + setfenv(script, newenv) + + -- register interfaces for the condition + newenv.modes = function (...) return project._api_modes(newenv, ...) end + newenv.platforms = function (...) return project._api_platforms(newenv, ...) end + + -- register interfaces for the target + newenv.target = function (...) return project._api_target(newenv, ...) end + + -- register interfaces for the subproject files + newenv.subdirs = function (...) return project._api_subdirs(newenv, ...) end + newenv.subfiles = function (...) return project._api_subfiles(newenv, ...) end + + -- register interfaces for the single value + local interfaces = { "kind" , "headerdir" , "targetdir" , "objectdir" - , "linkdirs" - , "includedirs" , "configfile" , "version" + , "strip" + , "optimize" + , "language"} + for _, interface in ipairs(interfaces) do + newenv[interface] = function (value) return project._api_value(newenv, interface, value) end + end + + -- register interfaces for the multiple values + interfaces = { "deps" + , "files" + , "links" + , "headers" + , "linkdirs" + , "includedirs" , "cflags" , "cxflags" , "cxxflags" @@ -454,64 +318,21 @@ function project.loadxproj(file) , "shflags" , "defines" , "undefines" - , "switches" - , "switchfiles" - , "strip" , "symbols" , "warnings" - , "optimize" - , "language" , "vectorexts"} - - -- init filter - local filter = function (env, v) - if v == "buildir" then - return config.get("buildir") - elseif v == "projectdir" then - return xmake._PROJECT_DIR - end - return v - end - - -- init import - local import = function (name) - - -- import configs? - if name == "configs" then - - -- init configs - local configs = {} - - -- get the config for the current target - for k, v in pairs(config._CURRENT) do - configs[k] = v - end - - -- init the project directory - configs.projectdir = xmake._OPTIONS.project - - -- import it - return configs - end - + for _, interface in ipairs(interfaces) do + newenv[interface] = function (...) return project._api_values(newenv, interface, ...) end end - -- load and execute the xmake.xproj - local newenv, errors = preprocessor.loadfile(file, "project", configures, {"target", "platforms", "modes"}, filter, import) - if newenv and newenv._CONFIGS then - -- ok - project._CONFIGS = newenv._CONFIGS - elseif errors then - -- error + -- done the project script + local ok, errors = pcall(script) + if not ok then return errors - else - -- error - return string.format("load %s failed!", file) end -- make the current project configure - project._make() - + project._make(newenv._CONFIGS) end -- dump the current configure @@ -530,22 +351,6 @@ end -- make the configure file for the given target function project.makeconf(target_name) - -- the target name - if target_name and target_name ~= "all" then - -- make configure for the target and dependents - if not project._makeconf_for_target_and_deps(target_name) then return false end - else - - -- the targets - local targets = project.targets() - assert(targets) - - -- make configure for the targets - for target_name, target in pairs(targets) do - if not project._makeconf_for_target(target_name, target) then return false end - end - end - -- ok return true end |
