Clean up rule container creation and usage

- Adds externalRule() to match rule()
- Adds externalProject() as replacement for external() for consistency with rules
- Adds rules() to associate rules (external or generated) with a project
- Drops customRules(); use rules() on the project level instead
This commit is contained in:
Jason Perkins 2014-10-20 15:41:00 -04:00
parent d73e9af2ed
commit 4af8eb44af
14 changed files with 154 additions and 109 deletions

View File

@ -162,13 +162,6 @@
tokens = true,
}
api.register {
name = "customRules",
scope = "project",
kind = "list:file",
tokens = true,
}
api.register {
name = "debugargs",
scope = "config",
@ -624,6 +617,12 @@
tokens = true,
}
api.register {
name = "rules",
scope = "project",
kind = "list:string",
}
api.register {
name = "startproject",
scope = "solution",

View File

@ -241,7 +241,7 @@
m.elements.itemDefinitionGroup = function(cfg)
if cfg.kind == p.UTILITY then
return {
m.customRuleVars,
m.ruleVars,
m.buildEvents,
}
else
@ -253,7 +253,7 @@
m.buildEvents,
m.imageXex,
m.deploy,
m.customRuleVars,
m.ruleVars,
}
end
end
@ -491,9 +491,9 @@
-- Write out project-level custom rule variables.
---
function m.customRuleVars(cfg)
function m.ruleVars(cfg)
local vars = p.api.getCustomVars()
table.foreachi(cfg.project._customRules, function(rule)
for rule in p.global.eachRule() do
local contents = p.capture(function ()
p.push()
for _, var in ipairs(vars) do
@ -515,11 +515,11 @@
end)
if #contents > 0 then
p.push('<%s>', rule)
p.push('<%s>', rule.name)
p.outln(contents)
p.pop('</%s>', rule)
p.pop('</%s>', rule.name)
end
end)
end
end
@ -764,17 +764,21 @@
function m.categorize(prj, file)
-- If any configuration for this file uses a custom build step or a
-- custom, externally defined rule, that's the category to use
-- If any configuration for this file uses a custom build step,
-- that's the category to use
for cfg in project.eachconfig(prj) do
local fcfg = fileconfig.getconfig(file, cfg)
if fileconfig.hasCustomBuildRule(fcfg) then
return "CustomBuild"
elseif fcfg and fcfg._customRule then
return fcfg._customRule
end
end
-- If there is a custom rule associated with it, use that
local rule = p.global.getRuleForFile(file.name)
if rule then
return rule.name
end
-- Otherwise use the file extension to deduce a category
if path.iscppfile(file.name) then
return "ClCompile"
@ -1155,11 +1159,13 @@
function m.importExtensionTargets(prj)
p.w('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.targets" />')
p.push('<ImportGroup Label="ExtensionTargets">')
table.foreachi(prj.customRules, function(value)
value = path.translate(project.getrelative(prj, value))
value = path.appendExtension(value, ".targets")
p.x('<Import Project="%s" />', value)
end)
for i = 1, #prj.rules do
local rule = p.global.getRule(prj.rules[i])
local loc = project.getrelative(prj, premake.filename(rule, ".targets"))
p.x('<Import Project="%s" />', path.translate(loc))
end
p.pop('</ImportGroup>')
end
@ -1174,11 +1180,13 @@
function m.importExtensionSettings(prj)
p.w('<Import Project="$(VCTargetsPath)\\Microsoft.Cpp.props" />')
p.push('<ImportGroup Label="ExtensionSettings">')
table.foreachi(prj.customRules, function(value)
value = path.translate(project.getrelative(prj, value))
value = path.appendExtension(value, ".props")
p.x('<Import Project="%s" />', value)
end)
for i = 1, #prj.rules do
local rule = p.global.getRule(prj.rules[i])
local loc = project.getrelative(prj, premake.filename(rule, ".props"))
p.x('<Import Project="%s" />', path.translate(loc))
end
p.pop('</ImportGroup>')
end

View File

