Merge work-in-progress rules support, configuration container API

This commit is contained in:
Jason Perkins 2014-10-08 16:45:03 -04:00
commit 352b5ba4ca
28 changed files with 2104 additions and 345 deletions

View File

@ -20,18 +20,13 @@
"base/globals.lua", "base/globals.lua",
-- configuration data -- configuration data
"base/container.lua",
"base/field.lua", "base/field.lua",
"base/criteria.lua", "base/criteria.lua",
"base/detoken.lua", "base/detoken.lua",
"base/configset.lua", "base/configset.lua",
"base/context.lua", "base/context.lua",
-- project objects
"base/project.lua",
"base/solution.lua",
"base/config.lua",
"base/fileconfig.lua",
-- runtime switches -- runtime switches
"base/option.lua", "base/option.lua",
"base/action.lua", "base/action.lua",
@ -39,6 +34,13 @@
-- project script setup -- project script setup
"base/api.lua", "base/api.lua",
-- project objects
"base/solution.lua",
"base/project.lua",
"base/config.lua",
"base/fileconfig.lua",
"base/rules.lua",
-- project script processing -- project script processing
"base/oven.lua", "base/oven.lua",
"base/premake.lua", "base/premake.lua",
@ -70,6 +72,9 @@
"actions/vstudio/vs2010_vcxproj.lua", "actions/vstudio/vs2010_vcxproj.lua",
"actions/vstudio/vs2010_vcxproj_user.lua", "actions/vstudio/vs2010_vcxproj_user.lua",
"actions/vstudio/vs2010_vcxproj_filters.lua", "actions/vstudio/vs2010_vcxproj_filters.lua",
"actions/vstudio/vs2010_rules_props.lua",
"actions/vstudio/vs2010_rules_targets.lua",
"actions/vstudio/vs2010_rules_xml.lua",
"actions/vstudio/vs2012.lua", "actions/vstudio/vs2012.lua",
"actions/vstudio/vs2013.lua", "actions/vstudio/vs2013.lua",

View File

