如何在不代表文件的项目上使用执行MSBuild批处理?

时间:2012-12-12 15:21:38

标签: msbuild

MSBuild文档在几个地方提示项目不一定与文件相同。

  

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

     

"Items are objects that typically represent files."

但是,我似乎无法找到任何项目不代表文件的示例。特别是,我想对一组非文件项进行批处理。但是我创建的每个项目,甚至是自定义构建任务,都会以某种方式获取类似文件的元数据(FullPath,RootDir,Filename,Extension等)。此外,我对将目标的输入设置为一组非文件的项目以及用作该目标的输出的内容的后果感到困惑。

是否有人使用非文件项在MSBuild中执行批处理?

修改

很抱歉花了这么长时间才拿出一个例子。我对事情了解得更多,但我仍然不确定(而且似乎完全缺乏关于此的文档)。这里的一切都让我记忆犹新;我现在不在我的工作电脑上,所以我无法验证它们。

根据我的经验,MSBuild不喜欢一次构建.sln文件的多个配置。所以,这个:

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

(编码分号是必要的,因此它不会尝试定义多个属性。)

产生这个:

"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]

因此,似乎应该可以使用批处理和项目来处理这个问题。

<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>

产生这个:

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=""
}

如您所见,这些项目附加了各种文件元数据。我不能删除Include属性,因为它是必需的,但我可以在自定义任务中合成项目。但是,当我这样做时,他们仍然以某种方式神奇地获得所有相同的文件元数据。

这有什么后果?由于我没有将这些指定为目标的输入或输出,文件元数据是否会导致任何问题?构建系统是否会跳过目标,或者构建超出其需要的内容,因为Items的FullPath元数据中指定的文件不存在?如果这些文件确实存在怎么办?它会引起任何问题吗?

2 个答案:

答案 0 :(得分:2)

我使用项目来构建多个解决方案,并使用它们执行一些“手动”任务,因此我定义了自己的项目:

<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>

然后我使用目标来获取信息并做必要的事情:

<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>

希望这有助于指明您所需的方向。

答案 1 :(得分:1)

棘手的问题。我是一个MSBuild菜鸟,发现自己最近需要了解批处理,所以我想分享一些我发现的东西。

总的来说,是的,似乎大多数地方你都看到有关ITaskItems的样本和讨论,它们往往是关于文件的。但是底层实现非常灵活,并且可以处理许多其他事情。就我而言,我一直在使用字符串和XML数据。

This MS article提供了非文件ItemGroup和元数据的一些很好的例子。

This article是我能找到的最好的总结,它讲述了物品的机制以及它们与物业的不同之处。它还涵盖了@和%语法,字符串和Items之间的转换,以及这些文件元数据属性的来源提示 - MSBuild针对它进行了优化。

每当您将某个接口用作任务的参数或其他任何东西时,该接口的默认实现某处。我的猜测是你的代码示例正在新建一些这些默认对象,它们定义了默认创建的元数据。如果你自己实现这个界面,我会打赌你可以改变这种行为。可能超出了问题的范围,但=)