tags:

views:

1025

answers:

1

See this MSDN post for some background: Using metadata to call a target multiple times with different parameters

The solution put forward was to use metadata in a Task's Output attribute to force the batching of the task.

It so happens that our build step is partitioned across a few targets. My requirement is for the dependencies to run sequentially in a sort of inner loop.

I tried the concept out with the following script:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="BuildSolutions"
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
         ToolsVersion="3.5">
    <ItemGroup>
        <BuildFile Include="myscript.txt">
          <InstallerFileName>MyInstaller1.msi</InstallerFileName>
          <CustomTwiddleBit>true</CustomTwiddleBit>
          <OtherCustomTwiddleBit>false</OtherCustomTwiddleBit>
        </BuildFile>
        <BuildFile Include="myscript.txt">
          <InstallerFileName>MyInstaller2.msi</InstallerFileName>
          <CustomTwiddleBit>false</CustomTwiddleBit>
          <OtherCustomTwiddleBit>true</OtherCustomTwiddleBit>
        </BuildFile>
    </ItemGroup>

    <Target  
        Name="BuildInstallers" 
        Outputs="OutputDir\%(BuildFile.InstallerFileName)" 
        DependsOnTargets="Step3" 
    >
        <Exec Command="echo %(BuildFile.InstallerFileName)" />
    </Target>

    <Target Name="Step1">  
        <Exec Command="echo step 1 %(BuildFile.InstallerFileName)" /> 
    </Target> 

    <Target Name="Step2" 
            DependsOnTargets="Step1">  
        <Exec Command="echo step 2 %(BuildFile.InstallerFileName)" /> 
    </Target> 

    <Target Name="Step3" 
            DependsOnTargets="Step2">  
        <Exec Command="echo step 3 %(BuildFile.InstallerFileName)" /> 
    </Target>      
</Project>

The output was as follows:

Microsoft (R) Build Engine Version 3.5.30729.1  
[Microsoft .NET Framework, Version 2.0.50727.3053]  
Copyright (C) Microsoft Corporation 2007. All rights reserved.  

Build started 2/16/2009 20:41:14.  
Project "D:\Source\test\test.proj" on node 0 (BuildInstallers target(s)).  
  step 1 MyInstaller1.msi  
  step 1 MyInstaller2.msi  
Step2:  
  step 2 MyInstaller1.msi  
  step 2 MyInstaller2.msi  
Step3:  
  step 3 MyInstaller1.msi  
  step 3 MyInstaller2.msi  
BuildInstallers:  
  MyInstaller1.msi  
BuildInstallers:  
  MyInstaller2.msi  
Done Building Project "D:\Source\test\test.proj" (BuildInstallers target(s)).  


Build succeeded.  
    0 Warning(s)  
    0 Error(s)  

Time Elapsed 00:00:00.43

Any ideas how I might get the output to be like so:

step 1 MyInstaller1.msi
step 2 MyInstaller1.msi
step 3 MyInstaller1.msi

step 1 MyInstaller2.msi
step 2 MyInstaller2.msi
step 3 MyInstaller2.msi
+1  A: 

I sure see the problem here as

<Exec Command="echo step 1 %(BuildFile.InstallerFileName)" />

Will iterate again and again on the InstallerFileName output. I think you can call a custom target instead and that target go through each of your steps. Call this target from the main script with the MSBuild Task, something like this:

<MSBuild Projects="CustomTargets.proj" 
  Targets="BuildInstallers"
  Properties="BuildFile=%(BuildFile.InstallerFileName)" />

And in you BuildInstallers target you would use

<Target ="BuildInstallers" DependsOnTargets="Step3" >
</Target>

<Target Name="Step1">  
    <Exec Command="echo step 1 $(BuildFile)" /> 
</Target>

etc

haqwin
I was hoping to avoid having to make custom build steps, but that does seem like the most practical solution for now. I intentionally put the %(BuildFile.InstallerFileName) metadata on each task to force it to iterate. Dropping that only has each target called once due to MSBuild design.
Jeremy