198 lines
5.9 KiB
Lua
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
|
|
|
|
|