Initial work on an expanded configuration API; added configset, criteria, and context objects, initial usage for target naming parameters
This commit is contained in:
parent
752adb830b
commit
91ba9c899f
@ -78,8 +78,8 @@
|
||||
-- load the manifest of script files
|
||||
scripts = dofile("src/_manifest.lua")
|
||||
|
||||
-- main script always goes at the end
|
||||
table.insert(scripts, "_premake_main.lua")
|
||||
-- main script always goes first
|
||||
table.insert(scripts, 1, "_premake_main.lua")
|
||||
|
||||
-- open scripts.c and write the file header
|
||||
local out = io.open("src/host/scripts.c", "w+b")
|
||||
|
@ -9,25 +9,35 @@
|
||||
|
||||
return
|
||||
{
|
||||
-- core files
|
||||
-- Lua extensions
|
||||
"base/os.lua",
|
||||
"base/path.lua",
|
||||
"base/string.lua",
|
||||
"base/table.lua",
|
||||
|
||||
-- core files
|
||||
"base/io.lua",
|
||||
"base/globals.lua",
|
||||
"base/action.lua",
|
||||
"base/criteria.lua",
|
||||
"base/option.lua",
|
||||
"base/tree.lua",
|
||||
"base/project.lua",
|
||||
"base/config.lua",
|
||||
"base/bake.lua",
|
||||
"base/api.lua",
|
||||
"base/cmdline.lua",
|
||||
"base/validate.lua",
|
||||
"base/help.lua",
|
||||
"base/premake.lua",
|
||||
|
||||
-- configuration APIs
|
||||
"base/api.lua",
|
||||
"base/configset.lua",
|
||||
"base/context.lua",
|
||||
|
||||
-- runtime environment setup
|
||||
"_premake_init.lua",
|
||||
"base/cmdline.lua",
|
||||
|
||||
-- project APIs
|
||||
"project/oven.lua",
|
||||
"project/project.lua",
|
||||
|
89
src/_premake_init.lua
Normal file
89
src/_premake_init.lua
Normal file
@ -0,0 +1,89 @@
|
||||
--
|
||||
-- _premake_init.lua
|
||||
--
|
||||
-- Prepares the runtime environment for the add-ons and user project scripts.
|
||||
--
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
local configset = premake.configset
|
||||
|
||||
|
||||
--
|
||||
-- Create a "root" configuration set, to hold the global configuration. Values
|
||||
-- that are added to this set become available for all add-ons, solution, projects,
|
||||
-- and on down the line.
|
||||
--
|
||||
|
||||
premake.root = configset.new()
|
||||
local root = premake.root
|
||||
|
||||
|
||||
--
|
||||
-- Set up the global environment for the systems I know about. I would like to see
|
||||
-- at least some if not all of this moved into add-ons in the future.
|
||||
--
|
||||
-- TODO: use the same configuration API as the user project scripts, once they
|
||||
-- have been ported, like:
|
||||
--
|
||||
-- configuration { "Windows or Xbox360", "SharedLib" }
|
||||
-- targetprefix ""
|
||||
-- targetextension ".dll"
|
||||
-- implibextension ".lib"
|
||||
--
|
||||
|
||||
configset.addblock(root, { "SharedLib" })
|
||||
|
||||
configset.addvalue(root, "targetprefix", "lib")
|
||||
configset.addvalue(root, "targetextension", ".so")
|
||||
|
||||
configset.addblock(root, { "StaticLib" })
|
||||
|
||||
configset.addvalue(root, "targetprefix", "lib")
|
||||
configset.addvalue(root, "targetextension", ".a")
|
||||
|
||||
configset.addblock(root, { "MacOSX", "SharedLib" })
|
||||
|
||||
configset.addvalue(root, "targetextension", ".dylib")
|
||||
|
||||
configset.addblock(root, { "PS3", "ConsoleApp" })
|
||||
|
||||
configset.addvalue(root, "targetextension", ".elf")
|
||||
|
||||
configset.addblock(root, { "Windows", "ConsoleApp" })
|
||||
|
||||
configset.addvalue(root, "targetextension", ".exe")
|
||||
|
||||
configset.addblock(root, { "Windows", "WindowedApp" })
|
||||
|
||||
configset.addvalue(root, "targetextension", ".exe")
|
||||
|
||||
configset.addblock(root, { "Windows", "SharedLib" })
|
||||
|
||||
configset.addvalue(root, "targetprefix", "")
|
||||
configset.addvalue(root, "targetextension", ".dll")
|
||||
configset.addvalue(root, "implibextension", ".lib")
|
||||
|
||||
configset.addblock(root, { "Windows", "StaticLib" })
|
||||
|
||||
configset.addvalue(root, "targetprefix", "")
|
||||
configset.addvalue(root, "targetextension", ".lib")
|
||||
|
||||
configset.addblock(root, { "Xbox360", "ConsoleApp" })
|
||||
|
||||
configset.addvalue(root, "targetextension", ".exe")
|
||||
|
||||
configset.addblock(root, { "Xbox360", "WindowedApp" })
|
||||
|
||||
configset.addvalue(root, "targetextension", ".exe")
|
||||
|
||||
configset.addblock(root, { "Xbox360", "SharedLib" })
|
||||
|
||||
configset.addvalue(root, "targetprefix", "")
|
||||
configset.addvalue(root, "targetextension", ".dll")
|
||||
configset.addvalue(root, "implibextension", ".lib")
|
||||
|
||||
configset.addblock(root, { "Xbox360", "StaticLib" })
|
||||
|
||||
configset.addvalue(root, "targetprefix", "")
|
||||
configset.addvalue(root, "targetextension", ".lib")
|
@ -760,14 +760,17 @@
|
||||
name = "system",
|
||||
scope = "config",
|
||||
kind = "string",
|
||||
allowed = function(value)
|
||||
value = value:lower()
|
||||
if premake.systems[value] then
|
||||
return value
|
||||
else
|
||||
return nil, "unknown system"
|
||||
end
|
||||
end,
|
||||
allowed = {
|
||||
"bsd",
|
||||
"haiku",
|
||||
"linux",
|
||||
"macosx",
|
||||
"ps3",
|
||||
"solaris",
|
||||
"wii",
|
||||
"windows",
|
||||
"xbox360",
|
||||
},
|
||||
}
|
||||
|
||||
api.register {
|
||||
|
110
src/base/configset.lua
Normal file
110
src/base/configset.lua
Normal file
@ -0,0 +1,110 @@
|
||||
--
|
||||
-- configset.lua
|
||||
--
|
||||
-- DO NOT USE THIS YET! I am just getting started here; please wait until
|
||||
-- I've had a chance to build it out more before using.
|
||||
--
|
||||
-- A configuration set manages a collection of configuration values, which
|
||||
-- are organized into "blocks". Each block stores a set of field-value pairs,
|
||||
-- along with a list of terms which indicate the context in which those
|
||||
-- values should be applied.
|
||||
--
|
||||
-- Configurations use the API definition to know what fields are available,
|
||||
-- and the corresponding value types for those fields. Only fields that have
|
||||
-- been registered via api.register() can be stored.
|
||||
--
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.configset = {}
|
||||
local configset = premake.configset
|
||||
local criteria = premake.criteria
|
||||
|
||||
|
||||
--
|
||||
-- Create a new configuration set.
|
||||
--
|
||||
|
||||
function configset.new()
|
||||
local cfgset = {}
|
||||
cfgset.blocks = {}
|
||||
configset.addblock(cfgset, {})
|
||||
return cfgset
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Create a new block of configuration field-value pairs, with the provided
|
||||
-- set of context terms to control their application.
|
||||
--
|
||||
-- @param cfgset
|
||||
-- The configuration set to hold the new block.
|
||||
-- @param terms
|
||||
-- A set of context terms to control the application of values contained
|
||||
-- in the block.
|
||||
-- @return
|
||||
-- The new configuration data block.
|
||||
--
|
||||
|
||||
function configset.addblock(cfgset, terms)
|
||||
local block = {}
|
||||
|
||||
-- convert terms to a simple, all-lower-case array
|
||||
terms = table.flatten(terms)
|
||||
for i, term in ipairs(terms) do
|
||||
terms[i] = term:lower()
|
||||
end
|
||||
block.terms = terms
|
||||
|
||||
table.insert(cfgset.blocks, block)
|
||||
cfgset.current = block
|
||||
return block
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Add a new field-value pair to the current configuration data block. The
|
||||
-- data type of the field is taken into account when adding the values:
|
||||
-- strings are replaced, arrays are merged, etc.
|
||||
--
|
||||
-- @param cfgset
|
||||
-- The configuration set to hold the new value.
|
||||
-- @param fieldname
|
||||
-- The name of the field being set. The field should have already been
|
||||
-- defined using the api.register() function.
|
||||
-- @param value
|
||||
-- The new value for the field.
|
||||
--
|
||||
|
||||
function configset.addvalue(cfgset, fieldname, value)
|
||||
cfgset.current[fieldname] = value
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Retrieve a value from the configuration set.
|
||||
--
|
||||
-- @param cfgset
|
||||
-- The configuration set to query.
|
||||
-- @param fieldname
|
||||
-- The name of the field to query. The field should have already been
|
||||
-- defined using the api.register() function.
|
||||
-- @param context
|
||||
-- A list of lowercase context terms to use during the fetch. Only those
|
||||
-- blocks with terms fully contained by this list will be considered in
|
||||
-- determining the returned value. Terms should be lower case to make
|
||||
-- the context filtering case-insensitive.
|
||||
--
|
||||
|
||||
function configset.fetchvalue(cfgset, fieldname, context)
|
||||
local value = ""
|
||||
|
||||
for _, block in ipairs(cfgset.blocks) do
|
||||
if criteria.matches(block.terms, context) then
|
||||
value = block[fieldname] or value
|
||||
end
|
||||
end
|
||||
|
||||
return value
|
||||
end
|
53
src/base/context.lua
Normal file
53
src/base/context.lua
Normal file
@ -0,0 +1,53 @@
|
||||
--
|
||||
-- context.lua
|
||||
--
|
||||
-- DO NOT USE THIS YET! I am just getting started here; please wait until
|
||||
-- I've had a chance to build it out more before using.
|
||||
--
|
||||
-- Provide a context for pulling out values from a configuration set. Each
|
||||
-- context has an associated list of terms which constrain the values that
|
||||
-- it will retrieve, i.e. "Windows, "Debug", "x64", and so on.
|
||||
--
|
||||
-- The context also provides caching for the values returned from the set.
|
||||
--
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.context = {}
|
||||
local context = premake.context
|
||||
local configset = premake.configset
|
||||
|
||||
|
||||
--
|
||||
-- Create a new context object.
|
||||
--
|
||||
-- @param cfgset
|
||||
-- The configuration set to provide the data from this context.
|
||||
-- @param terms
|
||||
-- A list of terms to describe this context. Only configuration blocks
|
||||
-- matching these terms will be considered when querying values.
|
||||
-- @return
|
||||
-- A new context object.
|
||||
--
|
||||
|
||||
function context.new(cfgset, terms)
|
||||
local ctx = {}
|
||||
ctx.cfgset = cfgset
|
||||
|
||||
-- make future tests case-insensitive
|
||||
terms = table.flatten(terms)
|
||||
for i, term in ipairs(terms) do
|
||||
terms[i] = term:lower()
|
||||
end
|
||||
ctx.terms = terms
|
||||
|
||||
-- attach field lookup metatable
|
||||
setmetatable(ctx, {
|
||||
__index = function(ctx, key)
|
||||
ctx[key] = configset.fetchvalue(cfgset, key, terms)
|
||||
return ctx[key]
|
||||
end
|
||||
})
|
||||
|
||||
return ctx
|
||||
end
|
67
src/base/criteria.lua
Normal file
67
src/base/criteria.lua
Normal file
@ -0,0 +1,67 @@
|
||||
--
|
||||
-- criteria.lua
|
||||
--
|
||||
-- DO NOT USE THIS YET! I am just getting started here; please wait until
|
||||
-- I've had a chance to build it out more before using.
|
||||
--
|
||||
-- Stores a list of criteria terms with support for negation, conjunction,
|
||||
-- and wildcard matches. Provides functions match match these criteria
|
||||
-- against various contexts.
|
||||
--
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake.criteria = {}
|
||||
local criteria = premake.criteria
|
||||
|
||||
|
||||
--
|
||||
-- Create a new criteria object.
|
||||
--
|
||||
-- @param terms
|
||||
-- A list of criteria terms.
|
||||
-- @return
|
||||
-- A new criteria object.
|
||||
--
|
||||
|
||||
function criteria.new(terms)
|
||||
terms = table.flatten(terms)
|
||||
|
||||
-- make future tests case-insensitive
|
||||
for i, term in ipairs(terms) do
|
||||
terms[i] = term:lower()
|
||||
end
|
||||
|
||||
return terms
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Determine if this criteria is met by the provided list of context terms.
|
||||
--
|
||||
-- @param crit
|
||||
-- The criteria to be tested.
|
||||
-- @param context
|
||||
-- The list of context terms to test against, provided as a list of
|
||||
-- lowercase strings.
|
||||
-- @return
|
||||
-- True if all criteria are satisfied by the context.
|
||||
--
|
||||
|
||||
function criteria.matches(crit, context)
|
||||
local checkterm = function(term)
|
||||
for _, value in ipairs(context) do
|
||||
if value:match(term) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, term in ipairs(crit) do
|
||||
if not checkterm(term) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
@ -28,47 +28,6 @@
|
||||
premake.XBOX360 = "xbox360"
|
||||
|
||||
|
||||
--
|
||||
-- The list of known systems, with metadata to help drive the generation process.
|
||||
--
|
||||
|
||||
premake.systems = {
|
||||
linux =
|
||||
{
|
||||
sharedlib = { prefix = "lib", extension = ".so" },
|
||||
staticlib = { prefix = "lib", extension = ".a" },
|
||||
|
||||
},
|
||||
|
||||
macosx =
|
||||
{
|
||||
sharedlib = { prefix = "lib", extension = ".dylib" },
|
||||
staticlib = { prefix = "lib", extension = ".a" },
|
||||
},
|
||||
|
||||
ps3 =
|
||||
{
|
||||
consoleapp = { extension = ".elf" },
|
||||
sharedlib = { prefix = "lib" },
|
||||
staticlib = { prefix = "lib", extension = ".a" },
|
||||
},
|
||||
|
||||
windows =
|
||||
{
|
||||
consoleapp = { extension = ".exe" },
|
||||
windowedapp = { extension = ".exe" },
|
||||
sharedlib = { extension = ".dll" },
|
||||
staticlib = { extension = ".lib" },
|
||||
}
|
||||
}
|
||||
|
||||
premake.systems.bsd = premake.systems.linux
|
||||
premake.systems.haiku = premake.systems.linux
|
||||
premake.systems.solaris = premake.systems.linux
|
||||
premake.systems.wii = premake.systems.linux
|
||||
premake.systems.xbox360 = premake.systems.windows
|
||||
|
||||
|
||||
--
|
||||
-- Open a file for output, and call a function to actually do the writing.
|
||||
-- Used by the actions to generate solution and project files.
|
||||
|
@ -55,10 +55,8 @@
|
||||
local bundlename = ""
|
||||
local bundlepath = ""
|
||||
local suffix = ""
|
||||
|
||||
local sysinfo = premake.systems[cfg.system][kind:lower()] or {}
|
||||
local prefix = sysinfo.prefix or ""
|
||||
local extension = sysinfo.extension or ""
|
||||
local prefix = cfg.context[field.."prefix"]
|
||||
local extension = cfg.context[field.."extension"]
|
||||
|
||||
-- Mac .app requires more logic than I can bundle up in a table right now
|
||||
if cfg.system == premake.MACOSX and kind == premake.WINDOWEDAPP then
|
||||
|
@ -4,8 +4,9 @@
|
||||
-- Copyright (c) 2011-2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
premake5.project = { }
|
||||
premake5.project = {}
|
||||
local project = premake5.project
|
||||
local context = premake.context
|
||||
local oven = premake5.oven
|
||||
|
||||
|
||||
@ -82,10 +83,24 @@
|
||||
cfg.solution = prj.solution
|
||||
cfg.project = prj
|
||||
cfg.architecture = cfg.architecture or architecture
|
||||
|
||||
-- Temporary: Create a context for this configuration. Eventually, the context
|
||||
-- will become the configuration object and much of this baking code will go
|
||||
-- away. For right now, it provides a way to access the global settings that
|
||||
-- match this configuration's setup.
|
||||
filter = { cfg.buildcfg, cfg.platform, _ACTION, cfg.system, cfg.architecture, cfg.kind }
|
||||
|
||||
local terms = {}
|
||||
for k, v in pairs(filter) do
|
||||
if filter[k] then
|
||||
table.insert(terms, v)
|
||||
end
|
||||
end
|
||||
cfg.context = context.new(premake.root, terms)
|
||||
|
||||
-- fill in any calculated values
|
||||
premake5.config.bake(cfg)
|
||||
|
||||
|
||||
return cfg
|
||||
end
|
||||
|
||||
|
75
tests/base/test_configset.lua
Normal file
75
tests/base/test_configset.lua
Normal file
@ -0,0 +1,75 @@
|
||||
--
|
||||
-- tests/base/test_configset.lua
|
||||
-- Test suite for the configset API.
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
T.configset = {}
|
||||
local suite = T.configset
|
||||
|
||||
local configset = premake.configset
|
||||
|
||||
|
||||
--
|
||||
-- Setup and teardown
|
||||
--
|
||||
|
||||
local cfgset
|
||||
|
||||
function suite.setup()
|
||||
cfgset = configset.new()
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that new() returns a valid object.
|
||||
--
|
||||
|
||||
function suite.new_returnsValidObject()
|
||||
test.isequal("table", type(cfgset))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Check the default values for different field types.
|
||||
--
|
||||
|
||||
function suite.defaultValue_onString()
|
||||
test.isequal("", configset.fetchvalue(cfgset, "targetextension", {}))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that I can roundtrip a value stored into the
|
||||
-- initial, default configuration.
|
||||
--
|
||||
|
||||
function suite.canRoundtrip_onDefaultBlock()
|
||||
configset.addvalue(cfgset, "targetextension", ".so")
|
||||
test.isequal(".so", configset.fetchvalue(cfgset, "targetextension", {}))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that I can roundtrip a value stored into a block
|
||||
-- with a simple matching term.
|
||||
--
|
||||
|
||||
function suite.canRoundtrip_onSimpleTermMatch()
|
||||
configset.addblock(cfgset, { "Windows" })
|
||||
configset.addvalue(cfgset, "targetextension", ".dll")
|
||||
test.isequal(".dll", configset.fetchvalue(cfgset, "targetextension", { "windows" }))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that blocks that do not match the context terms
|
||||
-- do not contribute to the result.
|
||||
--
|
||||
|
||||
function suite.skipsBlock_onTermMismatch()
|
||||
configset.addvalue(cfgset, "targetextension", ".so")
|
||||
configset.addblock(cfgset, { "Windows" })
|
||||
configset.addvalue(cfgset, "targetextension", ".dll")
|
||||
test.isequal(".so", configset.fetchvalue(cfgset, "targetextension", { "linux" }))
|
||||
end
|
43
tests/base/test_context.lua
Normal file
43
tests/base/test_context.lua
Normal file
@ -0,0 +1,43 @@
|
||||
--
|
||||
-- tests/base/test_context.lua
|
||||
-- Test suite for the configuration context API.
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
T.context = {}
|
||||
local suite = T.context
|
||||
|
||||
local context = premake.context
|
||||
local configset = premake.configset
|
||||
|
||||
|
||||
--
|
||||
-- Setup and teardown
|
||||
--
|
||||
|
||||
local ctx, cfgset
|
||||
|
||||
function suite.setup()
|
||||
cfgset = configset.new()
|
||||
ctx = context.new(cfgset, {"Windows"})
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that new() returns a valid object.
|
||||
--
|
||||
|
||||
function suite.new_returnsValidObject()
|
||||
test.isequal("table", type(ctx))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Context should be able to retrieve a default value from
|
||||
-- the configuration set, using the field name.
|
||||
--
|
||||
|
||||
function suite.returnsConfigValue_onExistingValue()
|
||||
configset.addvalue(cfgset, "targetextension", ".so")
|
||||
test.isequal(".so", ctx.targetextension)
|
||||
end
|
47
tests/base/test_criteria.lua
Normal file
47
tests/base/test_criteria.lua
Normal file
@ -0,0 +1,47 @@
|
||||
--
|
||||
-- tests/base/test_criteria.lua
|
||||
-- Test suite for the criteria matching API.
|
||||
-- Copyright (c) 2012 Jason Perkins and the Premake project
|
||||
--
|
||||
|
||||
T.criteria = {}
|
||||
local suite = T.criteria
|
||||
|
||||
local criteria = premake.criteria
|
||||
|
||||
|
||||
--
|
||||
-- Setup and teardown
|
||||
--
|
||||
|
||||
local crit
|
||||
|
||||
|
||||
--
|
||||
-- Make sure that new() returns a valid object.
|
||||
--
|
||||
|
||||
function suite.new_returnsValidObject()
|
||||
crit = criteria.new {}
|
||||
test.isequal("table", type(crit))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- A criteria with no terms should satisfy any context.
|
||||
--
|
||||
|
||||
function suite.matches_onEmptyCriteria()
|
||||
crit = criteria.new {}
|
||||
test.istrue(criteria.matches(crit, { "apple", "orange" }))
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Should not match if any term is missing in the context.
|
||||
--
|
||||
|
||||
function suite.fails_onMissingContext()
|
||||
crit = criteria.new { "orange", "pear" }
|
||||
test.isfalse(criteria.matches(crit, { "apple", "orange" }))
|
||||
end
|
@ -47,6 +47,9 @@
|
||||
dofile("base/test_api.lua")
|
||||
dofile("base/test_action.lua")
|
||||
dofile("base/test_config.lua")
|
||||
dofile("base/test_configset.lua")
|
||||
dofile("base/test_context.lua")
|
||||
dofile("base/test_criteria.lua")
|
||||
dofile("base/test_include.lua")
|
||||
dofile("base/test_location.lua")
|
||||
dofile("base/test_os.lua")
|
||||
@ -219,7 +222,8 @@
|
||||
|
||||
msg = string.format("%d tests passed, %d failed", passed, failed)
|
||||
if (failed > 0) then
|
||||
error(msg, 0)
|
||||
-- should probably return an error code here somehow
|
||||
print(msg)
|
||||
else
|
||||
print(msg)
|
||||
end
|
||||
|
Reference in New Issue
Block a user