# MSBuild 构建工具详解

MSBuild(Microsoft Build Engine)是 .NET 项目的官方构建工具,理解并善用 MSBuild 可以极大提升开发效率。


# 📋 什么是 MSBuild?

MSBuild 是 .NET 平台的构建引擎,负责:

  • ✅ 编译源代码
  • ✅ 管理项目依赖
  • ✅ 执行构建任务
  • ✅ 打包和发布
  • ✅ 运行测试
  • ✅ 自定义构建流程

核心理念: 一切皆项目(Project),一切皆目标(Target)


# 🎯 为什么使用 MSBuild?

优势 说明
跨平台 Windows/Linux/macOS 统一使用
高度可定制 自定义 Target 和 Task
与 .NET 集成 dotnet 命令底层就是 MSBuild
条件构建 根据配置/平台动态调整
增量构建 只构建变化的部分,提升速度
并行构建 多项目并行编译

# 📁 项目文件结构

# .csproj 文件示例

<Project Sdk="Microsoft.NET.Sdk">

  <!-- 项目属性 -->
  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <OutputType>Library</OutputType>
    <RootNamespace>DarkM.Lib.Utils.Core</RootNamespace>
    <AssemblyName>DarkM.Lib.Utils.Core</AssemblyName>
  </PropertyGroup>

  <!-- NuGet 包引用 -->
  <ItemGroup>
    <PackageReference Include="Dapper" Version="2.0.78" />
    <PackageReference Include="AutoMapper" Version="10.1.1" />
  </ItemGroup>

  <!-- 项目引用 -->
  <ItemGroup>
    <ProjectReference Include="..\Data\Data.csproj" />
  </ItemGroup>

  <!-- 文件包含 -->
  <ItemGroup>
    <None Include="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# Directory.Build.props(全局属性)

DarkM 使用 Directory.Build.props 统一配置所有项目:

<!-- /src/Framework/Directory.Build.props -->
<Project>
  <PropertyGroup>
    <!-- 作者信息 -->
    <Authors>DarkM</Authors>
    
    <!-- 忽略 XML 文档注释警告 -->
    <NoWarn>$(NoWarn);1591</NoWarn>
    
    <!-- 使用最新 C# 语言版本 -->
    <LangVersion>Latest</LangVersion>
    
    <!-- 命名空间前缀 -->
    <RootNamespacePrefix>DarkM.Lib</RootNamespacePrefix>
    
    <!-- 程序集名称 -->
    <AssemblyName>$(RootNamespacePrefix).$(MSBuildProjectName)</AssemblyName>
    <RootNamespace>$(AssemblyName)</RootNamespace>
    
    <!-- 生成 XML 文档 -->
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    
    <!-- 编译时生成 NuGet 包 -->
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    
    <!-- 包输出路径 -->
    <PackageOutputPath>$(SolutionDir)\_packages</PackageOutputPath>
    
    <!-- 公司信息 -->
    <Company>DarkM</Company>
    <Copyright>DarkM</Copyright>
    
    <!-- 项目地址 -->
    <PackageProjectUrl>http://dmdocs.woowis.com</PackageProjectUrl>
    <RepositoryUrl>https://glab.woowis.com/Woowis/DarkM</RepositoryUrl>
  </PropertyGroup>
</Project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

作用范围: 该文件所在目录及其所有子目录下的项目都会自动应用这些属性。

# Directory.Build.targets(全局目标)

<!-- 自定义构建目标 -->
<Project>
  <PropertyGroup>
    <ModulesDir>_modules\$(Id)_$(Code)</ModulesDir>
    <ModuleName>$(ModulesDir)\_module.json</ModuleName>
    <ModuleInfo>{"Id": "$(Id)","Name":"$(Name)","Code":"$(Code)","Version":"$(Version)"}</ModuleInfo>
  </PropertyGroup>

  <Target Name="ModulesBuild" AfterTargets="Build">
    <!-- 创建 modules 目录 -->
    <MakeDir Directories="$(ModulesDir)"/>
    
    <!-- 生成 module.json 文件 -->
    <WriteLinesToFile 
      File="$(ModuleName)" 
      Overwrite="true" 
      Lines="$(ModuleInfo)" />
  </Target>