@ -62,20 +62,35 @@
}, },
} }
api.register {
name = "buildmessage",
scope = "config",
kind = "string",
tokens = true,
}
api.register { api.register {
name = "buildcommands", name = "buildcommands",
scope = "config", scope = { "config", "rule" },
kind = "list:string", kind = "list:string",
tokens = true, tokens = true,
} }
api.alias("buildcommands", "buildCommands")
api.register {
name = "buildDependencies",
scope = { "rule" },
kind = "list:string",
tokens = true,
}
api.register {
name = "buildmessage",
scope = { "config", "rule" },
kind = "string",
tokens = true
}
api.alias("buildmessage", "buildMessage")
api.register { api.register {
name = "buildoptions", name = "buildoptions",
scope = "config", scope = "config",
@ -83,13 +98,17 @@
tokens = true, tokens = true,
} }
api.register { api.register {
name = "buildoutputs", name = "buildoutputs",
scope = "config", scope = { "config", "rule" },
kind = "list:path", kind = "list:path",
tokens = true, tokens = true,
} }
api.alias("buildoutputs", "buildOutputs")
api.register { api.register {
name = "buildinputs", name = "buildinputs",
scope = "config", scope = "config",
@ -214,14 +233,30 @@
tokens = true, tokens = true,
} }
api.register {
name = "display",
scope = "rule",
kind = "string",
}
-- For backward compatibility, excludes() is now an alias for removefiles() -- For backward compatibility, excludes() is now an alias for removefiles()
function excludes(value) function excludes(value)
removefiles(value) removefiles(value)
end end
api.register {
name = "fileExtension",
scope = "rule",
kind = "string",
}
api.register { api.register {
name = "filename", name = "filename",
scope = "project", scope = { "project", "rule" },
kind = "string", kind = "string",
tokens = true, tokens = true,
} }
@ -442,7 +477,7 @@
api.register { api.register {
name = "location", name = "location",
scope = "project", scope = { "project", "rule" },
kind = "path", kind = "path",
tokens = true, tokens = true,
} }
@ -555,6 +590,12 @@
tokens = true, tokens = true,
} }
api.register {
name = "propertyDefinition",
scope = "rule",
kind = "list:table",
}
api.register { api.register {
name = "rebuildcommands", name = "rebuildcommands",
scope = "config", scope = "config",

View File

@ -184,7 +184,7 @@
function make.csResponseRules(prj) function make.csResponseRules(prj)
local toolset = premake.tools.dotnet local toolset = premake.tools.dotnet
local ext = make.getmakefilename(prj, true) local ext = make.getmakefilename(prj, true)
local makefile = path.getname(premake.project.getfilename(prj, ext)) local makefile = path.getname(premake.filename(prj, ext))
local response = path.translate(make.cs.getresponsefilename(prj)) local response = path.translate(make.cs.getresponsefilename(prj))
_p('$(RESPONSE): %s', makefile) _p('$(RESPONSE): %s', makefile)

View File

@ -58,7 +58,7 @@
function make.cleanrules(sln) function make.cleanrules(sln)
_p('clean:') _p('clean:')
for prj in solution.eachproject(sln) do for prj in solution.eachproject(sln) do
local prjpath = project.getfilename(prj, make.getmakefilename(prj, true)) local prjpath = premake.filename(prj, make.getmakefilename(prj, true))
local prjdir = path.getdirectory(path.getrelative(sln.location, prjpath)) local prjdir = path.getdirectory(path.getrelative(sln.location, prjpath))
local prjname = path.getname(prjpath) local prjname = path.getname(prjpath)
_x(1,'@${MAKE} --no-print-directory -C %s -f %s clean', prjdir, prjname) _x(1,'@${MAKE} --no-print-directory -C %s -f %s clean', prjdir, prjname)
@ -174,7 +174,7 @@
_p(1,'@echo "==== Building %s ($(%s_config)) ===="', prj.name, cfgvar) _p(1,'@echo "==== Building %s ($(%s_config)) ===="', prj.name, cfgvar)
local prjpath = project.getfilename(prj, make.getmakefilename(prj, true)) local prjpath = premake.filename(prj, make.getmakefilename(prj, true))
local prjdir = path.getdirectory(path.getrelative(sln.location, prjpath)) local prjdir = path.getdirectory(path.getrelative(sln.location, prjpath))
local prjname = path.getname(prjpath) local prjname = path.getname(prjpath)

View File

@ -6,9 +6,11 @@
premake.vstudio = {} premake.vstudio = {}
local vstudio = premake.vstudio local vstudio = premake.vstudio
local solution = premake.solution
local project = premake.project local p = premake
local config = premake.config local solution = p.solution
local project = p.project
local config = p.config
-- --
@ -368,6 +370,16 @@
end end
---
-- Generates a Visual Studio project element for the current action.
---
function vstudio.projectElement()
p.push('<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">')
end
-- --
-- Returns the full, absolute path to the Visual Studio project file -- Returns the full, absolute path to the Visual Studio project file
-- corresponding to a particular project object. -- corresponding to a particular project object.
@ -386,7 +398,7 @@
extension = iif(_ACTION > "vs2008", ".vcxproj", ".vcproj") extension = iif(_ACTION > "vs2008", ".vcxproj", ".vcproj")
end end
return project.getfilename(prj, extension) return premake.filename(prj, extension)
end end
@ -563,3 +575,4 @@
end end
end end

View File

@ -467,7 +467,7 @@
function cs2005.xmlDeclaration() function cs2005.xmlDeclaration()
if _ACTION > "vs2008" then if _ACTION > "vs2008" then
_p('<?xml version="1.0" encoding="utf-8"?>') p.xmlUtf8()
end end
end end

View File

@ -14,7 +14,7 @@
-- --
function cs2005.generate_user(prj) function cs2005.generate_user(prj)
_p('<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">') p.vstudio.projectElement()
_p(1,'<PropertyGroup>') _p(1,'<PropertyGroup>')
-- Per-configuration reference paths aren't supported (are they?) so just -- Per-configuration reference paths aren't supported (are they?) so just

View File

@ -39,6 +39,22 @@
---
-- Generate the .props, .targets, and .xml files for custom rules.
---
function vs2010.generateRule(rule)
p.eol("\r\n")
p.indent(" ")
p.escaper(vs2010.esc)
p.generate(rule, ".props", vs2010.rules.props.generate)
p.generate(rule, ".targets", vs2010.rules.targets.generate)
p.generate(rule, ".xml", vs2010.rules.xml.generate)
end
-- --
-- The VS 2010 standard for XML escaping in generated project files. -- The VS 2010 standard for XML escaping in generated project files.
-- --
@ -80,6 +96,7 @@
onsolution = vstudio.vs2005.generateSolution, onsolution = vstudio.vs2005.generateSolution,
onproject = vstudio.vs2010.generateProject, onproject = vstudio.vs2010.generateProject,
onrule = vstudio.vs2010.generateRule,
oncleansolution = vstudio.cleanSolution, oncleansolution = vstudio.cleanSolution,
oncleanproject = vstudio.cleanProject, oncleanproject = vstudio.cleanProject,

View File

@ -0,0 +1,176 @@
---
-- vs2010_rules_props.lua
-- Generate a Visual Studio 201x custom rules properties file.
-- Copyright (c) 2014 Jason Perkins and the Premake project
--
premake.vstudio.vs2010.rules = {}
premake.vstudio.vs2010.rules.props = {}
local m = premake.vstudio.vs2010.rules.props
m.elements = {}
local p = premake
---
-- Entry point; generate the root <Project> element.
---
m.elements.project = function(r)
return {
p.xmlUtf8,
p.vstudio.projectElement,
m.targetsGroup,
m.dependsOnGroup,
m.ruleGroup,
}
end
function m.generate(r)
p.callArray(m.elements.project, r)
p.pop()
p.out('</Project>')
end
---
-- Generate the targets property group element.
---
m.elements.targetsGroup = function(r)
return {
m.beforeTargets,
m.afterTargets,
}
end
function m.targetsGroup(r)
p.w('<PropertyGroup')
p.push(' Condition="\'$(%sBeforeTargets)\' == \'\' and \'$(%sAfterTargets)\' == \'\' and \'$(ConfigurationType)\' != \'Makefile\'">',
r.name, r.name)
p.callArray(m.elements.targetsGroup, r)
p.pop('</PropertyGroup>')
end
---
-- Generate the dependencies property group element.
---
m.elements.dependsOnGroup = function(r)
return {
m.dependsOn,
}
end
function m.dependsOnGroup(r)
p.push('<PropertyGroup>')
p.callArray(m.elements.dependsOnGroup, r)
p.pop('</PropertyGroup>')
end
---
-- Generate the rule itemm group element.
---
m.elements.ruleGroup = function(r)
return {
m.propertyDefaults,
m.commandLineTemplates,
m.outputs,
m.executionDescription,
m.additionalDependencies,
}
end
function m.ruleGroup(r)
p.push('<ItemDefinitionGroup>')
p.push('<%s>', r.name)
p.callArray(m.elements.ruleGroup, r)
p.pop('</%s>', r.name)
p.pop('</ItemDefinitionGroup>')
end
---
-- Output the default values for all of the property definitions.
---
function m.propertyDefaults(r)
local defs = r.propertyDefinition
for i = 1, #defs do
local def = defs[i]
local value = def.value
if value then
if def.kind == "path" then
value = path.translate(value)
end
p.w('<%s>%s</%s>', def.name, value, def.name)
end
end
end
---
-- Implementations of individual elements.
---
function m.additionalDependencies(r)
local deps = table.concat(r.buildDependencies, ";")
p.x('<AdditionalDependencies>%s</AdditionalDependencies>', deps)
end
function m.afterTargets(r)
p.w('<%sAfterTargets>CustomBuild</%sAfterTargets>', r.name, r.name)
end
function m.beforeTargets(r)
p.w('<%sBeforeTargets>Midl</%sBeforeTargets>', r.name, r.name)
end
function m.commandLineTemplates(r)
if #r.buildcommands then
local cmds = table.concat(r.buildcommands, p.eol())
p.x('<CommandLineTemplate>%s</CommandLineTemplate>', cmds)
end
end
function m.dependsOn(r)
p.w('<%sDependsOn', r.name)
p.w(' Condition="\'$(ConfigurationType)\' != \'Makefile\'">_SelectedFiles;$(%sDependsOn)</%sDependsOn>',
r.name, r.name, r.name)
end
function m.executionDescription(r)
if r.buildmessage then
p.x('<ExecutionDescription>%s</ExecutionDescription>', r.buildmessage)
end
end
function m.outputs(r)
if #r.buildoutputs then
local outputs = table.concat(r.buildoutputs, ";")
p.x('<Outputs>%s</Outputs>', path.translate(outputs))
end
end

View File

@ -0,0 +1,443 @@
---
-- vs2010_rules_targets.lua
-- Generate a Visual Studio 201x custom rules targets file.
-- Copyright (c) 2014 Jason Perkins and the Premake project
---
premake.vstudio.vs2010.rules.targets = {}
local m = premake.vstudio.vs2010.rules.targets
m.elements = {}
local p = premake
---
-- Entry point; generate the root <Project> element.
---
m.elements.project = function(r)
return {
p.xmlUtf8,
p.vstudio.projectElement,
m.availableItemGroup,
m.computeInputsGroup,
m.usingTask,
m.ruleTarget,
m.computeOutputTarget,
}
end
function m.generate(r)
p.callArray(m.elements.project, r)
p.pop()
p.out('</Project>')
end
---
-- Generate the opening item group element.
---
m.elements.availableItemGroup = function(r)
return {
m.propertyPageSchema,
m.availableItemName,
}
end
function m.availableItemGroup(r)
p.push('<ItemGroup>')
p.callArray(m.elements.availableItemGroup, r)
p.pop('</ItemGroup>')
end
---
-- Generate the computed input targets group.
---
m.elements.computeInputsGroup = function(r)
return {
m.computeLinkInputsTargets,
m.computeLibInputsTargets,
}
end
function m.computeInputsGroup(r)
p.push('<PropertyGroup>')
p.callArray(m.elements.computeInputsGroup, r)
p.pop('</PropertyGroup>')
end
---
-- Generate the rule's target element.
---
m.elements.ruleTargetAttributes = function(r)
return {
m.targetName,
m.beforeTargets,
m.afterTargets,
m.targetCondition,
m.targetOutputs,
m.targetInputs,
m.dependsOnTargets,
}
end
m.elements.ruleTarget = function(r)
return {
m.selectedFiles,
m.tlog,
m.message,
m.tlogWrite,
m.tlogRead,
m.rule,
}
end
function m.ruleTarget(r)
local attribs = p.capture(function()
p.push()
p.callArray(m.elements.ruleTargetAttributes, r)
p.pop()
end)
p.push('<Target')
p.outln(attribs .. '>')
p.callArray(m.elements.ruleTarget, r)
p.pop('</Target>')
end
---
-- Write out the tlog entries. I've extended this with an input
-- dependencies fix as described here:
-- http://www.virtualdub.org/blog/pivot/entry.php?id=334
---
m.elements.tlog = function(r)
return {
m.tlogSource,
m.tlogInputs,
m.tlogProperties,
}
end
function m.tlog(r)
p.push('<ItemGroup>')
p.push('<%s_tlog', r.name)
p.w('Include="%%(%s.Outputs)"', r.name)
p.w('Condition="\'%%(%s.Outputs)\' != \'\' and \'%%(%s.ExcludedFromBuild)\' != \'true\'">', r.name, r.name)
p.callArray(m.elements.tlog, r)
p.pop('</%s_tlog>', r.name)
p.pop('</ItemGroup>')
end
---
-- Write out the rule element.
---
m.elements.ruleAttributes = function(r)
return {
m.ruleCondition,
m.commandLineTemplate,
m.properties,
m.additionalOptions,
m.inputs,
m.standardOutputImportance,
}
end
function m.rule(r)
local attribs = p.capture(function()
p.push()
p.callArray(m.elements.ruleAttributes, r)
p.pop()
end)
p.w('<%s', r.name)
p.outln(attribs .. ' />')
end
---
-- Generate the rule's computed output element.
---
m.elements.computeOutputItems = function(r)
return {
m.outputs,
m.linkLib,
}
end
m.elements.computeOutputTarget = function(r)
return {
m.makeDir,
}
end
function m.computeOutputTarget(r)
p.push('<Target')
p.w('Name="Compute%sOutput"', r.name)
p.w('Condition="\'@(%s)\' != \'\'">', r.name)
p.push('<ItemGroup>')
p.callArray(m.elements.computeOutputItems, r)
p.pop('</ItemGroup>')
p.callArray(m.elements.computeOutputTarget, r)
p.pop('</Target>')
end
---
-- Implementations of individual elements.
---
function m.additionalOptions(r)
p.w('AdditionalOptions="%%(%s.AdditionalOptions)"', r.name)
end
function m.commandLineTemplate(r)
p.w('CommandLineTemplate="%%(%s.CommandLineTemplate)"', r.name)
end
function m.afterTargets(r)
p.w('AfterTargets="$(%sAfterTargets)"', r.name)
end
function m.availableItemName(r)
p.push('<AvailableItemName Include="%s">', r.name)
p.w('<Targets>_%s</Targets>', r.name)
p.pop('</AvailableItemName>')
end
function m.beforeTargets(r)
p.w('BeforeTargets="$(%sBeforeTargets)"', r.name)
end
function m.computeLibInputsTargets(r)
p.push('<ComputeLibInputsTargets>')
p.w('$(ComputeLibInputsTargets);')
p.w('Compute%sOutput;', r.name)
p.pop('</ComputeLibInputsTargets>')
end
function m.computeLinkInputsTargets(r)
p.push('<ComputeLinkInputsTargets>')
p.w('$(ComputeLinkInputsTargets);')
p.w('Compute%sOutput;', r.name)
p.pop('</ComputeLinkInputsTargets>')
end
function m.dependsOnTargets(r)
p.w('DependsOnTargets="$(%sDependsOn);Compute%sOutput"', r.name, r.name)
end
function m.inputs(r)
p.w('Inputs="%%(%s.Identity)"', r.name)
end
function m.linkLib(r)
local linkable
for i = 1, #r.buildoutputs do
if (path.islinkable(r.buildoutputs[i])) then
linkable = true
end
end
if linkable then
for i, el in pairs { 'Link', 'Lib', 'ImpLib' } do
p.push('<%s', el)
p.w('Include="%%(%sOutputs.Identity)"', r.name)
p.w('Condition="\'%%(Extension)\'==\'.obj\' or \'%%(Extension)\'==\'.res\' or \'%%(Extension)\'==\'.rsc\' or \'%%(Extension)\'==\'.lib\'" />')
p.pop()
end
end
end
function m.makeDir(r)
p.w('<MakeDir Directories="@(%sOutputs->\'%%(RootDir)%%(Directory)\')" />', r.name)
end
function m.message(r)
p.w('<Message')
p.w(' Importance="High"')
p.w(' Text="%%(%s.ExecutionDescription)" />', r.name)
end
function m.outputs(r)
p.w('<%sOutputs', r.name)
p.w(' Condition="\'@(%s)\' != \'\' and \'%%(%s.ExcludedFromBuild)\' != \'true\'"', r.name, r.name)
p.w(' Include="%%(%s.Outputs)" />', r.name)
end
function m.properties(r)
local defs = r.propertyDefinition
for i = 1, #defs do
local name = defs[i].name
p.w('%s="%%(%s.%s)"', name, r.name, name)
end
end
function m.propertyPageSchema(r)
p.w('<PropertyPageSchema')
p.w(' Include="$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml" />')
end
function m.ruleCondition(r)
p.w('Condition="\'@(%s)\' != \'\' and \'%%(%s.ExcludedFromBuild)\' != \'true\'"', r.name, r.name)
end
function m.selectedFiles(r)
p.push('<ItemGroup Condition="\'@(SelectedFiles)\' != \'\'">')
p.w('<%s Remove="@(%s)" Condition="\'%%(Identity)\' != \'@(SelectedFiles)\'" />', r.name, r.name)
p.pop('</ItemGroup>')
end
function m.standardOutputImportance(r)
p.w('StandardOutputImportance="High"')
p.w('StandardErrorImportance="High"')
end
function m.targetCondition(r)
p.w('Condition="\'@(%s)\' != \'\'"', r.name)
end
function m.targetInputs(r)
local extra = {}
local defs = r.propertyDefinition
for i = 1, #defs do
local def = defs[i]
if def.dependency then
table.insert(extra, string.format("%%(%s.%s);", r.name, def.name))
end
end
extra = table.concat(extra)
p.w('Inputs="%%(%s.Identity);%%(%s.AdditionalDependencies);%s$(MSBuildProjectFile)"', r.name, r.name, extra)
end
function m.targetName(r)
p.w('Name="_%s"', r.name)
end
function m.targetOutputs(r)
p.w('Outputs="%%(%s.Outputs)"', r.name)
end
function m.tlogInputs(r)
p.w("<Inputs>@(%s, ';')</Inputs>", r.name)
end
function m.tlogProperties(r)
local defs = r.propertyDefinition
for i = 1, #defs do
local def = defs[i]
if def.dependency then
p.w('<%s>%%(%s.%s)</%s>', def.name, r.name, def.name, def.name)
end
end
end
function m.tlogRead(r)
local extra = {}
local defs = r.propertyDefinition
for i = 1, #defs do
local def = defs[i]
if def.dependency then
table.insert(extra, string.format("%%(%s_tlog.%s);", r.name, def.name))
end
end
extra = table.concat(extra)
p.w('<WriteLinesToFile')
p.w(' Condition="\'@(%s_tlog)\' != \'\' and \'%%(%s_tlog.ExcludedFromBuild)\' != \'true\'"', r.name, r.name)
p.w(' File="$(IntDir)$(ProjectName).read.1.tlog"')
p.w(' Lines="^%%(%s_tlog.Inputs);%s$(MSBuildProjectFullPath);%%(%s_tlog.Fullpath)" />', r.name, extra, r.name)
end
function m.tlogWrite(r)
p.w('<WriteLinesToFile')
p.w(' Condition="\'@(%s_tlog)\' != \'\' and \'%%(%s_tlog.ExcludedFromBuild)\' != \'true\'"', r.name, r.name)
p.w(' File="$(IntDir)$(ProjectName).write.1.tlog"')
p.w(' Lines="^%%(%s_tlog.Source);%%(%s_tlog.Fullpath)" />', r.name, r.name)
end
function m.tlogSource(r)
p.w("<Source>@(%s, '|')</Source>", r.name)
end
function m.usingTask(r)
p.push('<UsingTask')
p.w('TaskName="%s"', r.name)
p.w('TaskFactory="XamlTaskFactory"')
p.w('AssemblyName="Microsoft.Build.Tasks.v4.0">')
p.w('<Task>$(MSBuildThisFileDirectory)$(MSBuildThisFileName).xml</Task>')
p.pop('</UsingTask>')
end

View File

@ -0,0 +1,392 @@
---
-- vs2010_rules_xml.lua
-- Generate a Visual Studio 201x custom rules XML file.
-- Copyright (c) 2014 Jason Perkins and the Premake project
--
premake.vstudio.vs2010.rules.xml = {}
local m = premake.vstudio.vs2010.rules.xml
m.elements = {}
local p = premake
---
-- Entry point; generate the root <ProjectSchemaDefinitions> element.
---
m.elements.project = function(r)
return {
p.xmlUtf8,
m.projectSchemaDefinitions,
m.rule,
m.ruleItem,
m.fileExtension,
m.contentType,
}
end
function m.generate(r)
p.callArray(m.elements.project, r)
p.out('</ProjectSchemaDefinitions>')
end
---
-- Generate the main <Rule> element.
---
m.elements.rule = function(r)
return {
m.dataSource,
m.categories,
m.inputs,
m.properties,
m.commandLineTemplate,
m.beforeTargets,
m.afterTargets,
m.outputs,
m.executionDescription,
m.additionalDependencies,
m.additionalOptions,
}
end
function m.rule(r)
p.push('<Rule')
p.w('Name="%s"', r.name)
p.w('PageTemplate="tool"')
p.w('DisplayName="%s"', r.display or r.name)
p.w('Order="200">')
p.callArray(m.elements.rule, r)
p.pop('</Rule>')
end
---
-- Generate the list of categories.
---
function m.categories(r)
local categories = {
[1] = { name="General" },
[2] = { name="Command Line", subtype="CommandLine" },
}
p.push('<Rule.Categories>')
for i = 1, #categories do
m.category(categories[i])
end
p.pop('</Rule.Categories>')
end
function m.category(cat)
local attribs = p.capture(function()
p.push()
p.w('Name="%s"', cat.name)
if cat.subtype then
p.w('Subtype="%s"', cat.subtype)
end
p.pop()
end)
p.push('<Category')
p.outln(attribs .. '>')
p.push('<Category.DisplayName>')
p.w('<sys:String>%s</sys:String>', cat.name)
p.pop('</Category.DisplayName>')
p.pop('</Category>')
end
---
-- Generate the list of property definitions.
---
function m.properties(r)
local defs = r.propertyDefinition
for i = 1, #defs do
local def = defs[i]
if def.kind == "boolean" then
m.boolProperty(def)
elseif def.kind == "list" then
m.stringListProperty(def)
elseif type(def.values) == "table" then
m.enumProperty(def)
else
m.stringProperty(def)
end
end
end
function m.baseProperty(def, suffix)
local c = p.capture(function ()
p.w('Name="%s"', def.name)
p.w('HelpContext="0"')
p.w('DisplayName="%s"', def.display or def.name)
if def.description then
p.w('Description="%s"', def.description)
end
end)
if suffix then
c = c .. suffix
end
p.outln(c)
end
function m.boolProperty(def)
p.push('<BoolProperty')
m.baseProperty(def)
p.w('Switch="%s" />', def.switch or "[value]")
p.pop()
end
function m.enumProperty(def)
p.push('<EnumProperty')
m.baseProperty(def, '>')
local values = def.values
local switches = def.switch or {}
local keys = table.keys(def.values)
table.sort(keys)
for _, key in pairs(keys) do
p.push('<EnumValue')
p.w('Name="%d"', key)
if switches[key] then
p.w('DisplayName="%s"', values[key])
p.w('Switch="%s" />', switches[key])
else
p.w('DisplayName="%s" />', values[key])
end
p.pop()
end
p.pop('</EnumProperty>')
end
function m.stringProperty(def)
p.push('<StringProperty')
m.baseProperty(def)
p.w('Switch="%s" />', def.switch or "[value]")
p.pop()
end
function m.stringListProperty(def)
p.push('<StringListProperty')
m.baseProperty(def)
p.w('Separator="%s"', def.separator or " ")
p.w('Switch="%s" />', def.switch or "[value]")
p.pop()
end
---
-- Implementations of individual elements.
---
function m.additionalDependencies(r)
p.push('<StringListProperty')
p.w('Name="AdditionalDependencies"')
p.w('DisplayName="Additional Dependencies"')
p.w('IncludeInCommandLine="False"')
p.w('Visible="false" />')
p.pop()
end
function m.additionalOptions(r)
p.push('<StringProperty')
p.w('Subtype="AdditionalOptions"')
p.w('Name="AdditionalOptions"')
p.w('Category="Command Line">')
p.push('<StringProperty.DisplayName>')
p.w('<sys:String>Additional Options</sys:String>')
p.pop('</StringProperty.DisplayName>')
p.push('<StringProperty.Description>')
p.w('<sys:String>Additional Options</sys:String>')
p.pop('</StringProperty.Description>')
p.pop('</StringProperty>')
end
function m.afterTargets(r)
p.push('<DynamicEnumProperty')
p.w('Name="%sAfterTargets"', r.name)
p.w('Category="General"')
p.w('EnumProvider="Targets"')
p.w('IncludeInCommandLine="False">')
p.push('<DynamicEnumProperty.DisplayName>')
p.w('<sys:String>Execute After</sys:String>')
p.pop('</DynamicEnumProperty.DisplayName>')
p.push('<DynamicEnumProperty.Description>')
p.w('<sys:String>Specifies the targets for the build customization to run after.</sys:String>')
p.pop('</DynamicEnumProperty.Description>')
p.push('<DynamicEnumProperty.ProviderSettings>')
p.push('<NameValuePair')
p.w('Name="Exclude"')
p.w('Value="^%sAfterTargets|^Compute" />', r.name)
p.pop()
p.pop('</DynamicEnumProperty.ProviderSettings>')
p.push('<DynamicEnumProperty.DataSource>')
p.push('<DataSource')
p.w('Persistence="ProjectFile"')
p.w('ItemType=""')
p.w('HasConfigurationCondition="true" />')
p.pop()
p.pop('</DynamicEnumProperty.DataSource>')
p.pop('</DynamicEnumProperty>')
end
function m.beforeTargets(r)
p.push('<DynamicEnumProperty')
p.w('Name="%sBeforeTargets"', r.name)
p.w('Category="General"')
p.w('EnumProvider="Targets"')
p.w('IncludeInCommandLine="False">')
p.push('<DynamicEnumProperty.DisplayName>')
p.w('<sys:String>Execute Before</sys:String>')
p.pop('</DynamicEnumProperty.DisplayName>')
p.push('<DynamicEnumProperty.Description>')
p.w('<sys:String>Specifies the targets for the build customization to run before.</sys:String>')
p.pop('</DynamicEnumProperty.Description>')
p.push('<DynamicEnumProperty.ProviderSettings>')
p.push('<NameValuePair')
p.w('Name="Exclude"')
p.w('Value="^%sBeforeTargets|^Compute" />', r.name)
p.pop()
p.pop('</DynamicEnumProperty.ProviderSettings>')
p.push('<DynamicEnumProperty.DataSource>')
p.push('<DataSource')
p.w('Persistence="ProjectFile"')
p.w('HasConfigurationCondition="true" />')
p.pop()
p.pop('</DynamicEnumProperty.DataSource>')
p.pop('</DynamicEnumProperty>')
end
function m.commandLineTemplate(r)
p.push('<StringProperty')
p.w('Name="CommandLineTemplate"')
p.w('DisplayName="Command Line"')
p.w('Visible="False"')
p.w('IncludeInCommandLine="False" />')
p.pop()
end
function m.contentType(r)
p.push('<ContentType')
p.w('Name="%s"', r.name)
p.w('DisplayName="%s"', r.display or r.name)
p.w('ItemType="%s" />', r.name)
p.pop()
end
function m.dataSource(r)
p.push('<Rule.DataSource>')
p.push('<DataSource')
p.w('Persistence="ProjectFile"')
p.w('ItemType="%s" />', r.name)
p.pop()
p.pop('</Rule.DataSource>')
end
function m.executionDescription(r)
p.push('<StringProperty')
p.w('Name="ExecutionDescription"')
p.w('DisplayName="Execution Description"')
p.w('Visible="False"')
p.w('IncludeInCommandLine="False" />')
p.pop()
end
function m.fileExtension(r)
p.push('<FileExtension')
p.w('Name="*%s"', r.fileExtension)
p.w('ContentType="%s" />', r.name)
p.pop()
end
function m.inputs(r)
p.push('<StringListProperty')
p.w('Name="Inputs"')
p.w('Category="Command Line"')
p.w('IsRequired="true"')
p.w('Switch=" ">')
p.push('<StringListProperty.DataSource>')
p.push('<DataSource')
p.w('Persistence="ProjectFile"')
p.w('ItemType="%s"', r.name)
p.w('SourceType="Item" />')
p.pop()
p.pop('</StringListProperty.DataSource>')
p.pop('</StringListProperty>')
end
function m.outputs(r)
p.push('<StringListProperty')
p.w('Name="Outputs"')
p.w('DisplayName="Outputs"')
p.w('Visible="False"')
p.w('IncludeInCommandLine="False" />')
p.pop()
end
function m.ruleItem(r)
p.push('<ItemType')
p.w('Name="%s"', r.name)
p.w('DisplayName="%s" />', r.display or r.name)
p.pop()
end
function m.projectSchemaDefinitions(r)
p.push('<ProjectSchemaDefinitions xmlns="http://schemas.microsoft.com/build/2009/properties" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib">')
end

View File

@ -1583,8 +1583,9 @@
end end
function m.xmlDeclaration() function m.xmlDeclaration()
_p('<?xml version="1.0" encoding="utf-8"?>') p.xmlUtf8()
end end

View File

@ -1,10 +1,14 @@
-- ---
-- action.lua -- action.lua
-- Work with the list of registered actions. -- Work with the list of registered actions.
-- Copyright (c) 2002-2009 Jason Perkins and the Premake project -- Copyright (c) 2002-2014 Jason Perkins and the Premake project
-- ---
premake.action = {} premake.action = {}
local action = premake.action
local p = premake
-- --
@ -32,32 +36,32 @@
-- new entries here. -- new entries here.
-- --
premake.action.list = {} action._list = {}
-- --
-- Register a new action. -- Register a new action.
-- --
-- @param a -- @param act
-- The new action object. -- The new action object.
-- --
function premake.action.add(a) function action.add(act)
-- validate the action object, at least a little bit -- validate the action object, at least a little bit
local missing local missing
for _, field in ipairs({"description", "trigger"}) do for _, field in ipairs({"description", "trigger"}) do
if not a[field] then if not act[field] then
missing = field missing = field
end end
end end
if missing then if missing then
local name = a.trigger or "" local name = act.trigger or ""
error(string.format('action "%s" needs a %s', name, missing), 3) error(string.format('action "%s" needs a %s', name, missing), 3)
end end
-- add it to the master list -- add it to the master list
premake.action.list[a.trigger] = a action._list[act.trigger] = act
end end
@ -70,28 +74,28 @@
-- None. -- None.
-- --
function premake.action.call(name) function action.call(name)
local a = premake.action.list[name] local act = action._list[name]
-- TODO: remove this once everyone's had a chance to see for sln in p.solution.each() do
-- the deprecation warning if act.onsolution then
if _ACTION:endswith("ng") then act.onsolution(sln)
_ACTION = _ACTION:sub(1, -3)
end end
for prj in p.solution.eachproject(sln) do
for sln in premake.solution.each() do if act.onproject and not prj.external then
if a.onsolution then act.onproject(prj)
a.onsolution(sln)
end
for prj in premake.solution.eachproject(sln) do
if a.onproject and not prj.external then
a.onproject(prj)
end end
end end
end end
if a.execute then for rule in p.rules.each() do
a.execute() if act.onrule then
act.onrule(rule)
end
end
if act.execute then
act.execute()
end end
end end
@ -103,8 +107,8 @@
-- The current action, or nil if _ACTION is nil or does not match any action. -- The current action, or nil if _ACTION is nil or does not match any action.
-- --
function premake.action.current() function action.current()
return premake.action.get(_ACTION) return action.get(_ACTION)
end end
@ -117,13 +121,12 @@
-- The requested action, or nil if the action does not exist. -- The requested action, or nil if the action does not exist.
-- --
function premake.action.get(name) function action.get(name)
-- "Next-gen" actions are deprecated -- "Next-gen" actions are deprecated
if name and name:endswith("ng") then if name and name:endswith("ng") then
name = name:sub(1, -3) name = name:sub(1, -3)
end end
return action._list[name]
return premake.action.list[name]
end end
@ -131,18 +134,18 @@
-- Iterator for the list of actions. -- Iterator for the list of actions.
-- --
function premake.action.each() function action.each()
-- sort the list by trigger -- sort the list by trigger
local keys = { } local keys = { }
for _, action in pairs(premake.action.list) do for _, act in pairs(action._list) do
table.insert(keys, action.trigger) table.insert(keys, act.trigger)
end end
table.sort(keys) table.sort(keys)
local i = 0 local i = 0
return function() return function()
i = i + 1 i = i + 1
return premake.action.list[keys[i]] return act._list[keys[i]]
end end
end end
@ -154,13 +157,13 @@
-- The name of the action to activate. -- The name of the action to activate.
-- --
function premake.action.set(name) function action.set(name)
_ACTION = name _ACTION = name
-- Some actions imply a particular operating system -- Some actions imply a particular operating system
local action = premake.action.get(name) local act = action.get(name)
if action then if act then
_OS = action.os or _OS _OS = act.os or _OS
end end
end end
@ -168,7 +171,7 @@
-- --
-- Determines if an action supports a particular language or target type. -- Determines if an action supports a particular language or target type.
-- --
-- @param action -- @param act
-- The action to test. -- The action to test.
-- @param feature -- @param feature
-- The feature to check, either a programming language or a target type. -- The feature to check, either a programming language or a target type.
@ -176,17 +179,17 @@
-- True if the feature is supported, false otherwise. -- True if the feature is supported, false otherwise.
-- --
function premake.action.supports(action, feature) function action.supports(act, feature)
if not action then if not act then
return false return false
end end
if action.valid_languages then if act.valid_languages then
if table.contains(action.valid_languages, feature) then if table.contains(act.valid_languages, feature) then
return true return true
end end
end end
if action.valid_kinds then if act.valid_kinds then
if table.contains(action.valid_kinds, feature) then if table.contains(act.valid_kinds, feature) then
return true return true
end end
end end
@ -194,19 +197,20 @@
end end
-- --
-- Determines if an action supports a particular configuration. -- Determines if an action supports a particular configuration.
-- @return -- @return
-- True if the configuration is supported, false otherwise. -- True if the configuration is supported, false otherwise.
-- --
function premake.action.supportsconfig(action, cfg) function action.supportsconfig(act, cfg)
if not action then if not act then
return false return false
end end
if action.supportsconfig then if act.supportsconfig then
return action.supportsconfig(cfg) return act.supportsconfig(cfg)
end end
return true return true

View File

@ -6,24 +6,180 @@
premake.api = {} premake.api = {}
local api = premake.api local api = premake.api
local configset = premake.configset
local p = premake
local configset = p.configset
---
-- Set up a place to store the current active objects in each configuration
-- scope (e.g. solutions, projects, groups, and configurations). Initialize
-- it with a "root" container to contain the other containers, as well as the
-- global configuration settings which should apply to all of them.
-- --
-- Create a "root" configuration set, to hold the global configuration. Values -- TODO: this should be hidden, with a perhaps a read-only accessor to fetch
-- that are added to this set become available for all add-ons, solution, projects, -- individual scopes for testing.
-- and on down the line. ---
api.scope = {}
api.scope.root = p.containerClass.define("root"):new("root")
---
-- Register a new class of configuration container. A configuration container
-- can hold configuration settings, as well as child configuration containers.
-- Solutions, projects, and rules are all examples of containers.
-- --
-- @param def
-- The container definition; see premake.container.define().
-- @returns
-- The newly defined container class.
---
configset.root = configset.new() function api.container(def)
-- for now, everything inherits the root configuration
if not def.parent then
def.parent = "root"
end
-- register the new class; validation checks may cause a failure
local cc, err = p.containerClass.define(def)
if not cc then
error(err, 2)
end
-- create a global function to create new instances, e.g project()
_G[cc.name] = function(name)
return api._setScope(cc, name)
end
return cc
end
---
-- Return the currently active configuration container instance.
---
function api.currentContainer()
return api.scope.current or api.scope.root
end
---
-- Return the root container, which contains the global configuration and
-- all of the child containers (solutions, rules).
---
function api.rootContainer()
return api.scope.root
end
---
-- Recursively clear any child scopes for a container class. For example,
-- if a solution is being activated, clear the project and group scopes,
-- as those are children of solutions. If the root scope is made active,
-- all child scopes will be cleared.
---
function api._clearChildScopes(cc)
for ch in cc:eachChildClass() do
api.scope[ch.name] = nil
api._clearChildScopes(ch)
end
end
---
-- Activate a new configuration container, making it the target for all
-- subsequent configuration settings. When you call solution() or project()
-- to active a container, that call comes here (see api.container() for the
-- details on how that happens).
-- --
-- A place to store the current active objects in each configuration scope -- @param cc
-- (e.g. solutions, projects, groups, and configurations). -- The container class being activated, e.g. a project or solution.
-- -- @param name
-- The name of the container instance to be activated. If a container
-- (e.g. project) with this name does not already exist it will be
-- created. If name is not set, the last activated container of this
-- class will be made current again.
-- @return
-- The container instance.
---
function api._setScope(cc, name)
-- for backward compatibility, "*" activates the parent container
if name == "*" then
return api._setScope(cc.parent)
end
-- if name is not set, use whatever was last made current
local container
if not name then
container = api.scope[cc.name]
if not container then
error("no " .. cc.name .. " in scope", 3)
end
end
if not container then
-- all containers should be contained within a parent
local parent = api.scope[cc.parent.name]
if not parent then
error("no active " .. cc.parent.name, 3)
end
-- fetch (creating if necessary) the container
container = parent:fetchChild(cc, name)
if not container then
container = parent:createChild(cc, name, parent)
else
configset.addFilter(container, {}, os.getcwd())
end
end
-- clear out any active child container types
api._clearChildScopes(cc)
-- activate the container, as well as its ancestors
if not cc.placeholder then
api.scope.current = container
end
while container.parent do
api.scope[container.class.name] = container
container = container.parent
end
return api.scope.current
end
---
-- Find the closest active scope for the given container class. If no
-- exact instance of this container class is in scope, searches up the
-- class hierarchy to find the closest parent that is in scope.
--
-- @param cc
-- The container class to target.
-- @return
-- The closest available active container instance.
---
function api._target(cc)
while not api.scope[cc.name] do
cc = cc.parent
end
return api.scope[cc.name]
end
api.scope = { root = configset.root }
--- ---
@ -292,14 +448,47 @@
--- ---
-- Find the currently active configuration scope. -- Return the target container instance for a field.
-- --
-- @param field
-- The field being set or fetched.
-- @return -- @return
-- The currently active configuration set object. -- The currently active container instance if one is available, or nil if
-- active container is of the wrong class.
--- ---
function api.gettarget() function api.target(field)
return api.scope.project or api.scope.solution or api.scope.root -- if nothing is in scope, use the global root scope
if not api.scope.current then
return api.scope.root
end
-- use the current scope if it falls within the container hierarchy
-- of one of this field's target scopes; it is okay to set a value of
-- the parent of container (e.g. a project-level value can be set on a
-- solution, since it will be inherited).
local currentClass = api.scope.current.class
for i = 1, #field.scopes do
-- temporary: map config scope to the desired container class; will
-- go away once everything is ported to containers
local targetScope = field.scopes[i]
if targetScope == "config" then
targetScope = "project"
end
local targetClass = p.containerClass.get(targetScope)
repeat
if currentClass == targetClass then
return api.scope.current
end
targetClass = targetClass.parent
until not targetClass
end
-- this field's scope isn't available
return nil
end end
@ -322,7 +511,12 @@
end end
end end
local target = api.gettarget() local target = api.target(field)
if not target then
local err = string.format("unable to set %s in %s scope, should be %s", field.name, api.scope.current.class.name, table.concat(field.scopes, ", "))
error(err, 3)
end
local status, err = configset.store(target, field, value) local status, err = configset.store(target, field, value)
if err then if err then
error(err, 3) error(err, 3)
@ -342,7 +536,12 @@
-- return the current baked value -- return the current baked value
if not value then return end if not value then return end
local target = api.gettarget() local target = api.target(field)
if not target then
local err = string.format("unable to remove %s from %s scope, should be %s", field.name, api.scope.current.class.name, table.concat(field.scopes, ", "))
error(err, 3)
end
local hasDeprecatedValues = (type(field.deprecated) == "table") local hasDeprecatedValues = (type(field.deprecated) == "table")
-- Build a list of values to be removed. If this field has deprecated -- Build a list of values to be removed. If this field has deprecated
@ -478,6 +677,9 @@
--- ---
function api.reset() function api.reset()
-- Clear out all top level objects
api.scope.root.solutions = {}
-- Remove all custom variables -- Remove all custom variables
local vars = api.getCustomVars() local vars = api.getCustomVars()
for i, var in ipairs(vars) do for i, var in ipairs(vars) do
@ -854,7 +1056,7 @@
--- ---
function configuration(terms) function configuration(terms)
local target = api.gettarget() local target = api.currentContainer()
if terms then if terms then
if terms == "*" then terms = nil end if terms == "*" then terms = nil end
configset.addblock(target, {terms}, os.getcwd()) configset.addblock(target, {terms}, os.getcwd())
@ -870,7 +1072,7 @@
--- ---
function filter(terms) function filter(terms)
local target = api.gettarget() local target = api.currentContainer()
if terms then if terms then
if terms == "*" then terms = nil end if terms == "*" then terms = nil end
local ok, err = configset.addFilter(target, {terms}, os.getcwd()) local ok, err = configset.addFilter(target, {terms}, os.getcwd())
@ -882,60 +1084,6 @@
---
-- Begin a new solution group, which will contain any subsequent projects.
---
function group(name)
if name == "*" then name = nil end
api.scope.group = name
end
--
-- Set the current configuration scope to a project.
--
-- @param name
-- The name of the project. If a project with this name already
-- exists, it is made current, otherwise a new project is created
-- with this name. If no name is provided, the most recently defined
-- project is made active.
-- @return
-- The active project object.
--
function project(name)
if not name then
if api.scope.project then
name = api.scope.project.name
else
return nil
end
end
local sln = api.scope.solution
if not sln then
error("no active solution", 2)
end
local prj
if name ~= "*" then
prj = sln.projects[name]
if not prj then
prj = premake.project.new(sln, name)
prj.group = api.scope.group or ""
premake.solution.addproject(sln, prj)
end
end
api.scope.project = prj
configuration {}
return prj
end
-- --
-- Activates a reference to an external, non-Premake generated project. -- Activates a reference to an external, non-Premake generated project.
-- --
@ -955,41 +1103,6 @@
end end
--
-- Set the current configuration scope to a solution.
--
-- @param name
-- The name of the solution. If a solution with this name already
-- exists, it is made current, otherwise a new solution is created
-- with this name. If no name is provided, the most recently defined
-- solution is made active.
-- @return
-- The active solution object.
--
function solution(name)
if not name then
if api.scope.solution then
name = api.scope.solution.name
else
return nil
end
end
local sln
if name ~= "*" then
sln = premake.solution.get(name) or premake.solution.new(name)
end
api.scope.solution = sln
api.scope.project = nil
api.scope.group = nil
configuration {}
return sln
end
-- --
-- Define a new action. -- Define a new action.
@ -1124,7 +1237,12 @@
} }
end end
local cset = api.gettarget() 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 local current = cset.current
cset.current = cset.blocks[1] cset.current = cset.blocks[1]
api.callback(field, value) api.callback(field, value)

