适用语言环境(本文)
CShrp及VB,注意C++环境稍有差异,有关适用于C++的MSBuild的信息,请参阅MSBuild(C++)。
概要
Microsoft 生成引擎是一个用于生成应用程序的平台。 此引擎(也称为 MSBuild)为项目文件提供了一个 XML 架构,用于控制生成平台处理和生成软件的方式。 Visual Studio 会使用 MSBuild,但 MSBuild 不依赖于 Visual Studio。 通过在项目或解决方案文件中调用 msbuild.exe 或 dotnet build,可以在未安装 Visual Studio 的环境中安排和生成产品。
Visual Studio 使用 MSBuild 来加载和生成托管项目。 Visual Studio 中的项目文件(.csproj、.vbproj、vcxproj 等)包含 MSBuild XML 代码,当你使用 IDE 来生成项目时,此代码就会运行。 Visual Studio 项目会导入所有必要的设置和生成过程来执行典型的开发工作,但你可以从 Visual Studio 内或通过使用 XML 编辑器对其进行扩展或修改。
一、整体解决方案(.sln)
通过sln为项目整体解决方案,由创建项目时VS自动生成。它管理加载多个项目配置信息:
<!--Example-->
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
<!--当前版本:Visual Sudio 2022 -->
VisualStudioVersion = 17.9.34714.143
<!--最低版本:Visual Sudio 2010 -->
MinimumVisualStudioVersion = 10.0.40219.1
<!-- 等号后面包含[项目名称][项目的相对路径][项目加载生成的GUID] -->
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mes.DataAcquire.WebApi", "Mes.DataAcquire.WebApi\Mes.DataAcquire.WebApi.csproj", "{E18B20D7-AE1F-4647-A335-2E0F68BC04AA}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Builds", "Builds", "{844A1604-1155-49A5-8C88-1E76114ED5E2}"
ProjectSection(SolutionItems) = preProject
<!-- 自定义全局编译信息 -->
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Global
<!-- 省略 -->
EndGlobal
具体请见官方文档:解决方案 (.sln) 文件
1、自定义生成(.props和.targets)
使用标准生成进程(导入 Microsoft.Common.props 和 Microsoft.Common.targets)的 MSBuild 项目有多个可用于自定义生成过程的扩展性挂钩 。
许多可自定义的生成操作由属性控制。 了解如何以及在何处设置属性值以获得所需的效果非常重要。 可以在命令行(和响应文件)、特殊文件(如 Directory.Build.props)、导入的文件或项目文件中设置属性。 了解属性的使用、设置或更改位置以及导入文件的顺序(包括从诸如 .NET SDK 之类的 SDK 隐式导入)非常重要。
有关属性的列表,请参阅 MSBuild 通用属性。
选择将属性添加到
.props
或.targets
文件MSBuild 依赖于导入顺序,属性(或 UsingTask 或目标)的最后一个定义是使用的定义。
使用显式导入时,可以随时从 .props 或 .targets 文件导入。 下面介绍广泛使用的约定:
- .props 文件在导入顺序的早期导入。
- .targets 文件在生成顺序的后期导入。
此约定由 <Project Sdk="SdkName"> 导入强制执行(即,在文件的所有内容之前首先导入 Sdk.props,然后在文件的所有内容之后最后导入 Sdk.targets)。
(1) 用户自定义选项文件(Directory.Build.props)
Directory.Build.props是用户定义的对目录下的项目提供自定义选项的文件 。 除非属性 ImportDirectoryBuildTargets 设为 false,否则该文件将从 Microsoft.Common.targets 自动导入 。
注意:是在任何项目上右键[新键项]才能创建,在解决方案上搜索不出来(我是这样的情况)
名称按右侧描述的文件名直接抄上去就行,添加后IDE自行会在解决方案下创建Builds目录,并生成该文件,同时会在sln解决方案中引用该自定义选项文件。
<!--Example-->
<Project>
<PropertyGroup>
<!-- 基础中间件输出路径:默认为[项目根路径\obj] -->
<BaseIntermediateOutputPath>$(MSBuildThisFileDirectory).vs\$(SolutionName)\Intermediate\$(MSBuildProjectName)\</BaseIntermediateOutputPath>
<OutputPath>$(MSBuildThisFileDirectory)\OutPut\</OutputPath>
<AppendTargetFrameworkToOutputPath>True</AppendTargetFrameworkToOutputPath>
</PropertyGroup>
</Project>
- $(MSBuildThisFileDirectory):sln解决方案所在的根路径
- $(SolutionName):sln解决方案所在的目录名
- $(MSBuildProjectName):当前项目名称(项目文件.csproj的主文件名)
具体请见官方档:MSBuild 保留属性和已知属性
- AppendTargetFrameworkToOutputPath:是否将目标框架名字对象 (TFM) 追加到输出路径(由 OutputPath 定义)。 .NET SDK 会自动将目标框架以及运行时标识符(如果有)追加到输出路径。
- AppendRuntimeIdentifierToOutputPath:是否将运行时标识符 (RID) 追加到输出路径。 .NET SDK 会自动将目标框架以及运行时标识符(如果有)追加到输出路径。
具体请见官方档:与发布相关的属性
2、 项目文件(.csproj或.vbproj)
<!--.csproj Example-->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- 输出类型:Windows应用程序-->
<OutputType>WinExe</OutputType>
<!--目标框架-->
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<!--程序图标-->
<ApplicationIcon>Theme\Images\App.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<!-- 排除目录 -->
<Compile Remove="obj\**" />
<EmbeddedResource Remove="obj\**" />
<None Remove="obj\**" />
<Page Remove="obj\**" />
</ItemGroup>
<ItemGroup>
<!--包引用-->
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.30" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.30" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="6.0.3" />
</ItemGroup>
<ItemGroup>
<!--项目引用-->
<ProjectReference Include="..\Mes.DataAcquire.Entity\Mes.DataAcquire.Entity.csproj" />
</ItemGroup>
<ItemGroup>
<!--资源引用-->
<Resource Include="Theme\Images\App.ico">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Resource>
<Resource Include="Theme\Images\icon.png" />
</ItemGroup>
<!--预生成事件-->
<!--<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="echo OutDir: $(OutDir)
echo ProjectDir: $(ProjectDir)
echo TargetPath: $(TargetPath)
echo AssemblyName $(AssemblyName)" />
</Target>-->
<!--生成后事件-->
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<!-- 调用批处理命令-->
<Exec Command="call "$(ProjectDir)zh-CN_Hans.bat" "$(ProjectDir)$(OutDir)zh-CN"" />
</Target>
</Project>
(1) 预生成事件
提示:变量值的打印输出,可以通过echo指令进行获得。
(2) 生成后事件
::Example
@echo off
setlocal
::设置源路径和目标路径
set SourcePath=C:\Users\1\source\repos\zh-CN
set TargetPath=%1
::预处理逻辑
endlocal
提示:将MsBuild预置属性变量转入批处理中,再做具体处理。