</Project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 🔧 常用属性详解

# 项目基本信息

<PropertyGroup>
  <!-- 目标框架 -->
  <TargetFramework>net5.0</TargetFramework>
  <TargetFrameworks>netstandard2.0;net5.0;net462</TargetFrameworks>
  
  <!-- 输出类型 -->
  <OutputType>Library</OutputType>        <!-- 类库 -->
  <OutputType>Exe</OutputType>            <!-- 控制台应用 -->
  <OutputType>WinExe</OutputType>         <!-- Windows 应用 -->
  <OutputType>Web</OutputType>            <!-- Web 应用 -->
  
  <!-- 可执行文件 -->
  <IsPackable>true</IsPackable>          <!-- 是否可打包 NuGet -->
  <IsTestProject>false</IsTestProject>   <!-- 是否测试项目 -->
</PropertyGroup>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 编译选项

<PropertyGroup>
  <!-- 配置类型 -->
  <Configuration>Debug</Configuration>    <!-- Debug/Release -->
  
  <!-- 平台类型 -->
  <Platform>AnyCPU</Platform>             <!-- AnyCPU/x86/x64 -->
  
  <!-- 优化选项 -->
  <Optimize>true</Optimize>               <!-- Release 模式优化 -->
  <DebugType>portable</DebugType>         <!-- 调试符号类型 -->
  <DebugSymbols>true</DebugSymbols>       <!-- 生成调试符号 -->
  
  <!-- 警告设置 -->
  <WarningLevel>4</WarningLevel>          <!-- 警告级别 0-4 -->
  <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
  <WarningsNotAsErrors>1591</WarningsNotAsErrors>
  
  <!-- 语言特性 -->
  <LangVersion>latest</LangVersion>       <!-- 最新 C# 版本 -->
  <Nullable>enable</Nullable>             <!-- 启用可空引用类型 -->
  <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# NuGet 包元数据

<PropertyGroup>
  <!-- 包基本信息 -->
  <PackageId>DarkM.Lib.Utils.Core</PackageId>
  <Version>1.2.5</Version>
  <Authors>DarkM</Authors>
  <Company>DarkM</Company>
  <Description>DarkM 框架核心工具库</Description>
  <Copyright>Copyright © DarkM 2026</Copyright>
  
  <!-- 包配置 -->
  <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  <PackageOutputPath>$(SolutionDir)\_packages</PackageOutputPath>
  <PackageLicenseExpression>MIT</PackageLicenseExpression>
  <PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
  
  <!-- 包图标和文档 -->
  <PackageIcon>logo.png</PackageIcon>
  <PackageReadmeFile>README.md</PackageReadmeFile>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
  
  <!-- 项目地址 -->
  <PackageProjectUrl>http://dmdocs.woowis.com</PackageProjectUrl>
  <RepositoryUrl>https://glab.woowis.com/Woowis/DarkM</RepositoryUrl>
  <RepositoryType>git</RepositoryType>
  
  <!-- 标签 -->
  <PackageTags>darkm;utils;core;library</PackageTags>
  
  <!-- 发布配置 -->
  <IncludeSymbols>true</IncludeSymbols>
  <SymbolPackageFormat>snupkg</SymbolPackageFormat>
  <PublishRepositoryUrl>true</PublishRepositoryUrl>
</PropertyGroup>

<!-- 包含图标和 README -->
<ItemGroup>
  <None Include="..\logo.png" Pack="true" PackagePath="\" />
  <None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

# 条件属性

<PropertyGroup>
  <!-- 根据配置设置属性 -->
  <IsDebug Condition="'$(Configuration)' == 'Debug'">true</IsDebug>
  <IsRelease Condition="'$(Configuration)' == 'Release'">true</IsRelease>
</PropertyGroup>

<!-- 根据目标框架设置 -->
<PropertyGroup Condition="'$(TargetFramework)' == 'net5.0'">
  <DefineConstants>NET5_0</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
  <DefineConstants>NETSTANDARD2_0</DefineConstants>
</PropertyGroup>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 📦 Item 元素详解

# PackageReference(包引用)

