2014-09-14 08:36:58 +02:00

198 lines
5.9 KiB
Lua

module(..., package.seeall)
local util = require "tundra.util"
local buildfile = require "tundra.buildfile"
local decl = require "tundra.decl"
local nodegen = require "tundra.nodegen"
function match_build_id(id, default)
assert(id)
local i = id:gmatch("[^-]+")
local platform_name, toolset, variant, subvariant = i() or default, i() or default, i() or default, i() or default
return platform_name, toolset, variant, subvariant
end
local function iter_inherits(config, name)
local tab = config
return function()
while tab do
local my_tab = tab
if not my_tab then break end
tab = my_tab.Inherit
local v = my_tab[name]
if v then return v end
end
end
end
function load_toolset(id, ...)
-- For non-qualified packages, use a default package
if not id:find("%.") then
id = "tundra.tools." .. id
end
local pkg, err = require(id)
if err then
errorf("couldn't load extension module %s: %s", id, err)
end
pkg.apply(...)
end
local function setup_env(env, build_data, tuple, build_id)
local config = tuple.Config
local variant_name = tuple.Variant.Name
if not build_id then
build_id = config.Name .. "-" .. variant_name .. "-" .. tuple.SubVariant
end
local naked_platform, naked_toolset = match_build_id(build_id)
env:set("CURRENT_PLATFORM", naked_platform) -- e.g. linux or macosx
env:set("CURRENT_TOOLSET", naked_toolset) -- e.g. gcc or msvc
env:set("CURRENT_VARIANT", tuple.Variant.Name) -- e.g. debug or release
env:set("BUILD_ID", build_id) -- e.g. linux-gcc-debug
env:set("OBJECTDIR", "$(OBJECTROOT)" .. SEP .. "$(BUILD_ID)")
for tools in iter_inherits(config, "Tools") do
for k, v in pairs(tools) do
if type(k) == "string" then
error("Tools must be a plain array - to include options keys wrap them in their own tables:\n " ..
"e.g. Tools = { { 'foo'; Option = ... }, ... }.\n Your Tools:\n" .. util.tostring(tools))
end
end
for _, data in ipairs(tools) do
local id, options
if type(data) == "table" then
id = assert(data[1])
options = data
data = id
end
if type(data) == "string" then
load_toolset(data, env, options)
elseif type(data) == "function" then
data(env, options)
else
error("bad parameters")
end
end
end
-- Incorporate matching values from the build data's Env and ReplaceEnv.
if build_data.Env then
nodegen.append_filtered_env_vars(env, build_data.Env, build_id, false)
end
if build_data.ReplaceEnv then
nodegen.replace_filtered_env_vars(env, build_data.ReplaceEnv, build_id, false)
end
-- Incorporate matching values from the config's Env and ReplaceEnv.
for env_tab in iter_inherits(config, "Env") do
nodegen.append_filtered_env_vars(env, env_tab, build_id, false)
end
for env_tab in iter_inherits(config, "ReplaceEnv") do
nodegen.replace_filtered_env_vars(env, env_tab, build_id, false)
end
-- Run post-setup functions. This typically sets up implicit make functions.
env:run_setup_functions()
return env
end
local function setup_envs(tuple, configs, default_env, build_data)
local result = {}
local top_env = setup_env(default_env:clone(), build_data, tuple)
result["__default"] = top_env
-- Use the same build id for all subconfigurations
local build_id = top_env:get("BUILD_ID")
local cfg = configs[tuple.Config.Name]
for moniker, x in util.nil_pairs(cfg.SubConfigs) do
if result[x] then
croak("duplicate subconfig name: %s", x)
end
local sub_tuple = { Config = configs[x], Variant = tuple.Variant, SubVariant = tuple.SubVariant }
if not sub_tuple.Config then
errorf("%s: no such config (in SubConfigs specification)", x)
end
local sub_env = setup_env(default_env:clone(), build_data, sub_tuple, build_id)
result[moniker] = sub_env
end
return result
end
function parse_units(build_tuples, args, passes)
if args.SyntaxExtensions then
print("*WARNING* SyntaxExtensions has been deprecated. Use require instead.")
end
for _, id in util.nil_ipairs(args.SyntaxExtensions) do
require(id)
end
local function chunk ()
local raw_nodes, default_nodes, always_nodes = decl.parse(args.Units or "units.lua")
assert(#default_nodes > 0 or #always_nodes > 0, "no default unit name to build was set")
return { raw_nodes, default_nodes, always_nodes }
end
local success, result = xpcall(chunk, buildfile.syntax_error_catcher)
if success then
return result[1], result[2], result[3]
else
print("Build script execution failed")
croak("%s", result or "")
end
end
-- Inputs
-- build_tuples - the config/variant/subvariant pairs to include in the DAG
-- args - Raw data from Build() call
-- passes - Passes specified in Build() call
-- configs - Configs specified in Build() call
function generate_dag(build_tuples, args, passes, configs, default_env)
local raw_nodes, default_nodes, always_nodes = parse_units(build_tuples, args, passes)
local results = {}
-- Let the nodegen code generate DAG nodes for all active
-- configurations/variants.
for _, tuple in pairs(build_tuples) do
printf("Generating DAG for %s-%s-%s", tuple.Config.Name, tuple.Variant.Name, tuple.SubVariant)
local envs = setup_envs(tuple, configs, default_env, args)
local always_nodes, default_nodes, named_nodes = nodegen.generate_dag {
Envs = envs,
Config = tuple.Config,
Variant = tuple.Variant,
Declarations = raw_nodes,
DefaultNodes = default_nodes,
AlwaysNodes = always_nodes,
Passes = passes,
}
results[#results + 1] = {
Config = assert(tuple.Config),
Variant = assert(tuple.Variant),
SubVariant = assert(tuple.SubVariant),
AlwaysNodes = always_nodes,
DefaultNodes = default_nodes,
NamedNodes = named_nodes,
}
end
return raw_nodes, results
end