【问题标题】:ItemGroup Item scope, alternatively "Why does MSBuild hate me?"ItemGroup 项目范围,或者“为什么 MSBuild 讨厌我?”
【发布时间】:2010-11-08 12:07:33
【问题描述】:

我有一个正在尝试在 TFS 上构建的解决方案。我想更新所有适当文件的版本,但我一直在努力完成这项工作。有很多关于如何做到这一点的链接,但由于一个小问题,它们都不适合我……范围。

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="DesktopBuild" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
    <Target Name="DesktopBuild">
        <CallTarget Targets="GetFiles"  />

        <Message Text="CSFiles: '@(CSFiles)'" />
    </Target>

    <Target Name="GetFiles">
        <ItemGroup>
            <CSFiles Include="**\AssemblyInfo.cs" />
        </ItemGroup>
        <Message Text="CSFiles: '@(CSFiles)'" />
    </Target>
</Project>

我的树是这样的:

  • test.proj
  • application.sln
  • 应用程序(文件夹)
    • main.cs
    • 属性(文件夹)
      • AssemblyInfo.cs

当我从解决方案文件夹运行“c:\Windows\Microsoft.NET\Framework\v3.5\MSBuild.exe test.proj”时...我得到以下输出:

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

Build started 7/6/2009 3:54:10 PM.
Project "D:\src\test.proj" on node 0 (default targets).
  CSFiles: 'application\Properties\AssemblyInfo.cs'
DesktopBuild:
  CSFiles: ''
Done Building Project "D:\src\test.proj" (default targets).


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

Time Elapsed 00:00:00.04

那么,如何使我的 ItemGroup 具有全局范围?编译器和 TeamBuild 使用的所有 Targets 文件都做同样的事情,而且它们似乎都是全局的……我不明白为什么这对我不起作用。

有什么帮助吗?

【问题讨论】:

  • 您是否正在尝试构建 test.proj 文件?我不确定我是否理解您为什么指定 AssemblyInfo.cs 而不是仅从项目文件构建。
  • 我构建了 test.proj 文件作为显示我的问题的最小示例。实际上,我正在尝试在 TFS 中构建我的多个解决方案文件。这只是为了说明我在 ItemGroups 和 Targets 中看到的范围界定行为。
  • 我希望我能投票支持所有试图提供帮助的人,但显然我太“新手”了。我只是想写一个字条,我非常感谢这里的每个人都花时间观察和思考这个问题。

标签: c# tfs msbuild scope tfsbuild


【解决方案1】:

您是否尝试过使用 DependsOnTarget 而不是 CallTarget?可能是 CallTarget 导致了范围问题。

【讨论】:

  • 好的,这似乎给了我更多信息。我可以使用 DependsOn 更改 ItemGroup 的范围,但它似乎不一致。似乎用dependon调用的目标的兄弟姐妹可以访问项目组,但父级从不这样做。太奇怪了。是否有任何地方显示范围规则的文档?我找不到它们,我想现在我必须使用复杂的依赖而不是调用来重写我的文件。这太疯狂了。
  • 我还没有看到。您是否尝试过将 ItemGroup 完全移出 Targets?你有什么不想这样做的理由吗?
  • 或者在外面初始化为空(用 Include="*.WontExist" 破解)
  • 我必须在 Target 中执行 ItemGroup,因为它在 TFS 构建中,我需要在 AfterGet 中提取文件...(我使用的是 BeforeCompile,但无论如何)还有 Thomas,我试过了,不行。它附加到局部范围实例的全局变量。无论您是否使用现有文件。
  • #blessYou(以及原问题的海报)
【解决方案2】:

前一个评论者是正确的,您应该将其更改为使用 DependsOnTargets 而不是使用 CallTarget 任务。您看到的是bug,而不是范围界定问题。 way to avoid 这个错误是使用 DependsOnTargets (无论如何这是一个更好的方法)。

赛义德·易卜拉欣·哈希米

我的书:Inside the Microsoft Build Engine : Using MSBuild and Team Foundation Build

【讨论】:

【解决方案3】:

如前所述,您应该使用 DependsOnTargets。我对 MSBuild 范围做了一些研究,你可以在我的博客上找到我的结果:http://blog.qetza.net/2009/10/23/scope-of-properties-and-item-in-an-msbuild-script/

问题似乎是项目的全局范围和目标的本地范围。进入目标时,复制全局范围,退出目标时,合并回本地范围。所以 CallTarget 不会获得修改后的本地范围值,但 DependsOnTargets 会因为第一个目标在进入第二个目标之前退出。

【讨论】:

    【解决方案4】:

    我们在构建中做了类似的事情。我们将版本作为命令行参数传递。

    在我们的 TFSBuild.proj 中,如果没有提供版本,我们将版本设置为 0.0.0.0:

    <!--Our assembly version. Pass it in from the command prompt like this: /property:Version=1.0.0.0-->
    <PropertyGroup>
        <Version>0.0.0.0</Version>
    </PropertyGroup>
    
    <PropertyGroup>
        <!--Used to ensure there is a newline before our text to not break the .cs files if there is no newline at the end of the file.-->
        <newLine>%0D%0A</newLine>
    

    然后我们这样做:

    <Target Name="BeforeCompile">
        <!--Update our assembly version. Pass it in from the command prompt like this: /property:Version=1.0.0.0-->
    
        <!--attrib needs to be run first to remove the read only attribute since files from tfs are read only by default.-->
        <Exec Command='attrib -R $(SolutionRoot)\Source\Project\GlobalAssemblyInfo.cs'  />
    
        <WriteLinesToFile File="$(SolutionRoot)\Source\Project\GlobalAssemblyInfo.cs"
                          Lines='$(newLine)[assembly: AssemblyVersion("$(Version)")]'/>
    
    </Target>
    

    【讨论】:

    • 仅供参考,Exists 并没有执行该代码似乎期望它执行的操作。 Exists 检查命名文件是否存在,而不是命名变量是否存在。您可能想要 Condition="'$(Version)'==''" 代替。见msdn.microsoft.com/en-us/library/7szfhaft.aspx
    • 这个技术爱好者很聪明。 :-) 他说了什么。文档标准方法是用单引号括起来并在周围放置大量空格... 另外,这种方法对我来说并不好。我更喜欢 MSBuild 社区任务方法来属性和正则表达式更新文件。我的问题是构建要更新的文件列表,因为我有动态位置。不过谢谢。 :-)
    • 谢谢克里斯。 :) 我们正在对 CI 环境进行大量工作,所以这一切在我看来都很新鲜。 ;)
    • 不错的技术。看来传递的命令行值无法在 PropertyGroups 中被覆盖。
    • @David 我不确定你的意思。你可以做你最初想要的(如果它没有在命令行上传递,则默认它),如下所示: 0.0.0.0 检查是否传入了 Version 属性,如果没有,将其设置为 0.0.0.0。如果您关闭 Condition 属性,它将无条件地覆盖命令行上传递的任何 ws。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    • 2010-09-05
    相关资源
    最近更新 更多