<ItemGroup>
  <!-- 基础引用 -->
  <PackageReference Include="Dapper" Version="2.0.78" />
  
  <!-- 指定版本范围 -->
  <PackageReference Include="AutoMapper" Version="[10.1.1,11.0.0)" />
  
  <!-- 私有资源 -->
  <PackageReference Include="Internal.Lib" Version="1.0.0" PrivateAssets="All" />
  
  <!-- 开发依赖 -->
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
  
  <!-- 条件引用 -->
  <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" 
                    Condition="'$(TargetFramework)' == 'net5.0'" />
</ItemGroup>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# ProjectReference(项目引用)

<ItemGroup>
  <!-- 相对路径引用 -->
  <ProjectReference Include="..\Data\Data.csproj" />
  
  <!-- 绝对路径引用 -->
  <ProjectReference Include="$(SolutionDir)\src\Core\Core.csproj" />
  
  <!-- 带输出引用 -->
  <ProjectReference Include="..\Utils\Utils.csproj">
    <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
    <IncludeOutputGroupsInBuildOutput>BuiltProjectOutputGroup</IncludeOutputGroupsInBuildOutput>
  </ProjectReference>
</ItemGroup>
1
2
3
4
5
6
7
8
9
10
11
12
13

# Content 和 None(文件包含)

<ItemGroup>
  <!-- 内容文件(复制到输出目录) -->
  <Content Include="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </Content>
  
  <!-- 非编译文件 -->
  <None Include="README.md" />
  <None Include="*.targets" />
  
  <!-- 嵌入式资源 -->
  <EmbeddedResource Include="Resources\*.resx" />
  
  <!-- 全局文件(不复制到输出) -->
  <None Update="appsettings.*.json">
    <CopyToOutputDirectory>Never</CopyToOutputDirectory>
  </None>
</ItemGroup>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 🎯 Target(目标)详解

# 内置 Target

Restore        → 还原 NuGet 包
Build          → 编译项目
Rebuild        → 清理后编译
Clean          → 清理输出
Publish        → 发布项目
Pack           → 打包 NuGet
Test           → 运行测试
1
2
3
4
5
6
7

# 自定义 Target

<Project>
  <!-- 在编译前执行 -->
  <Target Name="BeforeBuild">
    <Message Text="开始编译..." Importance="high" />
  </Target>
  
  <!-- 在编译后执行 -->
  <Target Name="AfterBuild">
    <Message Text="编译完成!" Importance="high" />
  </Target>
  
  <!-- 自定义目标 -->
  <Target Name="GenerateModuleInfo" AfterTargets="Build">
    <!-- 创建目录 -->
    <MakeDir Directories="$(OutputPath)\modules" />
    
    <!-- 生成 JSON 文件 -->
    <WriteLinesToFile 
      File="$(OutputPath)\modules\module.json" 
      Lines='{"Name": "$(AssemblyName)", "Version": "$(Version)"}'
      Overwrite="true" />
    
    <!-- 包含到输出 -->
    <ItemGroup>
      <Content Include="$(OutputPath)\modules\module.json">
        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      </Content>
    </ItemGroup>
  </Target>
  
  <!-- 依赖其他目标 -->
  <Target Name="CustomTarget" DependsOnTargets="Build;GenerateModuleInfo">
    <Message Text="执行自定义目标" />
  </Target>
</Project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# Target 条件执行

<Target Name="ReleaseOnlyTarget" 
        Condition="'$(Configuration)' == 'Release'"
        AfterTargets="Build">
  <Message Text="仅 Release 模式执行" />
</Target>
1
2
3
4
5

# 🛠️ Task(任务)详解

# 常用 Task