@ -645,7 +645,8 @@
---
function api.reset()
-- Clear out all top level objects
-- Clear out all top level objects, but keep the root config
api.scope.global.rules = {}
api.scope.global.solutions = {}
-- Remove all custom variables
@ -1192,46 +1193,3 @@
table.remove(value, 1)
api._customVarFormats[name] = value
end
function customRule(value)
-- Store the rule name in the current configuration, like a
-- normal set-field operation would
local fieldName = "_customRule"
local field = premake.field.get(fieldName)
if not field then
field = premake.field.new {
name = fieldName,
scope = "config",
kind = "string",
}
end
api.callback(field, value)
-- Wild hack: I need a way to get all of the custom rule names that are
-- in use within a project. The rule names are currently only associated
-- with individual files. Rather than iterating over all the files after
-- the fact, keep a master list of rule names in the first configuration
-- block of the project. This way it will come out of the baking system
-- looking like a normal list:string field.
fieldName = "_customRules"
field = premake.field.get(fieldName)
if not field then
field = premake.field.new {
name = fieldName,
scope = "config",
kind = "list:string"
}
end
local cset = api.target(field)
if not cset then
local err = string.format("unable to set rule in %s scope, should be project", api.scope.current.class.name)
error(err, 2)
end
local current = cset.current
cset.current = cset.blocks[1]
api.callback(field, value)
cset.current = current
end

View File

@ -70,6 +70,7 @@
self.class = class
self.name = name
self.filename = name
self.script = _SCRIPT
self.basedir = os.getcwd()
self.external = false

View File

@ -47,6 +47,43 @@
---
-- Retrieve a rule by name or index.
--
-- @param key
-- The rule key, either a string name or integer index.
-- @returns
-- The rule with the provided key.
---
function global.getRule(key)
local root = p.api.rootContainer()
return root.rules[key]
end
---
-- Retrieve the rule to applies to the provided file name, if any such
-- rule exists.
--
-- @param fname
-- The name of the file.
-- @returns
-- The rule, is one has been registered, or nil.
---
function global.getRuleForFile(fname)
local ext = path.getextension(fname):lower()
for rule in global.eachRule() do
if rule.fileExtension == ext then
return rule
end
end
end
---
-- Retrieve a solution by name or index.
--
@ -58,7 +95,5 @@
function global.getSolution(key)
local root = p.api.rootContainer()
if root.solutions then
return root.solutions[key]
end
return root.solutions[key]
end

View File

@ -94,7 +94,6 @@
-- to project configurations.
self.configs = oven.bakeConfigs(self)
end

View File

@ -4,10 +4,12 @@
-- Copyright (c) 2002-2014 Jason Perkins and the Premake project
--
local solution = premake.solution
local project = premake.project
local config = premake.config
local field = premake.field
local p = premake
local solution = p.solution
local project = p.project
local config = p.config
local field = p.field
@ -180,7 +182,7 @@
---
function premake.filename(obj, ext)
local fname = obj.location
local fname = obj.location or obj.basedir
if ext and not ext:startswith(".") then
fname = path.join(fname, ext)
else
@ -367,6 +369,14 @@ end
premake.error("project '%s' does not have a language", prj.name)
end
-- all rules must exist
for i = 1, #prj.rules do
local rule = prj.rules[i]
if not p.global.getRule(rule) then
premake.error("project '%s' uses missing rule '%s'", prj.name, rule)
end
end
-- check for out of scope fields
premake.validateScopes(prj, "project", ctx)
end

View File

@ -28,7 +28,6 @@
function project.new(name)
local prj = p.container.new(project, name)
prj.uuid = os.uuid(name)
prj.filename = name
if p.api.scope.group then
prj.group = p.api.scope.group.name

View File

@ -18,7 +18,6 @@
function solution.new(name)
local sln = p.container.new(solution, name)
sln.filename = name
return sln
end

View File