245
src/base/container.lua Normal file
View File

@ -0,0 +1,245 @@
---
-- container.lua
-- Implementation of configuration containers.
-- Copyright (c) 2014 Jason Perkins and the Premake project
---
local p = premake
p.containerClass = {}
p.container = {}
local container = p.container
-- The master list of registered container classes
container._classes = {}
---
-- The metatable allows container functions to be called with the ":" syntax,
-- and also allows API field values to be get and set as if they were direct
-- properties.
--
-- TODO: I think I'd like to get away from treating the fields as direct
-- properties on the containers (fine on the baked contexts later) and require
-- explicit fetch() and store() calls instead.
---
p.containerClass.__index = p.containerClass
p.container.__index = function(c, key)
local f = p.field.get(key)
if f then
return p.configset.fetch(c, f)
else
return p.container[key]
end
end
p.container.__newindex = function(c, key, value)
local f = p.field.get(key)
if f then
local status, err = p.configset.store(c, f, value)
if err then
error(err, 2)
end
else
rawset(c, key, value)
return value
end
end
---
-- A container class holds and operates on the metadata about a particular
-- type of container, including its name, parent container, and any child
-- containers. The container class is responsible for creating new instances
-- of its kind of containers.
--
-- @param def
-- A table containing metadata about the container class being created.
-- Supported keys are:
--
-- name (required)
-- The name of the new container class (e.g. "solution").
-- parent (optional)
-- The name of the parent container class (e.g. "solution").
-- init (optional)
-- An initializer function to call for new instances of this class.
-- Should accept the new instance object as its only argument.
--
-- Other keys are allowed and will be left intact.
--
-- @return
-- A new container class object if successful, else nil and an
-- error message.
---
function p.containerClass.define(def)
-- If the class has no special properties, allow it to be set using
-- just the class name instead of the whole key-value list.
if type(def) == "string" then
def = { name = def }
end
-- Sanity check my inputs
if not def.name then
return nil, "name is required"
end
if container._classes[def.name] then
return nil, "container class name already in use"
end
if def.parent and not container._classes[def.parent] then
return nil, "parent class does not exist"
end
-- Looks good, set myself up and add to master list
def._children = {}
def._listKey = def.name:plural()
setmetatable(def, p.containerClass)
container._classes[def.name] = def
-- Wire myself to my parent class
def.parent = container._classes[def.parent]
if def.parent then
table.insert(def.parent._children, def)
end
return def
end
---
-- Enumerate the child container class of a given class.
---
function p.containerClass:eachChildClass()
local children = self._children
local i = 0
return function ()
i = i + 1
if i <= #children then
return children[i]
end
end
end
---
-- Retrieve a container class by name.
--
-- @param name
-- The class name.
-- @return
-- The corresponding container class if found, nil otherwise.
---
function p.containerClass.get(name)
return container._classes[name]
end
---
-- Create a new instance of a container class.
--
-- @param name
-- The name for the container instance.
-- @return
-- A new instance of the container class.
---
function p.containerClass:new(name, parent)
local c = p.configset.new(parent)
setmetatable(c, p.container)
c.class = self
c.name = name
c.script = _SCRIPT
c.basedir = os.getcwd()
c.filename = name
if type(self.init) == "function" then
self.init(c)
end
return c
end
---
-- Create a new child container of the given class, with the specified name.
--
-- @param cc
-- The class of child container to be fetched.
-- @param key
-- A string key or array index for the container.
-- @param parent
-- The parent container instance.
-- @return
-- The child container instance.
---
function container:createChild(cc, key, parent)
self[cc._listKey] = self[cc._listKey] or {}
local list = self[cc._listKey]
local child = cc:new(key, parent)
child[parent.class.name] = parent -- i.e. child.solution = sln
table.insert(list, child)
list[key] = child
return child
end
---
-- Return an iterator for the child containers of a particular class.
--
-- @param cc
-- The class of child container to be enumerated.
---
function container:eachChild(cc)
local children = self[cc._listKey] or {}
local i = 0
return function ()
i = i + 1
if i <= #children then
return children[i]
end
end
end
---
-- Fetch the child container with the given container class and instance name.
--
-- @param cc
-- The class of child container to be fetched.
-- @param key
-- A string key or array index for the container.
-- @return
-- The child container instance.
---
function container:fetchChild(cc, key)
self[cc._listKey] = self[cc._listKey] or {}
return self[cc._listKey][key]
end