<Target Name="ExampleTasks">
  <!-- 输出消息 -->
  <Message Text="编译版本:$(Version)" Importance="high" />
  
  <!-- 创建目录 -->
  <MakeDir Directories="$(OutputPath)\docs" />
  
  <!-- 复制文件 -->
  <Copy SourceFiles="README.md" 
        DestinationFolder="$(OutputPath)" />
  
  <!-- 复制多个文件 -->
  <Copy SourceFiles="@(Content)" 
        DestinationFolder="$(OutputPath)\content" />
  
  <!-- 删除文件 -->
  <Delete Files="$(OutputPath)\*.tmp" />
  
  <!-- 删除目录 -->
  <RemoveDir Directories="$(OutputPath)\temp" />
  
  <!-- 写入文件 -->
  <WriteLinesToFile 
    File="$(OutputPath)\version.txt" 
    Lines="$(Version)" 
    Overwrite="true" />
  
  <!-- 读取文件 -->
  <ReadLinesFromFile File="$(OutputPath)\version.txt">
    <Output TaskParameter="Lines" PropertyName="FileVersion" />
  </ReadLinesFromFile>
  
  <!-- 执行命令 -->
  <Exec Command="dotnet --version" />
  
  <!-- 条件判断 -->
  <Error Condition="'$(Version)' == ''" 
         Text="版本号不能为空!" />
  
  <!-- 警告 -->
  <Warning Condition="'$(Configuration)' == 'Debug'" 
           Text="Debug 模式,性能未优化!" />
