3

The MSBuild documentation hints in several places that Items aren't necessarily the same as files.

"MSBuild items are inputs into the build system, and they typically represent files."

"Items are objects that typically represent files."

However, I can't seem to find any examples where Items do not represent files. In particular, I would like to perform batching over a set of non-file items. But every item that I create, even from a custom build task, somehow acquires file-like metadata (FullPath, RootDir, Filename, Extension, etc.). Furthermore, I'm confused about the ramifications of setting the Inputs of a target to a set of items that aren't files, and what to use as that target's Outputs.

Does anybody have an example of using non-file Items to perform batching in MSBuild?

edit

Sorry for taking so long to come up with an example. I understand things a bit more, but I'm still uncertain (and there seems to be a complete lack of documentation about this). Everything here is going off my recollection; I'm not at my work computer right now, so I can't verify any of it.

In my experience, MSBuild doesn't like to build multiple configurations of a .sln file in one go. So, this:

msbuild.exe SampleMSBuild.sln /p:Configuration=Debug%3BRelease

(The encoded semicolon being necessary so that it doesn't try to define multiple properties.)

Produces this:

"D:\src\SampleMSBuild\SampleMSBuild.sln" (default target) (1) ->
(ValidateSolutionConfiguration target) ->
  D:\src\SampleMSBuild\SampleMSBuild.sln.metaproj : error MSB4126: The 
  specified solution configuration "Debug;Release|Any CPU" is invalid. 
  Please specify a valid solution configuration using the Configuration 
  and Platform properties (e.g. MSBuild.exe Solution.sln 
  /p:Configuration=Debug /p:Platform="Any CPU") or leave those properties 
  blank to use the default solution configuration. 
  [D:\src\SampleMSBuild\SampleMSBuild.sln]

So, it seems like it should be possible to use batching and items to handle this.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" 
         DefaultTarget="Rebuild" 
         ToolsVersion="4.0">
  <ItemGroup>
    <Configurations Include="Debug" />-->
    <Configurations Include="Release" />-->
  </ItemGroup>

  <UsingTask TaskName="LogMetadata"
             TaskFactory="CodeTaskFactory"
             AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <Items ParameterType="Microsoft.Build.Framework.ITaskItem[]" 
             Required="true" />
    </ParameterGroup>
    <Task>
      <Code Type="Fragment" Language="cs">
        <![CDATA[
        foreach (var item in Items) {
          Console.Write(item.ItemSpec);
          Console.Write(" {");
          foreach (string metadataKey in item.MetadataNames) {
            Console.Write(metadataKey);
            Console.Write("=\"");
            Console.Write(item.GetMetadata(metadataKey).
                ToString().Replace("\"", "\\\""));
            Console.Write("\" ");
          }
          Console.WriteLine("}");
        }]]>
      </Code>
    </Task>
  </UsingTask>

  <Target Name="Rebuild">
    <LogMetadata Items="%(Configurations.Identity)" />
  </Target>
</Project>

Which produces this:

Debug {
  FullPath="D:\src\SampleMSBuild\Debug" 
  RootDir="D:\" 
  Filename="Debug" 
  Extension="" 
  RelativeDir="" 
  Directory="src\SampleMSBuild\" 
  RecursiveDir="" 
  Identity="Debug" 
  ModifiedTime="" 
  CreatedTime="" 
  AccessedTime="" 
}
Release {
  FullPath="D:\src\SampleMSBuild\Release" 
  RootDir="D:\" 
  Filename="Release" 
  Extension="" 
  RelativeDir="" 
  Directory="src\SampleMSBuild\" 
  RecursiveDir="" 
  Identity="Release" 
  ModifiedTime="" 
  CreatedTime="" 
  AccessedTime=""
}

As you can see, the items have all kinds of file metadata attached to them. I can't drop the Include attribute, since it's required, but I could synthesize the items in a custom task. HOWEVER, when I do that, they still somehow magically gain all the same file metadata.

What are the ramifications of this? Since I haven't specified these as Inputs or Outputs to a target, will the file metadata cause any problems? Will the build system skip over targets, or build more than it needs to, because the files specified in the Items' FullPath metadata do not exist? What if those files did exist? Would it cause any problems?

4

2 回答 2

2

I use items to build several solutions after each other and doing some "manual" task with them, therefore I define my own items:

<ItemGroup>
 <MergeConfigurations Include="project1\project1.SDK.sln">
  <MergeOutAssemblyName>product1.dll</MergeOutAssemblyName>
  <MergePrimaryAssemblyName>project1.Interfaces.dll</MergePrimaryAssemblyName>
  <SolutionBinaries>project1\bin\$(FlavorToBuild)</SolutionBinaries>
 </MergeConfigurations>

 <MergeConfigurations Include="project1\project1.Plugin.sln">
  <MergeOutAssemblyName>product1.dll</MergeOutAssemblyName>
  <MergePrimaryAssemblyName>project1.Interfaces.dll</MergePrimaryAssemblyName>
  <SolutionBinaries>project1\bin\plugin\$(FlavorToBuild)</SolutionBinaries>
 </MergeConfigurations>
<ItemGroup>

Then I use a target to take the information and do what is necessary:

<Target Name="MergeSolution"
      Inputs="%(MergeConfigurations.Identity)"
      Outputs="%(MergeConfigurations.Identity)\Ignore_this">

  <PropertyGroup>
   <MergeSolution>%(MergeConfigurations.Identity)</MergeSolution>
   <MergeOutAssemblyName>%(MergeConfigurations.MergeOutAssemblyName)</MergeOutAssemblyName>
   <MergePrimaryAssemblyName>%(MergeConfigurations.MergePrimaryAssemblyName)</MergePrimaryAssemblyName>
   <SolutionBinaries>%(MergeConfigurations.SolutionBinaries)</SolutionBinaries>
  </PropertyGroup>

  [....]
 </Target>

Hope this helps to point you in the direction you need.

于 2012-12-13T16:41:28.257 回答
1

Tricky question. I'm an MSBuild noob, and found myself needing to understand batching recently, so figured I'd share some of what I found.

In general, yes, it seems that most everywhere you see samples and discussions about ITaskItems they tend to be about files. But the underlying implementation is very flexible and can deal with many other things as well. In my case, I've been working with strings and XML data.

This MS article gives some great examples of non-file ItemGroups and metadata.

This article was the best summary I can find that talks about the mechanics of Items and how they are different than Properties. It also covers the whole bit about @ and % syntax, converting between strings and Items, and a hint as to where those file metadata properties are coming from - MSBuild is optimized for it.

Whenever you have an interface used as a parameter to a task or whatever, there is going to be a default implementation of that interface somewhere. My guess is that your code sample is newing up a number of these default objects under the hood and those define the metadata that are created by default. If you were to implement this interface yourself, I'll wager you could change this behavior. Probably beyond the scope of the question though =)

于 2013-02-26T18:02:57.710 回答