View File

@ -81,6 +81,13 @@
f._kind = kind f._kind = kind
-- Make sure scope is always an array; don't overwrite old value
if type(f.scope) == "table" then
f.scopes = f.scope
else
f.scopes = { f.scope }
end
-- All fields must have a valid store() function -- All fields must have a valid store() function
if not field.accessor(f, "store") then if not field.accessor(f, "store") then
return nil, "invalid field kind '" .. f._kind .. "'" return nil, "invalid field kind '" .. f._kind .. "'"
@ -250,6 +257,7 @@
end end
function field.merge(f, current, value) function field.merge(f, current, value)
local processor = field.accessor(f, "merge") local processor = field.accessor(f, "merge")
if processor then if processor then

View File

@ -6,9 +6,10 @@
premake.fileconfig = {} premake.fileconfig = {}
local fileconfig = premake.fileconfig local p = premake
local context = premake.context local fileconfig = p.fileconfig
local project = premake.project local context = p.context
local project = p.project
-- --
@ -171,7 +172,7 @@
function fileconfig.hasFileSettings(fcfg) function fileconfig.hasFileSettings(fcfg)
for key, field in pairs(premake.fields) do for key, field in pairs(premake.fields) do
if field.scope == "config" then if field.scopes[1] == "config" then
local value = fcfg[field.name] local value = fcfg[field.name]
if value then if value then
if type(value) == "table" then if type(value) == "table" then

