指定生成事件 (C#)

使用生成事件指定在生成开始之前或生成完成后运行的命令。

指定生成事件

  1. 解决方案资源管理器中,选择要为其指定生成事件的项目。

  2. 在“项目”菜单上,单击“属性”

  3. 选择“生成事件”选项卡

  4. 预生成事件命令行 框中,指定生成事件的语法。

    注释

    如果项目是最新的且没有触发构建,则预构建事件不会运行。

  5. 生成后事件命令行 框中,指定生成事件的语法。

    注释

    在运行 .bat 文件的所有生成后命令之前添加 call 语句。 例如 call MyFile.batcall MyFile.bat call MyFile2.bat。 路径可以是输出文件夹的绝对路径,也可以是其相对路径。

  6. 运行生成后事件 框中,指定生成后事件应在何种条件下运行。

    注释

    若要添加冗长的语法,或从 预生成事件/生成后事件命令行对话框中选择任何生成宏,请单击省略号按钮(...)以显示编辑框。

  1. 解决方案资源管理器中,选择要为其指定生成事件的项目。

  2. 在“项目”菜单上,单击 {ProjectName} 属性(或在 解决方案资源管理器中,按 Alt+Enter)。

  3. 选择“生成”>“事件”

    显示“生成事件”设置的屏幕截图。

  4. 预生成事件 部分中,指定生成事件的语法。

    注释

    如果项目是最新的且没有触发构建,则预生成事件不会运行。

  5. 生成后事件 部分中,指定生成事件的语法。

    注释

    在运行 .bat 文件的所有生成后命令之前添加 call 语句。 例如 call MyFile.batcall MyFile.bat call MyFile2.bat。 路径可以是项目文件夹的绝对路径,也可以是其相对路径。

  6. 何时运行生成后事件 部分中,指定何种条件下需运行生成后事件。

创建构建事件命令

生成事件命令可以包含任何在命令提示符或 .bat 文件中有效的命令。 Windows 命令参考中记录了可用命令。 批处理文件的名称应先于 call,以确保执行所有后续命令。 批处理文件本身从输出文件夹运行,例如,bin/Debug。 如果您在所有配置中需要相同的批处理文件,可以将它放在与项目文件相同的文件夹中,然后使用相对路径,例如:call ../../prebuild.bat

可以通过输入 PowerShell MyPowerShellScript.ps1等命令来执行 PowerShell 脚本。 PowerShell 脚本的路径可能是绝对路径,也可能是相对于项目目录的路径。 需要确保在操作系统上为 PowerShell 脚本设置适当的执行策略,以便运行脚本。 请参阅关于执行策略

如果要使用另一个 shell(如 bash),通常使用与从 Windows 命令提示符启动 shell 脚本相同的命令语法。 使用第三方 shell 超出了本文档的范围,但 Stack Overflow 等站点可能很有帮助。

在项目文件中

执行前面的步骤时,Visual Studio 会通过添加 PreBuildPostBuild 目标以及执行所提供的步骤所需的 MSBuild 代码来修改项目文件。 可以打开项目文件并查看步骤。 修改项目文件中的步骤是可以的。 保存更改后,你将在项目属性的 生成 > 事件 部分中看到更改。

<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
  <Exec Command="call prebuild.bat" />
</Target>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
  <Exec Command="call postbuild.bat" />
</Target>

Exec 元素引用 MSBuild Exec 任务。 有关可用于自定义执行的其他参数的信息,请参阅 Exec 任务。 例如,可以使用 WorkingDirectory 设置运行可执行文件的文件夹。 默认值为包含项目文件的目录。

<Exec Command="call prebuild.bat" WorkingDirectory="$(OutDir)">

可以使用 MSBuild 属性(宏),例如上一示例中的 OutDir,正如本文后面 部分中所讨论的那样。

错误和其他输出

生成事件的输出将写入“输出窗口”的“生成”部分。 若要打开它,请选择 视图>其他窗口输出窗口,或按 Ctrl+Alt+O。 在“显示输出来源”旁边的下拉列表中,选择“生成”

如果预生成事件或生成后事件未成功完成,可通过使用除零 (0) 之外的代码退出事件操作来终止生成。 零退出代码指示作成功;任何其他退出代码都被视为错误。

如果预生成事件失败,可能会在 错误列表 窗口中看到如下所示的错误:

MSB3073    The command "call c:\source\repos\prebuild.bat" exited with code 1.

如果 错误列表 窗口中没有足够的信息,则可以尝试使用 输出窗口 查看完整的生成输出,包括批处理文件的任何输出。

小贴士

“错误列表”窗口只限于一行输出,即你为事件输入的第一行。 如果“错误列表”窗口输出对你很重要,请避免在事件中放置多行。 在 Windows 命令提示符或操作系统中创建批处理文件,然后使用 call mybatchfile.bat 进行事件处理。 在批处理文件本身中包含命令。

有关可在批处理文件中使用的命令的指南,请参阅 Windows 命令

常见的“宏”(实际为 MSBuild 属性)列在 MSBuild 通用属性。 对于 .NET SDK 项目(.NET Core 或 .NET 5 及更高版本),MSBuild 属性中列出了 Microsoft.NET.Sdk的其他属性。

在生成事件的脚本中,你可能想要引用某些项目级变量的值,例如项目的名称或输出文件夹的位置。 在早期版本的 Visual Studio 中,这些宏称为 。 在最新版本的 Visual Studio 中,等同于宏的是 MSBuild 属性。 MSBuild 是 Visual Studio 在执行生成时用于处理项目文件的生成引擎。 IDE 中的生成事件会在项目文件中产生一个 MSBuild 目标。 可以使用项目文件中目标中可用的任何 MSBuild 属性(例如,$(OutDir)$(Configuration))。 在这些事件中可用的 MSBuild 属性取决于在项目文件中隐式或显式导入的文件,例如 .props.targets 文件,以及项目文件中设置的属性,例如在 PropertyGroup 元素中设置。 请小心使用每个属性的准确拼写。 如果错报属性,则不会报告错误;相反,未定义属性的计算结果为空字符串。

例如,假设指定了预生成事件,如下所示:

显示预生成事件示例的屏幕截图。

该预构建事件会导致在你的项目文件中出现以下条目,称为 Target

  <Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="echo Configuration: $(Configuration)&#xD;&#xA;echo DevEnvDir: $(DevEnvDir)&#xD;&#xA;echo OutDir: $(OutDir)&#xD;&#xA;echo ProjectDir: $(ProjectDir)&#xD;&#xA;echo VisualStudioVersion: $(VisualStudioVersion)&#xD;&#xA;echo AssemblySearchPaths: $(AssemblySearchPaths)&#xD;&#xA;echo AssemblyName: $(AssemblyName)&#xD;&#xA;echo BaseIntermediateOutputPath: $(BaseIntermediateOutputPath)&#xD;&#xA;echo CscToolPath: $(CscToolPath)" />
  </Target>

生成事件作为一个目标出现,其中包含 Exec 任务和你指定为 Command 的输入。 换行符使用 XML 进行编码。

在此示例中生成项目时,预生成事件会输出某些属性的值。 在此示例中,$(CscToolPath) 不生成任何输出,因为它未定义。 它是一个可选属性,你可以在项目文件中定义,以提供 C# 编译器的自定义实例的路径(例如,如果测试了不同版本的 csc.exe或实验性编译器)。

生成事件的输出将写入生成输出,你可在“输出”窗口中找到该输出。 在“显示来自 的输出”下拉列表中,选择“生成”。

Build started...
1>------ Build started: Project: ConsoleApp4, Configuration: Debug Any CPU ------
1>You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
1>Configuration: Debug
1>DevEnvDir: C:\Program Files\Microsoft Visual Studio\2022\Preview\Common7\IDE\
1>OutDir: bin\Debug\net6.0\
1>ProjectDir: C:\source\repos\ConsoleApp4\ConsoleApp4\
1>VisualStudioVersion: 17.0
1>ALToolsPath:
1>AssemblySearchPaths: {CandidateAssemblyFiles};{HintPathFromItem};{TargetFrameworkDirectory};{RawFileName}
1>AssemblyName: ConsoleApp4
1>BaseIntermediateOutputPath: obj\
1>CscToolsPath:
1>Skipping analyzers to speed up the build. You can execute 'Build' or 'Rebuild' command to run analyzers.
1>ConsoleApp4 -> C:\source\repos\ConsoleApp4\ConsoleApp4\bin\Debug\net6.0\ConsoleApp4.dll

注释

某些场景需要比生成事件更复杂的构建操作。 例如,对于许多常见的代码生成方案,需要处理清理和重建操作,并且您可能希望为代码生成步骤启用增量构建,以便仅当输出与输入相比已过时时,才运行该步骤。 MSBuild 旨在智能处理所有这些方案。 考虑创建一个自定义目标,用于指定 AfterTargetsBeforeTargets 在生成过程中的特定点运行;为了在高级场景中进一步控制,可以考虑创建自定义任务,或查看可自定义生成的不同方式。

示例

  1. 在项目文件夹中创建名为 postbuild.bat 的批处理文件,内容如下:

    echo Copying output file %1 to %1.copy
    copy %1 %1.copy
    

    回想一下,在批处理文件中,%1 引用传入的第一个参数。

  2. 在项目属性的 生成后事件 部分中调用批处理文件,并使用 MSBuild 属性 $(TargetPath)传递参数。

    call postbuild.bat $(TargetPath)
    
  3. 生成项目并检查输出文件夹。 生成的程序集旁边应会显示复制的文件。 在“输出窗口”的“生成”部分中,应会看到批处理文件输出

    1>Output file is C:\source\repos\ConsoleApp-BuildEvents\ConsoleApp-BuildEvents\bin\Debug\net6.0\ConsoleApp-BuildEvents.dll
    1>        1 file(s) copied.
    ========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
    ========== Build started at 12:00 PM and took 00.723 seconds ==========