MSBuild:确保在任何其他构建步骤之前运行目标

13

我正在尝试更新AssemblyInfo.cs文件以反映项目的下一个发布版本,在进行任何其他构建步骤之前。

在我的项目文件中,我在结尾之前添加了以下内容:

<Import Project="$(ProjectDir)Properties\PublishVersion.proj" />

PublishVersion.proj的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<Target Name="BeforeBuild">
    <FormatVersion Version="$(ApplicationVersion)" Revision="$(ApplicationRevision)">
        <Output TaskParameter="OutputVersion" PropertyName="SetVersion" />
    </FormatVersion>
    <FileUpdate Files="$(ProjectDir)Properties\AssemblyInfo.cs"
       Regex="\d+\.\d+\.\d+\.\d+"
       ReplacementText="$(SetVersion)" />
</Target>
</Project>

现在它确实会在构建完成之前的某个位置执行,但绝对不是在构建开始之前执行,因为当我查看生成的exe文件时,它具有在AssemblyInfo.cs中BUILD开始之前的文件版本,但.application文件和清单文件引用了新版本。

最终的清单文件(在构建开始之前为1.0.0.0,在构建后为1.0.0.4):

<?xml version="1.0" encoding="utf-8"?>
<asmv1:assembly ...>
  <asmv1:assemblyIdentity name="BHTechSupport.exe" version="1.0.0.4" ... />
  ...
  <entryPoint>
    <assemblyIdentity name="BHTechSupport" version="1.0.0.0" ... />
    ...
  </entryPoint>
  ...
  <dependency>
    <dependentAssembly ... codebase="BHTechSupport.exe" ...>
      <assemblyIdentity name="BHTechSupport" version="1.0.0.0" ... />
      ...
    </dependentAssembly>
  </dependency>
  ...
</asmv1:assembly>

我该如何确保我的目标在所有其他操作之前执行?

对于 PublishVersion.proj 的更改有时似乎不会生效,我需要清理解决方案并重新启动 Visual Studio 才能生效。


1
看起来你正在使用Visual Studio 2010和MSBUILD 4.0,是吗?否则BeforeTargets将无法工作,你必须使用DependsOnTargets - sll
是的,我该如何指定构建目标依赖于我的目标? - Lawrence Ward
尝试在PublishVersion.proj中设置DefaultTargets="MyTarget" - sll
DefaultTargets="MyTarget"InitialTargets="MyTarget"在结果上没有区别。 - Lawrence Ward
@sll 把它变成一个答案,这样我就可以点赞了。 - jrummell
2个回答

10

也许你需要使用 BeforeBuild 目标。

那么,我该如何确保我的目标在所有其他操作之前执行?

要检查你的目标是否执行,可以将 MSBuild 项目生成输出详细程度 改为 诊断。在工具 > 选项 > 项目和解决方案 > 生成与运行下找到它。然后构建项目,在输出窗口中查找你的目标。

对 PublishVersion.proj 进行更改有时似乎不起作用,我需要清理解决方案并重新启动 Visual Studio 才能生效。

据我所知,Visual Studio 只加载目标文件一次,因此你必须重新加载你的项目才能看到结果。

更新 我不知道你的版本控制系统,但这不重要。无论如何,我尝试为你提供一个简单的示例。

using System;
using System.IO;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

namespace Foo.Build.Tasks {

    public sealed class GenerateVersion : Task {

        [Output]
        public ITaskItem[] GeneratedFiles { get; private set; }

        public override bool Execute() {
            string objPath = Path.Combine(Path.GetDirectoryName(this.BuildEngine3.ProjectFileOfTaskNode), "obj");
            string path = Path.Combine(objPath, "VersionInfo.cs");

            File.WriteAllText(path, @"using System.Reflection;
[assembly: AssemblyVersion(""2.0.0"")]");

            GeneratedFiles = new[] { new TaskItem(path) };

            return true;
        }

    }

}

前面的任务会生成一个包含AssemblyVersion元数据或其他你想要的内容的文件。

最后,你需要按照以下方式更改你的项目文件:

<UsingTask TaskName="Foo.Build.Tasks.GenerateVersion" AssemblyFile="Foo.Build.Tasks.dll" />

<Target Name="BeforeBuild">
  <GenerateVersion>
    <Output TaskParameter="GeneratedFiles" ItemName="Compile" />
  </GenerateVersion>
</Target>

@user1037993,当你重新构建项目时,会有一些额外的目标(比如BeforeRebuild)。无论如何,BeforeBuild是最初的任务之一,任何构建操作都将在此之后执行。 - m3kh
执行“Rebuild”应该导致“BeforeBuild”最终执行吗?无论如何,结果总是相同的。 - Lawrence Ward
在更改输出详细程度后检查输出后,我可以确认BeforeBuild确实在其他所有内容之前被调用,并且我的任务也是如此。我接受了你的答案,因为它回答了我的最初问题。所以现在似乎由于某种原因,在链接文件时捕获了初始程序集版本,并使用它。似乎没有定义任何具有初始程序集版本值的属性。现在怎么办? - Lawrence Ward
@LawrenceWard 已更新,希望这有所帮助。 - m3kh

3
如果您想让一个目标在每次构建的开始运行,无论调用什么最终目标(清理,还原,构建,发布),您可以使用Project元素的InitialTargets属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接