View File

@ -10,29 +10,41 @@
-- --
premake.oven = {} premake.oven = {}
local oven = premake.oven local oven = premake.oven
local solution = premake.solution
local project = premake.project local p = premake
local config = premake.config local solution = p.solution
local fileconfig = premake.fileconfig local project = p.project
local configset = premake.configset local config = p.config
local context = premake.context local fileconfig = p.fileconfig
local configset = p.configset
local context = p.context
---
-- Traverses the entire container hierarchy built up by the project scripts,
-- filters, merges, and munges the project settings based on the current
-- runtime environment, and returns a new container hierarchy with the end
-- result. This result will then get handed off to the current action to
-- do whatever it is it needs to do, like generate project files.
-- --
-- Iterates through all of the current solutions, bakes down their contents, -- @param root
-- and then replaces the original solution object with the baked result. -- The top level or root container to be baked.
-- This is the entry point to the whole baking process, which happens after -- @return
-- the scripts have run, but before the project files are generated. -- ???
-- ---
function oven.bake() function oven.bake(root)
local result = {} local result = {}
for i, sln in ipairs(solution.list) do
local root = p.api.rootContainer()
root.solutions = root.solutions or {}
for i, sln in ipairs(root.solutions) do
result[i] = oven.bakeSolution(sln) result[i] = oven.bakeSolution(sln)
end end
solution.list = result
root.solutions = result
end end
@ -94,6 +106,7 @@
-- store that for future reference -- store that for future reference
local projects = {} local projects = {}
sln.projects = sln.projects or {}
for i, prj in ipairs(sln.projects) do for i, prj in ipairs(sln.projects) do
projects[i] = oven.bakeProject(prj, ctx) projects[i] = oven.bakeProject(prj, ctx)
projects[prj.name] = projects[i] projects[prj.name] = projects[i]

