I have an MSBuild project file that generates some of its own targets, then imports them. It works nicely, except that msbuild
has to be run twice to do the build—once to generate the rules and again for them to be visible to finish the build. (The logic was ported from a Makefile
that itself only needed one run.)
Is it possible to run the generating target, then Import
, then run one of the generated targets?
The following listing is a trivialized version of the actual use case which exhibits the same behavior. (Beside the point, the actual case generates targets from a list of filenames of the pattern *-to-*.xsl
, using the name to automatically determine the dependency and destination.)
The objective is to make msbuild /t:SecondTarget
work on the first try instead of requiring a second.
<Project
xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
InitialTargets="AdditionalTargets"
ToolsVersion="4.0">
<!--
A trivial target-generating task. Presume something more useful for
the actual case.
-->
<UsingTask
TaskName="GenerateAdditionalTargets"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<Result ParameterType="System.String" Output="true"/>
</ParameterGroup>
<Task>
<Reference Include="System.Xml"/>
<Reference Include="System.Xml.Linq"/>
<Using Namespace="System"/>
<Using Namespace="System.Xml.Linq"/>
<Code Type="Fragment" Language="cs"><![CDATA[
var ns = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");
var collected = new XElement(ns + "Project",
new XAttribute("ToolsVersion", "4.0"),
new XElement(ns + "Target",
new XAttribute("Name", "SecondTarget"),
new XElement(ns + "Message",
new XAttribute("Text", "1.21GW?!")
)
)
);
Result = collected.ToString(SaveOptions.DisableFormatting);
]]></Code>
</Task>
</UsingTask>
<PropertyGroup>
<AdditionalTargets>additional.targets</AdditionalTargets>
</PropertyGroup>
<Target Name="AdditionalTargets">
<GenerateAdditionalTargets>
<Output TaskParameter="Result" PropertyName="Targets"/>
</GenerateAdditionalTargets>
<WriteLinesToFile File="$(AdditionalTargets)" Lines="$(Targets)" Overwrite="true"/>
</Target>
<Import Project="$(AdditionalTargets)" Condition="Exists('$(AdditionalTargets)')"/>
</Project>