premake/modules/vstudio/vs2010_rules_targets.lua
2017-06-19 13:12:05 -07:00

493 lines
9.8 KiB
Lua

---
-- vs2010_rules_targets.lua
-- Generate a Visual Studio 201x custom rules targets file.
-- Copyright (c) 2014 Jason Perkins and the Premake project
---
local p = premake
p.vstudio.vs2010.rules.targets = {}
local m = p.vstudio.vs2010.rules.targets
m.elements = {}
---
-- Entry point; generate the root <Project> element.
---
m.elements.project = function(r)
return {
p.vstudio.projectElement,
m.availableItemGroup,
m.computedProperties,
m.computeInputsGroup,
m.usingTask,
m.ruleTarget,
m.computeOutputTarget,
}
end
function m.generate(r)
p.xmlUtf8()
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 outputs property.
---
function m.computedProperties(r)
-- create shadow context.
local pathVars = p.rule.createPathVars(r, "%%(%s)")
local ctx = p.context.extent(r, { pathVars = pathVars })
-- now use the shadow context to detoken.
local buildoutputs = ctx.buildoutputs
-- write the output.
if buildoutputs and #buildoutputs > 0 then
local outputs = table.concat(buildoutputs, ";")
p.push('<ItemDefinitionGroup>')
p.push('<%s>', r.name)
p.x('<Outputs>%s</Outputs>', path.translate(outputs))
p.pop('</%s>', r.name)
p.pop('</ItemDefinitionGroup>')
end
end
---
-- Generate the computed input targets group.
---
m.elements.computeInputsGroup = function(r)
return {
m.computeCompileInputsTargets,
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.computeCompileInputsTargets(r)
p.push('<ComputeCompileInputsTargets>')
p.w('$(ComputeCompileInputsTargets);')
p.w('Compute%sOutput;', r.name)
p.pop('</ComputeCompileInputsTargets>')
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)
-- create shadow context.
local pathVars = p.rule.createPathVars(r, "%%(%s)")
local ctx = p.context.extent(r, { pathVars = pathVars })
-- now use the shadow context to detoken.
local buildoutputs = ctx.buildoutputs
local linkable, compileable
for i = 1, #buildoutputs do
if (path.islinkable(buildoutputs[i])) then
linkable = true
end
if (path.iscppfile(buildoutputs[i])) then
compileable = 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
if compileable then
p.push('<ClCompile', el)
p.w('Include="%%(%sOutputs.Identity)"', r.name)
p.w('Condition="\'%%(Extension)\'==\'.cc\' or \'%%(Extension)\'==\'.cpp\' or \'%%(Extension)\'==\'.cxx\' or \'%%(Extension)\'==\'.c\'" />')
p.pop()
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