View File

@ -169,6 +169,16 @@
end end
---
-- Is this a type of file that can be linked?
---
function path.islinkable(fname)
return path.hasextension(fname, { ".o", ".obj", ".a", ".lib", ".so" })
end
-- --
-- Returns true if the filename represents an object file. -- Returns true if the filename represents an object file.
-- --

View File

@ -7,6 +7,8 @@
local solution = premake.solution local solution = premake.solution
local project = premake.project local project = premake.project
local config = premake.config local config = premake.config
local field = premake.field
-- Store captured output text for later testing -- Store captured output text for later testing
@ -135,7 +137,7 @@
-- Used by the actions to generate solution and project files. -- Used by the actions to generate solution and project files.
-- --
-- @param obj -- @param obj
-- A solution or project object; will be based to the callback function. -- A solution or project object; will be passed to the callback function.
-- @param ext -- @param ext
-- An optional extension for the generated file, with the leading dot. -- An optional extension for the generated file, with the leading dot.
-- @param callback -- @param callback
@ -144,7 +146,7 @@
-- --
function premake.generate(obj, ext, callback) function premake.generate(obj, ext, callback)
local fn = premake.project.getfilename(obj, ext) local fn = premake.filename(obj, ext)
printf("Generating %s...", path.getrelative(os.getcwd(), fn)) printf("Generating %s...", path.getrelative(os.getcwd(), fn))
local f, err = io.open(fn, "wb") local f, err = io.open(fn, "wb")
@ -160,6 +162,34 @@
---
-- Returns the full path a file generated from any of the project
-- objects (project, solution, rule).
--
-- @param obj
-- The project object being generated.
-- @param ext
-- An optional extension for the generated file, with the leading dot.
-- @param callback
-- The function responsible for writing the file; will receive the
-- project object as its only argument.
---
function premake.filename(obj, ext)
local fname = obj.location
if ext and not ext:startswith(".") then
fname = path.join(fname, ext)
else
fname = path.join(fname, obj.filename)
if ext then
fname = fname .. ext
end
end
return fname
end
--- ---
-- Sets the output indentation parameters. -- Sets the output indentation parameters.
-- --
@ -380,23 +410,28 @@
-- --
function premake.validateScopes(cfg, expected, ctx) function premake.validateScopes(cfg, expected, ctx)
for name, field in pairs(premake.fields) do for f in field.each() do
local okay = false -- Pull out the project level scope (this will get cleaned up when
-- the project objects move to the new container API)
-- skip fields that are at or below the expected scope local scope
if field.scope == "config" or field.scope == expected then if f.scopes[1] ~= "rule" then
okay = true scope = f.scopes[1]
end end
-- Skip fields that are at or below the expected scope. Config-
-- level fields are the most general (can be applied to projects
-- or solutions) and so can never be out of scope.
local okay = (not scope or scope == "config" or scope == expected)
-- this one needs to checked -- this one needs to checked
if not okay then if not okay then
okay = premake.field.compare(field, cfg[field.scope][name], cfg[name]) okay = field.compare(f, cfg[scope][f.name], cfg[f.name])
end end
-- found a problem? -- found a problem?
if not okay then if not okay then
local key = "validate." .. field.name local key = "validate." .. f.name
premake.warnOnce(key, "'%s' on %s '%s' differs from %s '%s'; may be set out of scope", name, expected, cfg.name, field.scope, cfg[field.scope].name) premake.warnOnce(key, "'%s' on %s '%s' differs from %s '%s'; may be set out of scope", f.name, expected, cfg.name, scope, cfg[scope].name)
end end
end end
@ -435,6 +470,18 @@
---
-- Write a opening XML element for a UTF-8 encoded file. Used by
-- several different files for different actions, so makes sense
-- to have a common call for it.
---
function premake.xmlUtf8()
premake.outln('<?xml version="1.0" encoding="utf-8"?>')
end
-- --
-- These are the output shortcuts that I used before switching to the -- These are the output shortcuts that I used before switching to the
-- indentation-aware calls above. They are still in use all over the -- indentation-aware calls above. They are still in use all over the