@ -16,6 +16,8 @@
local sln
function suite.setup()
rule "MyRules"
rule "MyOtherRules"
sln = test.createsolution()
end
@ -45,8 +47,7 @@
--
function suite.addsImport_onEachRulesFile()
customRules "MyRules"
customRules "MyOtherRules"
rules { "MyRules", "MyOtherRules" }
prepare()
test.capture [[
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
@ -63,13 +64,13 @@
--
function suite.usesProjectRelativePaths()
customRules "path/to/MyRules"
rules "MyRules"
location "build"
prepare()
test.capture [[
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="..\path\to\MyRules.props" />
<Import Project="..\MyRules.props" />
</ImportGroup>
]]
end

View File

@ -16,6 +16,8 @@
local sln
function suite.setup()
rule "MyRules"
rule "MyOtherRules"
sln = test.createsolution()
end
@ -45,8 +47,7 @@
--
function suite.addsImport_onEachRulesFile()
customRules "MyRules"
customRules "MyOtherRules"
rules { "MyRules", "MyOtherRules" }
prepare()
test.capture [[
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
@ -63,13 +64,13 @@
--
function suite.usesProjectRelativePaths()
customRules "path/to/MyRules"
rules { "MyRules" }
location "build"
prepare()
test.capture [[
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
<Import Project="..\path\to\MyRules.targets" />
<Import Project="..\MyRules.targets" />
</ImportGroup>
]]
end

View File

@ -524,10 +524,12 @@
function suite.correctlyCategorized_onCustomRule()
files { "hello.dae" }
filter "files:**.dae"
customRule "Animation"
rule "Animation"
fileExtension ".dae"
prepare()
test.capture [[
test.capture [[
<ItemGroup>
<Animation Include="hello.dae" />
</ItemGroup>
@ -535,11 +537,14 @@
end
function suite.customRule_onLiteralVars()
function suite.rule_onLiteralVars()
files { "hello.dae" }
filter "files:**.dae"
customRule "Animation"
customVar { "GenerateDebugInfo", "True" }
rule "Animation"
fileExtension ".dae"
prepare()
test.capture [[
<ItemGroup>
@ -552,12 +557,15 @@
end
function suite.customRule_onLiteralPath()
function suite.rule_onLiteralPath()
targetdir "../bin/%{cfg.buildcfg}"
files { "hello.dae" }
filter "files:**.dae"
customRule "Animation"
customVar { "OutputDirectory", "%{cfg.targetdir}/anim" }
rule "Animation"
fileExtension ".dae"
prepare()
test.capture [[
<ItemGroup>
@ -570,12 +578,14 @@
end
function suite.customRule_onPerConfigLiteralVars()
function suite.rule_onPerConfigLiteralVars()
files { "hello.dae" }
filter { "files:**.dae" }
customRule "Animation"
filter { "files:**.dae", "configurations:Debug" }
customVar { "GenerateDebugInfo", "True" }
rule "Animation"
fileExtension ".dae"
prepare()
test.capture [[
<ItemGroup>
@ -587,11 +597,14 @@
end
function suite.customRule_onListVars()
function suite.rule_onListVars()
files { "hello.dae" }
filter "files:**.dae"
customRule "Animation"
customList { "ExtraDependencies", "File1", "File2" }
rule "Animation"
fileExtension ".dae"
prepare()
test.capture [[
<ItemGroup>
@ -604,13 +617,16 @@
end
function suite.customRule_onPerConfigListVars()
function suite.rule_onPerConfigListVars()
files { "hello.dae" }
filter { "files:**.dae" }
customRule "Animation"
customList { "ExtraDependencies", "File1", "File2" }
filter { "files:**.dae", "configurations:Release" }
customList { "ExtraDependencies", "File3" }
rule "Animation"
fileExtension ".dae"
prepare()
test.capture [[
<ItemGroup>
@ -623,12 +639,15 @@
end
function suite.customRule_onListVarsWithCustomFormat()
function suite.rule_onListVarsWithCustomFormat()
files { "hello.dae" }
filter "files:**.dae"
customRule "Animation"
customListFormat { "ExtraDependencies", ";" }
customList { "ExtraDependencies", "File1", "File2" }
rule "Animation"
fileExtension ".dae"
prepare()
test.capture [[
<ItemGroup>

View File

@ -172,8 +172,10 @@
function suite.filter_onCustomRule()
files { "hello.dae" }
filter "files:**.dae"
customRule "Animation"
rule "Animation"
fileExtension ".dae"
prepare()
test.capture [[
<ItemGroup>

View File

@ -130,3 +130,17 @@
premake.validate()
test.stderr("'configurations' on config")
end
--
-- If a rule is specified for inclusion, it must have been defined.
--
function suite.fails_onNoSuchRule()
solution "MySolution"
configurations { "Debug", "Release" }
project "MyProject"
rules { "NoSuchRule" }
test.isfalse(pcall(premake.validate))
end