【问题标题】:How can I make TeamCity take advantage of MSBuild's incremental build support?如何让 TeamCity 充分利用 MSBuild 的增量构建支持?
【发布时间】:2012-08-09 16:55:05
【问题描述】:

我正在设置 TeamCity(从 CruiseControl.NET 迁移),我正在努力让它通过 MSBuild 执行增量构建。

我有一个小的 .proj 文件,其中包含一个基本构建脚本,用于使用从 TeamCity 输入的一些参数来调用我的解决方案的构建。当我手动调用脚本时,MSBuild 的 Incremental Build 功能会启动并在后续运行时完全跳过构建。

通过 Team City 调用此脚本时,构建日志每次都会显示干净编译的输出。我在构建过程中观察了工作目录,可以看到之前构建的输出没有消失。

我还通过远程连接到服务器并从命令提示符运行 MSBuild,从该目录手动调用了构建脚本。以这种方式运行它会在第一次调用后触发预期的增量构建。

即使从仪表板开始构建而不进行任何更改,也会发生完整的重建。

我无法确定原因,但似乎有些东西给 MSBuild 的印象是它正在获得新的更改并导致它在每次运行时都执行重建。我在 TeamCity 文档中看不到太多可以解释这一点的内容 - 我的期望是,如果源代码控制系统没有更改,它就不会更新工作文件夹。

TeamCity 是否将某些参数传递给触发重建的构建过程?我可以查看这些参数吗?


检查了详细的 MSBuild 日志(/v:d 命令行开关)后,发生完全重建的原因是文件 .NETFramework,Version=v4.0.AssemblyAttributes.cs 在每次构建时都在 <Agent>\temp\buildTmp 目录中更新。

此文件通常位于%TMP%\.NETFramework,Version=v4.0.AssemblyAttributes.cs; TeamCity 正在更改本地临时目录环境变量以引用代理的临时文件夹。不幸的是,这个文件是由构建过程的Microsoft.Common.targets 部分在不存在时创建的。在每次构建之前删除“temp”文件会导致每次构建都会创建它,并在每个项目文件的构建中动态引用。

我需要找到一种方法来防止在每次构建时重新创建此文件。