View File

@ -6,35 +6,29 @@
premake.project = {} premake.project = {}
local project = premake.project local project = premake.project
local configset = premake.configset
local context = premake.context local p = premake
local tree = premake.tree local tree = p.tree
--
-- Create a new project object.
--
-- @param sln
-- The solution object to contain the new project.
-- @param name
-- The new project's name.
-- @return
-- A new project object, contained by the specified solution.
--
function project.new(sln, name) ---
local prj = configset.new(sln) -- Register a new container class to represent projects.
setmetatable(prj, configset.metatable(prj)) ---
prj.name = name local _prjClass = p.api.container {
prj.solution = sln name = "project",
prj.script = _SCRIPT parent = "solution",
prj.basedir = os.getcwd() init = function(prj)
prj.filename = name prj.uuid = os.uuid(prj.name)
prj.uuid = os.uuid(name) if p.api.scope.group then
prj.group = p.api.scope.group.name
return prj else
prj.group = ""
end end
end
}
-- --
@ -210,32 +204,17 @@
-- ---
-- Returns the file name for this project. Also works with solutions. -- Returns the file name for this project. Also works with solutions.
-- -- Deprecated 11 Aug 2014
-- @param prj ---
-- The project object to query.
-- @param ext
-- An optional file extension to add, with the leading dot. If provided
-- without a leading dot, it will treated as a file name.
-- @return
-- The absolute path to the project's file.
--
function project.getfilename(prj, ext) function project.getfilename(prj, ext)
local fn = prj.location return premake.filename(prj, ext)
if ext and not ext:startswith(".") then
fn = path.join(fn, ext)
else
fn = path.join(fn, prj.filename)
if ext then
fn = fn .. ext
end
end
return fn
end end
-- --
-- Return the first configuration of a project, which is used in some -- Return the first configuration of a project, which is used in some
-- actions to generate project-wide defaults. -- actions to generate project-wide defaults.

50
src/base/rules.lua Normal file
View File

@ -0,0 +1,50 @@
---
-- base/rules.lua
--
-- Defines rule sets for generated custom rule files.
--
-- Copyright (c) 2014 Jason Perkins and the Premake project
---
premake.rules = {}
local rules = premake.rules
local p = premake
---
-- Register a new container class to hold the rules.
---
local _ruleContainerClass = p.api.container {
name = "rule",
}
---
-- Iterate over the collection of rules in a session.
--
-- @returns
-- An iterator function.
---
function rules.each()
return p.api.rootContainer():eachChild(_ruleContainerClass)
end
---
-- Retrieve a rule set by name or numeric index.
--
-- @param key
-- The rule key, either a string name or integer index.
-- @returns
-- The rule set with the provided key.
---
function rules.fetch(key)
return p.api.rootContainer():fetchChild(_ruleContainerClass, key)
end

View File