</Target>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 自定义 Task(C#)

// GenerateModuleInfoTask.cs
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

public class GenerateModuleInfoTask : Task
{
    [Required]
    public string ModuleName { get; set; }
    
    [Required]
    public string OutputPath { get; set; }
    
    public override bool Execute()
    {
        try
        {
            var json = $"{{\"name\":\"{ModuleName}\"}}";
            File.WriteAllText(OutputPath, json);
            Log.LogMessage($"生成模块信息:{ModuleName}");
            return true;
        }
        catch (Exception ex)
        {
            Log.LogError($"生成失败:{ex.Message}");
            return false;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

在项目中注册使用:

<UsingTask TaskName="GenerateModuleInfoTask" 
           AssemblyFile="tasks/GenerateModuleInfoTask.dll" />

<Target Name="GenerateInfo">
  <GenerateModuleInfoTask 
    ModuleName="DarkM.Utils" 
    OutputPath="$(OutputPath)\module.json" />
</Target>
1
2
3
4
5
6
7
8

# 🚀 命令行使用

# 基本命令

# 编译项目
dotnet build

# 编译 Release 版本
dotnet build -c Release

# 编译指定框架
dotnet build -f net5.0

# 编译多框架
dotnet build -f net5.0 -f netstandard2.0

# 清理
dotnet clean

# 重新编译
dotnet build --no-incremental

# 还原包
dotnet restore

# 打包 NuGet
dotnet pack -c Release

# 发布
dotnet publish -c Release -r win-x64

# 运行测试
dotnet test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# MSBuild 命令

# 使用 MSBuild 编译
msbuild DarkM.sln

# 指定配置
msbuild DarkM.sln /p:Configuration=Release

# 指定目标
msbuild DarkM.sln /t:Rebuild

# 并行构建
msbuild DarkM.sln /m:4

# 详细日志
msbuild DarkM.sln /v:detailed

# 只编译变化的项目
msbuild DarkM.sln /t:Build /p:UseIncrementalCompilation=true

# 生成二进制日志(用于分析)
msbuild DarkM.sln /bl

# 查看二进制日志
msbuildlog DarkM.binlog
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 常用参数

参数 说明 示例
/p: 设置属性 /p:Configuration=Release
/t: 指定目标 /t:Clean;Build
/m: 并行构建 /m:4
/v: 日志详细度 /v:minimal
/bl: 二进制日志 /bl:build.binlog
/restore: 自动还原 /restore:true
/property: 设置属性 /property:Version=1.0.0

# 📊 DarkM 实战配置

# 完整 .csproj 示例

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <!-- 目标框架 -->
    <TargetFrameworks>netstandard2.0;net5.0</TargetFrameworks>
    
    <!-- 输出类型 -->
    <OutputType>Library</OutputType>
    
    <!-- 包信息 -->
    <PackageId>DarkM.Lib.Data.Core</PackageId>
    <Version>1.2.5</Version>
    <Authors>DarkM</Authors>
    <Description>DarkM 数据访问核心库</Description>
    <PackageTags>darkm;data;orm;dapper</PackageTags>
    
    <!-- 编译选项 -->
    <LangVersion>latest</LangVersion>
    <Nullable>enable</Nullable>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
    
    <!-- Source Link -->
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <IncludeSymbols>true</IncludeSymbols>
    <SymbolPackageFormat>snupkg</SymbolPackageFormat>
  </PropertyGroup>

  <!-- 条件属性 -->
  <PropertyGroup Condition="'$(Configuration)' == 'Debug'">
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)' == 'Release'">
    <DefineConstants>RELEASE</DefineConstants>
    <DebugType>portable</DebugType>
    <Optimize>true</Optimize>
  </PropertyGroup>

  <!-- 包引用 -->
  <ItemGroup>
    <PackageReference Include="Dapper" Version="2.0.78" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" />
    <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
  </ItemGroup>

  <!-- 项目引用 -->
  <ItemGroup>
    <ProjectReference Include="..\Utils\Utils.Core\Utils.Core.csproj" />
  </ItemGroup>

  <!-- 自定义目标 -->
  <Target Name="GenerateVersionInfo" AfterTargets="Build" Condition="'$(Configuration)' == 'Release'">
    <WriteLinesToFile 
      File="$(OutputPath)\version.txt" 
      Lines="Version: $(Version)&#10;Build: $([System.DateTime]::Now.ToString('yyyy-MM-dd HH:mm:ss'))" 
      Overwrite="true" />
  </Target>

</Project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 自定义 .targets 文件

<!-- build/DarkM.Lib.Data.Core.targets -->
<Project>
  <Target Name="CopyModuleFiles" AfterTargets="Build">
    <!-- 复制模块文件到输出目录 -->
    <ItemGroup>
      <ModuleFiles Include="$(MSBuildThisFileDirectory)..\modules\**\*" />
    </ItemGroup>
    
    <Copy SourceFiles="@(ModuleFiles)" 
          DestinationFolder="$(OutputPath)\modules\%(RecursiveDir)" 
          SkipUnchangedFiles="true" />
    
    <Message Text="复制模块文件完成" Importance="high" />
  </Target>
</Project>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 🔍 调试和分析

# 查看构建过程

# 详细日志
dotnet build -v detailed

# 诊断日志
dotnet build -v diagnostic

# 生成二进制日志
dotnet build /bl

# 使用 MSBuild Structured Log Viewer 查看
# https://msbuildlog.com/
1
2
3
4
5
6
7
8
9
10
11

# 性能优化

<PropertyGroup>
  <!-- 启用增量编译 -->
  <UseIncrementalCompilation>true</UseIncrementalCompilation>
  
  <!-- 启用编译缓存 -->
  <EnableCompileCache>true</EnableCompileCache>
  
  <!-- 并行构建 -->
  <BuildInParallel>true</BuildInParallel>
</PropertyGroup>
1
2
3
4
5
6
7
8
9
10

# 常见问题排查

# 查看属性值
dotnet build /p:Configuration=Release /v:d | grep "Version"

# 查看引用的包
dotnet list package

# 查看项目引用
dotnet list reference

# 清理 NuGet 缓存
dotnet nuget locals all --clear

# 强制还原
dotnet restore --force
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 📚 最佳实践

# 1. 使用 Directory.Build.props

统一管理所有项目的公共属性,避免重复配置。

# 2. 条件编译

<PropertyGroup Condition="'$(TargetFramework)' == 'net5.0'">
  <DefineConstants>NET5_0</DefineConstants>
</PropertyGroup>
1
2
3

# 3. 版本管理

<PropertyGroup>
  <VersionPrefix>1.2.0</VersionPrefix>
  <VersionSuffix>beta.1</VersionSuffix>
  <Version>$(VersionPrefix)$(VersionSuffix)</Version>
</PropertyGroup>
1
2
3
4
5
<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
1
2
3

# 5. 代码分析

<PropertyGroup>
  <EnableNETAnalyzers>true</EnableNETAnalyzers>
  <AnalysisMode>AllEnabledByDefault</AnalysisMode>
  <AnalysisLevel>latest</AnalysisLevel>
</PropertyGroup>
1
2
3
4
5

# 🔗 相关文档


# 📖 参考链接


最后更新: 2022-08-07