【问题讨论】:

    标签: msbuild teamcity


    【解决方案1】:

    此问题的解决方法是自定义 MSBuild 过程以设置创建“目标框架 Moniker 程序集属性”文件(问题中提到的文件的正确名称)的路径。

    TargetFrameworkMonikerAssemblyAttributesPath 属性在 Microsoft.Common.targets 中定义,确定文件的创建位置。通过覆盖此属性,可以更改位置以使用不同的位置。

    这是一个可用于实现合适替换的脚本:

    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    
    <PropertyGroup>
        <PrepareForBuildDependsOn>
            $(PrepareForBuildDependsOn);
            _SetTargetFrameworkMonikerAssemblyAttributesPath
        </PrepareForBuildDependsOn>
    </PropertyGroup>
    
    <Target 
        Name="_SetTargetFrameworkMonikerAssemblyAttributesPath"
        Condition="'$(TEAMCITY_VERSION)' != ''">
    
        <PropertyGroup>
            <TargetFrameworkMonikerAssemblyAttributesDir
                Condition="'$(TargetFrameworkMonikerAssemblyAttributesDir)' == ''">
                $([MSBuild]::GetRegistryValue("HKEY_CURRENT_USER\Environment", "TMP"))
            </TargetFrameworkMonikerAssemblyAttributesDir>
            <TargetFrameworkMonikerAssemblyAttributesDir
                Condition="'$(TargetFrameworkMonikerAssemblyAttributesDir)' == ''">
                $([MSBuild]::GetRegistryValue("HKEY_CURRENT_USER\Environment", "TEMP"))
            </TargetFrameworkMonikerAssemblyAttributesDir>
            <TargetFrameworkMonikerAssemblyAttributesDir 
                Condition="'$(TargetFrameworkMonikerAssemblyAttributesDir)' == ''">
                $(USERPROFILE)
            </TargetFrameworkMonikerAssemblyAttributesDir>
            <TargetFrameworkMonikerAssemblyAttributesDir
                Condition="'$(TargetFrameworkMonikerAssemblyAttributesDir)' == ''">
                $([System.IO.Path]::Combine('$(WINDIR)', 'Temp'))
            </TargetFrameworkMonikerAssemblyAttributesDir>
            <TargetFrameworkMonikerAssemblyAttributesPath>
                $([System.IO.Path]::Combine('$(TargetFrameworkMonikerAssemblyAttributesDir)','$(TargetFrameworkMoniker).AssemblyAttributes$(DefaultLanguageSourceExtension)'))
            </TargetFrameworkMonikerAssemblyAttributesPath>
        </PropertyGroup>
    
        <Message Text="Target Framework Moniker Assembly Attributes path is &quot;$(TargetFrameworkMonikerAssemblyAttributesPath)&quot;" Importance="low" />
    
    </Target>
    

    仅当TEAMCITY_VERSION 被指定为属性时才会执行目标,这应该是在 TeamCity 代理正在执行构建时。

    注意:PropertyGroup 的子元素应分别位于一行。它们分布在多行以增加此处的可读性,但额外的换行符会导致脚本失败。

    当目标运行时,它会尝试根据注册表中定义的用户环境变量构建合适的路径,首先查找TMPTEMP,然后返回到用户的配置文件文件夹,最后是@ 987654328@目录。这与 System.Path.GetTempPath() 记录的顺序相匹配,并且应该导致行为匹配 TeamCity 之外的 MSBuild 执行。

    这应该保存为系统某处的 .targets 文件,并使用 &lt;Import&gt; 元素导入到 TeamCity 服务器正在构建的项目的 .csproj 文件中。我在我的 MSBuild 扩展目录 (C:\Program Files\MSBuild\) 下添加了脚本,并通过添加以下导入元素来引用它:

    <Import Project="$(MSBuildExtensionsPath)\TeamCity\TeamCity.Incremental.targets" />
    

    Import 元素的位置/顺序无关紧要,但我建议将其包含在应该出现在每个 .csproj 文件中的 &lt;Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /&gt; 之后。

    【讨论】:

    • 使用此脚本时出现以下错误:C:\Program Files (x86)\MSBuild\TeamCity\TeamCity.Incremental.targets(27, 9): error MSB4184: The expression "[System.IO.Path]::Combine( C:\Windows\system32\config\systemprofile\AppData\Local\Temp , .NETFramework,Version=v4.0.AssemblyAttributes.cs)" cannot be evaluated. Illegal characters in path.
    • 您是否注意到代码示例下的NOTE?这是最可能的原因。
    • 我以为我确实尊重了这些笔记,但我可能只是个痴人说梦。您能否发布或链接到您的最终版本?
    • 我希望我能再次投票。我不记得我做了什么来解决这个问题,所以搜索并找到了这个我已经在过去一段时间内投票过的答案。
    【解决方案2】:

    正如 Paul Turner 所提到的,调整 TargetFrameworkMonikerAssemblyAttributesPath 可以解决这个问题。我没有在 Microsoft 的构建系统脚本中与 High Magick 作斗争,而是在 TeamCity 项目参数中添加了一个环境变量来设置 TargetFrameworkMonikerAssemblyAttributesPath。

    在 TeamCity 的项目设置中,我将 env.TargetFrameworkMonikerAssemblyAttributesDir 设置为 %env.windir%\Temp

    【讨论】:

      【解决方案3】:

      TeamCity 2017.3 中仍然存在此问题。

      我想找到一种比接受的答案详细说明的更容易跟踪的解决方法,所以我做了以下操作:

      1. 我将.NETFramework,Version=v4.7.AssemblyAttributes.cs 文件的副本签入到我的 VCS 中
      2. 我在使用具有以下属性的 MSBuild 的构建配置中添加了一个新的构建步骤:
        • 运行器类型:命令行
        • 步骤名称:CopyAssemblyAttributesFile
        • 运行:自定义脚本
        • 自定义脚本copy "%system.teamcity.build.workingDir%\&lt;path_to_AssemblyAttributes.cs Dir&gt;\." "%env.TEMP%\."

      这将第一次复制我的 AssemblyAttributes 文件版本以及初始 VCS 签出时的时间戳,

      随后 MSBuild 似乎认为它是同一个文件,因为时间戳将保持一致,现在将正确执行增量构建,这可以从代理上的构建日志中验证。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-13
        • 2011-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多