@ -6,41 +6,26 @@
premake.solution = {} premake.solution = {}
local solution = premake.solution local solution = premake.solution
local project = premake.project
local configset = premake.configset local p = premake
local context = premake.context local tree = p.tree
local tree = premake.tree
-- The list of defined solutions (which contain projects, etc.)
solution.list = {} ---
-- Register a new container class to represent solutions.
---
local _slnClass = p.api.container {
name = "solution",
}
-- p.api.container {
-- Create a new solution and add it to the session. name = "group",
-- parent = "solution",
-- @param name placeholder = true,
-- The new solution's name. }
-- @return
-- A new solution object.
--
function solution.new(name)
sln = configset.new(configset.root)
setmetatable(sln, configset.metatable(sln))
sln.name = name
sln.projects = {}
sln.basedir = os.getcwd()
sln.filename = name
-- Add to master list keyed by both name and index
table.insert(premake.solution.list, sln)
premake.solution.list[name] = sln
return sln
end
-- --
@ -67,11 +52,13 @@
-- --
function solution.each() function solution.each()
local root = p.api.rootContainer()
local i = 0 local i = 0
return function () return function ()
i = i + 1 i = i + 1
if i <= #premake.solution.list then if i <= #root.solutions then
return premake.solution.list[i] return root.solutions[i]
end end
end end
end end
@ -153,24 +140,13 @@
-- --
function solution.get(key) function solution.get(key)
return premake.solution.list[key] local root = p.api.rootContainer()
if root.solutions then
return root.solutions[key]
end
end end
--
-- Returns the file name for this solution.
--
-- @param sln
-- The solution object to query.
-- @param ext
-- An optional file extension to add, with the leading dot.
-- @return
-- The absolute path to the solution's file.
--
solution.getfilename = project.getfilename
-- --
-- Retrieve the tree of project groups. -- Retrieve the tree of project groups.
@ -237,7 +213,7 @@
function solution.hascppproject(sln) function solution.hascppproject(sln)
for prj in solution.eachproject(sln) do for prj in solution.eachproject(sln) do
if project.iscpp(prj) then if p.project.iscpp(prj) then
return true return true
end end
end end
@ -258,7 +234,7 @@
function solution.hasdotnetproject(sln) function solution.hasdotnetproject(sln)
for prj in solution.eachproject(sln) do for prj in solution.eachproject(sln) do
if project.isdotnet(prj) then if p.project.isdotnet(prj) then
return true return true
end end
end end

View File

@ -61,3 +61,17 @@
end end
return n return n
end end
---
-- Return a plural version of a string.
---
function string:plural()
if self:endswith("y") then
return self:sub(1, #self - 1) .. "ies"
else
return self .. "s"
end
end

View File

@ -1,13 +1,13 @@
-- --
-- tests/project/test_filename.lua -- tests/base/test_filename.lua
-- Verify generation of project (and solution) filenames. -- Verify generation of project/solution/rule filenames.
-- Copyright (c) 2008-2012 Jason Perkins and the Premake project -- Copyright (c) 2008-2014 Jason Perkins and the Premake project
-- --
T.project_filename = {} local suite = test.declare("project_filename")
local suite = T.project_filename
local p = premake
local project = premake.project
-- --
@ -17,11 +17,11 @@
local sln local sln
function suite.setup() function suite.setup()
sln, prj = test.createsolution() sln = test.createsolution()
end end
local function prepare() local function prepare()
prj = premake.solution.getproject(sln, 1) prj = test.getproject(sln, 1)
end end
@ -31,7 +31,7 @@
function suite.isAbsolutePath() function suite.isAbsolutePath()
prepare() prepare()
test.isequal(os.getcwd(), path.getdirectory(project.getfilename(prj))) test.isequal(os.getcwd(), path.getdirectory(p.filename(prj)))
end end
@ -41,7 +41,7 @@
function suite.isProjectName_onNoFilename() function suite.isProjectName_onNoFilename()
prepare() prepare()
test.isequal("MyProject", path.getname(project.getfilename(prj))) test.isequal("MyProject", path.getname(p.filename(prj)))
end end
@ -52,7 +52,7 @@
function suite.doesUseFilename() function suite.doesUseFilename()
filename "Howdy" filename "Howdy"
prepare() prepare()
test.isequal("Howdy", path.getname(project.getfilename(prj))) test.isequal("Howdy", path.getname(p.filename(prj)))
end end
@ -62,7 +62,7 @@
function suite.doesUseExtension() function suite.doesUseExtension()
prepare() prepare()
test.isequal(".xc", path.getextension(project.getfilename(prj, ".xc"))) test.isequal(".xc", path.getextension(p.filename(prj, ".xc")))
end end
@ -72,7 +72,7 @@
function suite.worksWithSolution() function suite.worksWithSolution()
prepare() prepare()
test.isequal("MySolution", path.getname(project.getfilename(sln))) test.isequal("MySolution", path.getname(p.filename(sln)))
end end
@ -84,7 +84,7 @@
solution ("MySolution") solution ("MySolution")
filename ("Howdy") filename ("Howdy")
prepare() prepare()
test.isequal("MyProject", path.getname(project.getfilename(prj))) test.isequal("MyProject", path.getname(p.filename(prj)))
end end
@ -95,6 +95,5 @@
function suite.canOverrideFilename() function suite.canOverrideFilename()
prepare() prepare()
test.isequal("Makefile", path.getname(project.getfilename(prj, "Makefile"))) test.isequal("Makefile", path.getname(p.filename(prj, "Makefile")))
end end

View File

@ -83,38 +83,16 @@
-- Warn if a configuration value is set in the wrong scope. -- Warn if a configuration value is set in the wrong scope.
-- --
function suite.warns_onSolutionStringField_inProject()
solution "MySolution"
configurations { "Debug", "Release" }
project "MyProject"
kind "ConsoleApp"
language "C++"
startproject "MyProject"
premake.validate()
test.stderr("'startproject' on project")
end
function suite.warns_onSolutionStringField_inConfig() function suite.warns_onSolutionStringField_inConfig()
solution "MySolution" solution "MySolution"
configurations { "Debug", "Release" } configurations { "Debug", "Release" }
project "MyProject"
kind "ConsoleApp"
language "C++"
filter "Debug" filter "Debug"
startproject "MyProject" startproject "MyProject"
premake.validate()
test.stderr("'startproject' on config")
end
function suite.warns_onSolutionStringField_onlyWarnOnce()
solution "MySolution"
configurations { "Debug", "Release" }
project "MyProject" project "MyProject"
kind "ConsoleApp" kind "ConsoleApp"
language "C++" language "C++"
startproject "MyProject"
premake.validate() premake.validate()
test.notstderr("'startproject' on config") test.stderr("'startproject' on config")
end end
function suite.warns_onProjectStringField_inConfig() function suite.warns_onProjectStringField_inConfig()

230
tests/premake5.lua Normal file
View File

@ -0,0 +1,230 @@
--
-- tests/premake5.lua
-- Automated test suite for Premake 5.x
-- Copyright (c) 2008-2013 Jason Perkins and the Premake project
--
dofile("testfx.lua")
newoption {
trigger = "test",
description = "A suite or test to run"
}
newoption {
trigger = "profile",
description = "Profile execution times; saves to profile.txt"
}
if _OPTIONS["profile"] then
dofile("pepperfish_profiler.lua")
end
--
-- The test suites
--
-- Base API tests
dofile("test_dofile.lua")
dofile("test_string.lua")
dofile("base/test_configset.lua")
dofile("base/test_context.lua")
dofile("base/test_criteria.lua")
dofile("base/test_detoken.lua")
dofile("base/test_filename.lua")
dofile("base/test_include.lua")
dofile("base/test_option.lua")
dofile("base/test_os.lua")
dofile("base/test_override.lua")
dofile("base/test_path.lua")
dofile("base/test_premake_command.lua")
dofile("base/test_table.lua")
dofile("base/test_tree.lua")
dofile("base/test_uuid.lua")
-- Solution object tests
dofile("solution/test_eachconfig.lua")
dofile("solution/test_location.lua")
dofile("solution/test_objdirs.lua")
-- Project object tests
dofile("project/test_config_maps.lua")
dofile("project/test_eachconfig.lua")
dofile("project/test_getconfig.lua")
dofile("project/test_location.lua")
dofile("project/test_vpaths.lua")
-- Configuration object tests
dofile("config/test_linkinfo.lua")
dofile("config/test_links.lua")
dofile("config/test_targetinfo.lua")
-- Baking tests
dofile("oven/test_filtering.lua")
dofile("oven/test_objdirs.lua")
-- API tests
dofile("api/test_containers.lua")
dofile("api/test_directory_kind.lua")
dofile("api/test_list_kind.lua")
dofile("api/test_path_kind.lua")
dofile("api/test_register.lua")
dofile("api/test_string_kind.lua")
dofile("api/test_table_kind.lua")
-- Control system tests
dofile("test_premake.lua")
dofile("base/test_validation.lua")
-- Toolset tests
dofile("tools/test_dotnet.lua")
dofile("tools/test_gcc.lua")
dofile("tools/test_msc.lua")
dofile("tools/test_snc.lua")
-- Visual Studio 2005-2010 C# projects
dofile("actions/vstudio/cs2005/test_assembly_refs.lua")
dofile("actions/vstudio/cs2005/test_build_events.lua")
dofile("actions/vstudio/cs2005/test_compiler_props.lua")
dofile("actions/vstudio/cs2005/test_debug_props.lua")
dofile("actions/vstudio/cs2005/test_files.lua")
dofile("actions/vstudio/cs2005/test_icon.lua")
dofile("actions/vstudio/cs2005/test_output_props.lua")
dofile("actions/vstudio/cs2005/projectelement.lua")
dofile("actions/vstudio/cs2005/test_platform_groups.lua")
dofile("actions/vstudio/cs2005/test_project_refs.lua")
dofile("actions/vstudio/cs2005/projectsettings.lua")
-- Visual Studio 2005-2010 solutions
dofile("actions/vstudio/sln2005/test_dependencies.lua")
dofile("actions/vstudio/sln2005/test_header.lua")
dofile("actions/vstudio/sln2005/test_nested_projects.lua")
dofile("actions/vstudio/sln2005/test_projects.lua")
dofile("actions/vstudio/sln2005/test_platforms.lua")
-- Visual Studio 2002-2008 C/C++ projects
dofile("actions/vstudio/vc200x/test_assembly_refs.lua")
dofile("actions/vstudio/vc200x/test_build_steps.lua")
dofile("actions/vstudio/vc200x/test_configuration.lua")
dofile("actions/vstudio/vc200x/test_compiler_block.lua")
dofile("actions/vstudio/vc200x/test_debug_settings.lua")
dofile("actions/vstudio/vc200x/test_excluded_configs.lua")
dofile("actions/vstudio/vc200x/test_external_compiler.lua")
dofile("actions/vstudio/vc200x/test_external_linker.lua")
dofile("actions/vstudio/vc200x/test_files.lua")
dofile("actions/vstudio/vc200x/test_linker_block.lua")
dofile("actions/vstudio/vc200x/test_manifest_block.lua")
dofile("actions/vstudio/vc200x/test_nmake_settings.lua")
dofile("actions/vstudio/vc200x/test_platforms.lua")
dofile("actions/vstudio/vc200x/test_project.lua")
dofile("actions/vstudio/vc200x/test_project_refs.lua")
dofile("actions/vstudio/vc200x/test_resource_compiler.lua")
-- Visual Studio 2010 C/C++ projects
dofile("actions/vstudio/vc2010/test_assembly_refs.lua")
dofile("actions/vstudio/vc2010/test_build_events.lua")
dofile("actions/vstudio/vc2010/test_compile_settings.lua")
dofile("actions/vstudio/vc2010/test_config_props.lua")
dofile("actions/vstudio/vc2010/test_debug_settings.lua")
dofile("actions/vstudio/vc2010/test_excluded_configs.lua")
dofile("actions/vstudio/vc2010/test_extension_settings.lua")
dofile("actions/vstudio/vc2010/test_extension_targets.lua")
dofile("actions/vstudio/vc2010/test_globals.lua")
dofile("actions/vstudio/vc2010/test_header.lua")
dofile("actions/vstudio/vc2010/test_files.lua")
dofile("actions/vstudio/vc2010/test_filter_ids.lua")
dofile("actions/vstudio/vc2010/test_filters.lua")
dofile("actions/vstudio/vc2010/test_item_def_group.lua")
dofile("actions/vstudio/vc2010/test_link.lua")
dofile("actions/vstudio/vc2010/test_manifest.lua")
dofile("actions/vstudio/vc2010/test_nmake_props.lua")
dofile("actions/vstudio/vc2010/test_output_props.lua")
dofile("actions/vstudio/vc2010/test_project_configs.lua")
dofile("actions/vstudio/vc2010/test_project_refs.lua")
dofile("actions/vstudio/vc2010/test_prop_sheet.lua")
dofile("actions/vstudio/vc2010/test_resource_compile.lua")
-- Visual Studio 2012
dofile("actions/vs2012/test_csproj_common_props.lua")
dofile("actions/vs2012/test_csproj_project_element.lua")
dofile("actions/vs2012/test_csproj_project_props.lua")
dofile("actions/vs2012/test_csproj_targets.lua")
dofile("actions/vs2012/test_sln_header.lua")
dofile("actions/vs2012/test_vcxproj_clcompile.lua")
dofile("actions/vs2012/test_vcxproj_config_props.lua")
-- Visual Studio 2013
dofile("actions/vs2013/test_csproj_project_element.lua")
dofile("actions/vs2013/test_globals.lua")
dofile("actions/vs2013/test_sln_header.lua")
dofile("actions/vs2013/test_vcxproj_config_props.lua")
-- Makefile tests
dofile("actions/make/test_make_escaping.lua")
dofile("actions/make/test_make_tovar.lua")
-- Makefile solutions
dofile("actions/make/solution/test_config_maps.lua")
dofile("actions/make/solution/test_default_config.lua")
dofile("actions/make/solution/test_help_rule.lua")
dofile("actions/make/solution/test_project_rule.lua")
-- Makefile C/C++ projects
dofile("actions/make/cpp/test_clang.lua")
dofile("actions/make/cpp/test_file_rules.lua")
dofile("actions/make/cpp/test_flags.lua")
dofile("actions/make/cpp/test_make_pch.lua")
dofile("actions/make/cpp/test_make_linking.lua")
dofile("actions/make/cpp/test_objects.lua")
dofile("actions/make/cpp/test_ps3.lua")
dofile("actions/make/cpp/test_target_rules.lua")
dofile("actions/make/cpp/test_tools.lua")
dofile("actions/make/cpp/test_wiidev.lua")
-- Makefile C# projects
dofile("actions/make/cs/test_embed_files.lua")
dofile("actions/make/cs/test_flags.lua")
dofile("actions/make/cs/test_links.lua")
dofile("actions/make/cs/test_response.lua")
dofile("actions/make/cs/test_sources.lua")
newaction {
trigger = "test",
description = "Run the automated test suite",
execute = function ()
local focus = {}
if _OPTIONS["test"] then
focus = string.explode(_OPTIONS["test"] or "", ".", true)
end
local profile = _OPTIONS["profile"]
if profile == "" then profile = "time" end
local profiler
if profile then
profiler = newProfiler()
profiler:start()
end
passed, failed = test.runall(focus[1], focus[2])
if profile then
profiler:stop()
local outfile = io.open("profile.txt", "w+")
profiler:report(outfile)
outfile:close()
end
msg = string.format("%d tests passed, %d failed", passed, failed)
if (failed > 0) then
print(msg)
os.exit(5)
else
print(msg)
end
end
}

View File

@ -339,7 +339,6 @@
stderr_capture = nil stderr_capture = nil
premake.solution.list = { }
premake.clearWarnings() premake.clearWarnings()
premake.eol("\n") premake.eol("\n")
premake.escaper(nil) premake.escaper(nil)