MSBuild的深入认识

不容错过的MSBuild技巧,必备用法详解和实践指南 MSBuild是一种基于XML的构建引擎,用于在.NET Framework和.NET Core应用程序中自动化构建过程。它是Visual Studio的构建引擎,可在命令行或其他构建工具中使用。MSBuild使用XML文件格式来指定项目的编译、测试和部署等各个阶段的任务。这些XML文件通常以.csproj文件的形式存储。每个项目文件都包含一个或多个 PropertyGroup 元素和一个或多个 ItemGroup 元素。 阅读详情

原文地址:http://knightyzj.iteye.com/blog/463157

最近在从事自动构造工作的过程中,对MSBuild本身有了一些更加深入的认识。MSBuild不仅仅是一个构造工具,应该称之为拥有相当强大扩展能力的自动化平台。

按照笔者现在的理解,MSBuild平台的主要涉及到三部分:执行引擎、构造工程、任务。其中最核心的就是执行引擎,它包括定义构造工程的规范,解释构造工程,执行“构造动作”;构造工程是用来描述构造任务的,大多数情况下我们使用MSBuild就是遵循规范,编写一个构造工程;MSBuild引擎执行的每一个“构造动作”就是通过任务实现的 ,任务就是MSBuild的扩展机制,通过编写新的任务就能够不断扩充MSBuild的执行能力。

所以这三部分分别代表了引擎、脚本和扩展能力。

1、构造工程(脚本文件)

先说说构造工程,只要通过Notepad打开任何一个VS2005(也就是支持CLR 2.0)下的C#工程(csproj)文件,就知道构造工程到底是怎么回事了。

如果说脚本,我们立刻想到的是VBScript或者JavaScript,构造工程内描述的内容,和常见的脚本语言的源文件之间还是有蛮大差距的,为什么也称之为“脚本”呢?因为笔者觉得没啥区别。脚本不就是纯文本形式保存,不经编译解释执行,可以实现一定逻辑分支的程序么?

再看构造工程,在构造工程中我们我们可以定义和使用变量(通过Property/PropertyGourp/Item/ItemGroup等元素),可以使用条件分支(通过Choose/When/Otherwise等元素)、能够在运行时给变量赋值(通过执行任务,获取其返回类型参数的方式)、能够定义执行块(通过Target元素,相当于函数)、能够进行异常处理(通过OnError元素)、还可以复用已有工程定义的内容(通过Import元素)。拥有这些能力和高级语言已经相差无几了,所以笔者认为构造工程不是描述性语言,而是脚本语言。

这里还需要强调一点的是,项目级元素(Property)可以在<PropertyGroup>元素下定义,也可以在构造过程中作为外部参数传入(具体参见《MSBuild命令行参考》)。这是一个非常有用的特性,一般编译时选择配置项(Debug或者Release)就是利用这个特性实现的。

有关构造工程的编写规范可以参考《MSBuild项目文件引用》。

2、执行引擎

接下来看执行引擎,通常我们使用下面的命令行开始执行构造:

MSBuild.exe <ProjectFile>

其中<ProjectFile>是前面提到的构造工程,也就是脚本文件,那么MSBuild.exe就应当是执行引擎了。

没错,不过看一下源代码就会发现MSBuild.exe非常简单,其实主要做的工作就是命令行解析、构造环境的准备(如生成日志记录模块准备一些全局变量),然后就是创建Microsoft.Build.BuildEngine.Engine类的实例,然后调用其BuildProjectFile方法来完成。所以真正的构造逻辑是在Microsoft.Build.Engine.dll中定义并且实现的。下面简单的代码就模拟了MSBuild.exe的工作。

C-sharp代码 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4. using Microsoft.Build.BuildEngine;  
  5.    
  6. namespace BuildAProjectCS  
  7. {  
  8.     class Program  
  9.     {         
  10.         static void Main(string[] args)  
  11.         {  
  12.             // Instantiate a new Engine object  
  13.             Engine engine = new Engine();  
  14.             // Point to the path that contains the .NET Framework 2.0 CLR and tools  
  15.             engine.BinPath = @"c:\windows\microsoft.net\framework\v2.0.xxxxx";  
  16.             // Instantiate a new FileLogger to generate build log  
  17.             FileLogger logger = new FileLogger();  
  18.             // Set the logfile parameter to indicate the log destination  
  19.             logger.Parameters = @"logfile=C:\temp\build.log";  
  20.             // Register the logger with the engine  
  21.             engine.RegisterLogger(logger);  
  22.             // Build a project file  
  23.             bool success = engine.BuildProjectFile(@"c:\temp\validate.proj");  
  24.             //Unregister all loggers to close the log file  
  25.             engine.UnregisterAllLoggers();  
  26.             if (success)  
  27.                 Console.WriteLine("Build succeeded.");  
  28.             else  
  29.                 Console.WriteLine(@"Build failed. View C:\temp\build.log for details");  
  30.         }  
  31.     }  
  32. }  

具体的对象模型参见CLR类库参考中的《Microsoft.Build.Framework命名空间》和《Microsoft.Build.BuildEngine命令空间》。

笔者简单地分析了一下MSBuild.exe和Microsoft.Build.Engine.dll的源代码,MSBuild的构造过程大致如下:

a) 先创建一个构造请求(BuildRequest,构造请求是用来记录构造状态的数据结构),创建完毕之后将构造请求投递到请求队列中。

b) 在执行模块中,从请求队列中获取请求,然后开始处理。

c) 通过Project类加载构造工程,加载过程中检查是Sulotion、VC工程还是其它语言的工程。如果是Solution的话,生成一个临时的包装工程,逐一构造Solution中包含的工程;如果是VC工程的话,也生成一个包装工程,在这个工程中直接执行VCBuild任务来执行构造。否则直接通过XmlDocument加载项目文件,解析其中的元素,识别Property、Item、Target之类元素。

d) 工程解析完毕后按照Target的顺序逐一执行。

e) 在执行Target的过程中先解析是否存在依赖的Target以及OnError子句(即产生错误时需要执行的Target)。

f) 先执行Target依赖的Target,然后通过TaskEngine执行本Target中的每一个任务。如果Target每一个任务都正确执行的话,那么执行下一个Target;否则执行错误处理的Target。

g) 执行Task的过程就是实例化注册为Task的类,然后调用其Execute方法。

h) 所有Target执行完毕,则本次构造也执行完毕。

以上仅仅为了便于理解概念进行的描述,实际的构造过程可能是考虑到多CPU以及内联编译,内部逻辑相当复杂,很多地方应用了Proxy模式。

3、任务(Task)

通过对执行引擎的描述可以发现执行引擎主要是维护执行流程以及记录执行流程中各类变量(Property和Item),具体构造过程中的每一个动作,都是通过Task实现的。也就是说单靠Microsoft.Build.Engine.dll虽然可以加载并且解析构造工程,但是无法完成构造动作。之所以MSBuild能够完成编译、链接、创建目录、复制文件等一系列工作,都是因为在Microsoft.Build.Tasks.dll中实现了与之对应的一个个任务。具体请参考《MSBuild任务参考》以及CLR类库参考中的《Microsoft.Build.Task命名空间》

通过观察MSBuild自带的这些常用任务,可以发现其中分为两类:一类从ToolTask继承,这类任务基本上就是直接调用外部二进制文件执行完成某个特定的动作,例如VCBuild和Exec等;另一类直接从Task继承,是通过内部代码逻辑完成特定动作,例如Copy和MSBuild等。那些直接执行外部文件的任务虽然功能强大,但是有比较大的局限性,执行结果的反馈非常有限,通常只有ExitCode,很难获得其内部执行的更多信息,例如日志输出或者操作影响的结果。

大部分情况下我们只需要一个Exec任务就能够完成全部的构造动作,但是这样做的结果和我们写一个命令行的批处理文件没什么区别了。MSBuild平 台和命令行批处理最大不同在于,它是一个更紧密的工作环境,任务之间通过一系列自定义的全局参数互相协同工作,比较灵活并且移植性高;同时共享日志模块统 一输出执行过程中的各类信息,便于观察和分析。而批处理中各个命令之间几乎是完全孤立的,只能通过硬编码的方式进行协同,协作能力比较差。

举个最简单的例子,编译三个工程,然后复制编译结果到目标目录下。如果用批处理可能会写成这个样子:“编译工程1、复制编译结果、编译工程2、复制结果、编译工程3、复制结果”。而利用MSBuild就可以简化很多工作,例如“申明需要编译的工程(工程1、工程2、工程3、...)、编译需要编译的工程、复制编译结果”。

顺便说一句,MSBuild这个任务比较有趣,在内部直接调用了构造引擎的方法(IBuildEngine2.BuildPrejectFilesInParallel)。这个例子又一次告诉我们这个世界上许多看似强大的东西,其实什么都没有干,只是因为他们手中掌握了有效的资源。-^o^-

除了基础的任务之外,任务还可以任意扩展,并且实现这种扩展非常方便。创建一个CLR 2.0以上的类库工程,编写实现了ITask接口的类,然后在构造工程中通过<UsingTask>元素注册任务就可以使用了。例如:

Xhtml代码 
  1. <UsingTask  
  2. TaskName="Microsoft.CompactFramework.Build.Tasks.PlatformVerificationTask"  
  3. AssemblyName="Microsoft.CompactFramework.Build.Tasks, Version=9.0.0.0,  
  4. Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />  
  5. ……  
  6. <Target Name="PlatformVerificationTask">  
  7. <PlatformVerificationTask PlatformFamilyName="$(PlatformFamilyName)"  
  8. PlatformID="$(PlatformID)" SourceAssembly="@(IntermediateAssembly)"  
  9. ReferencePath="@(ReferencePath)"  
  10. TreatWarningsAsErrors="$(TreatWarningsAsErrors)"  
  11. PlatformVersion="$(TargetFrameworkVersion)"/>  
  12. </Target>  

所以说MSBuild能够成为一个构造引擎,不是因为有个叫MSBuild的Exe文件,也不是因为脚本文件被称之为构造工程,而是因为与之配套的Microsoft.Build.Task.dll中主要实现了主要是和构造相关的任务。换句话说如果提供和测试相关的任务库的话,MSBuild也就是一个自动测试的平台。

总之,MSBuild本身更趋向于一个自动化执行平台,可以根据需求编写不同的脚本文件来满足不同的应用,当现有能力无法满足时,通过编写新的任务进行扩展。不仅限于构造,自动安装、自动测试等都可以依赖这个平台来实现。

MSBuild 摘要:本文介绍了MSBuild在Visual C++项目中的应用,包括命令行参数、常用属性和目标设置。主要内容涵盖PlatformToolset属性(指定工具集版本)、PreferredToolArchitecture属性(选择32/64位工具)、UseEnv属性(控制环境变量优先级)等重要参数配置。同时提供了MSBuild命令行参考,详细说明了/target、/property、/maxcpucount等关键开关的用法,以及日志输出控制选项。这些功能帮助开发者通过命令行灵活控制项目构建. 阅读详情

相关推荐

从零开始构建MSBuild C#项目文件

本文参考自MSDN的一篇文章,从零开始创建MSBuild C#项目文件。准备条件 一个好用的文本编辑器,例如Atom或者Sublime Text。 MSBuild命令行工具。如果已经安装了Visual Studio的话,应该可以在开始菜单中找到类似Visual Studio 2015的MSBuild命令提示符 这样的项目。 创建程序首先打开MSBuild命令提示符,然后切换到你想要创建项目的文件夹,

乐百川 7792

MSBuild的入门完整教程(包学包会)

MSBuild的完整入门教程(实现不了来打我TAT) 看完能够了解MSBuild是什么;我们能用MSBuild做什么;MSBuild的简易使用

weixin_40301728的博客 2万+

掌握MSBUILD构建与部署技术

在现代软件开发中,编译过程是将源代码转换成可执行程序的关键步骤。MSBUILD,作为一种强大的编译工具,它通过提供一种声明式的、基于XML的项目文件格式,使得编译过程高度可配置和可扩展。无论你是经验丰富的开发者还是初学者,理解MSBUILD的基本工作原理和优势,都能让你更高效地管理复杂的项目结构和编译过程。MSBUILD不仅能够处理编译任务,还可以进行资源管理、程序集签名、打包等构建操作,大大简化了项目构建的复杂性。在本章中,我们将介绍MSBUILD的基本功能,并探讨它在自动化构建中的核心作用。

weixin_42527589的博客 1313

【整理】MSbuild

MSBuild基本概念MSBuild是什么为什么要了解MSBuild我想从MSBuild中得到什么MSBuild 基本概念项目文件属性项任务目标MSBuild 问题1.error MSB1009 MSBuild是什么 MSBuild 全称 Microsoft Build Engine,代表 Microsoft 和 Visual Studio 的新的生成平台,用于生成应用程序。此引擎为项目文件提供了一个 XML 架构,用于控制生成平台处理和生成软件的方式。 Visual Studio 会使用 MSBuild,

天天向上 7166

MSBuild 12.0 14.0 17.0

MSBuild vc编绎时使用的构件。

MSBuildSdks:MSBuild项目SDK

MSBuild SDK MSBuild项目SDK用于配置和扩展构建。 有哪些可用的SDK? 支持创建遍历项目,这些遍历项目是MSBuild项目,可指示在构建树时要包括的项目。 对于大型项目树,它们是Visual Studio解决方案文件的替代品。 支持以代码库集中管理NuGet软件包版本。 还允许将全局包引用添加到所有项目。 支持不编译程序集的实用程序项目。 Microsoft.Build.Artifacts 支持来自构建输出的暂存工件。 如何使用这些SDK? 当使用通过NuGet获得的MSBuild Project SDK(例如此仓库中的SDK)时,必须指定特定版本。 将版本附加到软件包名称中: < Project xss=removed> ... 或从SDK属性中省略版本,并在global.j

MSBuild入门

MSBuild是什么? MSBuild全称(Microsoft Build Engine),是用于构建应用程序的平台。您可能不知道它,但是如果您在使用VS做开发,那么一定时时刻刻在使用它。因为是它在背后为你管理生成你的项目文件。当新建一个项目时,注意下项目文件夹中的*.*proj文件就是为MSBuild提供的,这是个文本文件,基于XML格式,里面包含有项目所包含的文件,生成配置,输出配置等信...

weixin_33832340的博客 771

Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build

Paperback: 432 pages Publisher: Microsoft Press; 1 edition (January 7, 2009) Language: English ISBN-10: 0735626286 ISBN-13: 978-0735626287

MSBuild 官方详解

最近使用Jenkins通过命令调用MSBuild实现编译和发布,研究一下相应的命令。

技术人生 2977

代号OneNET02 STM32+ESP8266 WIFI系列-第2节-STM32单片机通过ESP8266连接WIFI访问OneNET OTA服务器实现SOTA远程程序升级

第2节-STM32单片机通过ESP8266连接WIFI访问OneNET OTA服务器实现SOTA远程程序升级,这一节主要是实现通过OneNET OTA服务器将需要更新的程序远程下载到STM32单片机,这一节主要是引导程序和应用程序的讲解。

weixin_44862509的博客 1904

python基础语法与数据结构

本文摘要: Python基础语法包含输入输出、函数、变量、数据类型及运算符等内容。输入函数input()获取键盘输入并以字符串存储,输出函数print()可格式化输出数据。函数通过def定义,可带参数和返回值,提高代码复用性。变量无需声明类型,可动态赋值。数据类型包括数字、字符串、布尔及复合类型,可通过type()查看。运算符包含算术、赋值等类型,其中复合赋值运算符如+=可简化运算。类型转换函数如int()、str()等可实现显式类型转换。这些基础语法构成Python编程的核心要素。

MM602388的博客 434

MSBuild使用2——MSBuild保留属性

本博客(http://blog.youkuaiyun.com/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正! MSBuild使用2——MSBuild保留属性 1. 概述MSBuild 提供一组保留的属性,这些属性存储有关项目文件和 MSBuild 二进制文件的信息。这些属性的计算方式与其他 MSBuild 属性相同。 2.

学习,思考,记录,分享。 6582

Carla-UE4Editor导入RoadRunner地图文件(保姆级教程)

以Carla官网导入RoadRunner地图的标准文档为参考,里面增添了很多细节和注意事项,遇到问题的小伙伴过来看看吧。

DSK_981029的博客 1万+

VSCode添加MSBuild

在tasks.json里面tasks下添加: { "type": "shell", "label": "VS2019 MSBuild", "command": "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\2019\\Enterprise\\MSBuild\\Current\\Bin\\MSBuild.exe", "args":...

jsjxm1984的博客 3870

车载毫米波雷达实战:用MATLAB复现DDMA-MIMO雷达的Empty-band算法(附代码解析)

本文详细介绍了车载毫米波雷达中DDMA-MIMO技术的实战应用,重点解析了Empty-band算法的原理与MATLAB实现。通过搭建仿真环境,文章深入探讨了发射天线通道解调与相位法速度解模糊两大核心难题的解决方案,并提供了完整的代码解析,为雷达算法工程师提供了从理论到实践的清晰指南。

hill8的博客 559

时空数据建模的跨节点联邦图神经网络:KDD21 Cross-Node Federated Graph Neural Network for Spatio-Temporal Data Modeling

前言 联邦学习(FL)虽然已经被广泛研究,但是对复杂的时空依赖关系进行建模以提高预测能力仍然是一个开放的问题。此外目前最优的时空预测模型假定对数据的访问不受限制,忽略了对数据共享的限制。基于此,本文提了一个基于图联邦学习的时空数据模型 Cross-Node Federated Graph Neural Network (CNFGNN),该模型在跨节点联邦学习的约束下,使用基于图神经网络(GNN)的架构对底层图结构进行编码,属于结构化联邦的一种,每个本地模型利用私有数据进行学习,并保持分散性。CNFGNN

qq_56027260的博客 1810

VisualStudio MSBuild 项目文件

Microsoft Build Engine是一个用于生成应用程序的平台。此引擎(也称为 MSBuild)为项目文件提供了一个 XML 架构,用于控制生成平台处理和生成软件的方式。Visual Studio 会使用 MSBuild,但它不依赖于 Visual Studio。通过在项目或解决方案文件中调用 msbuild.exe ,可以在未安装 Visual Studio 的环境中安排和生成...

码农的专栏 1716

开源LocalAI本地人工智能安装教程

LocalAI是一款能在本地运行的人工智能应用,它兼容了OpenAI API规范,它可以在普通的电脑运行,不需要GPU,也不需要联网,音频转录

2301_78652552的博客 3614

MSBUILD

添加编译选项, 需要使用环境变量。传递, 包括增加宏定义。

nicebluechai的博客 1160

Windows 11下JDK 21与JMeter 5.6.3环境配置全攻略

环境变量是操作系统管理软件路径与执行权限的核心机制,它通过预设的键值对,指引系统在调用命令时定位可执行文件。理解其工作原理,是解决软件安装后“命令未找到”等问题的关键。对于Java生态而言,正确配置JAVA_HOME和Path变量,不仅能让java、javac等基础命令全局可用,更是Maven、Gradle乃至JMeter等众多工具链顺畅运行的基石。JMeter作为一款基于Java开发的经典性能测试与接口测试工具,其稳定运行高度依赖健全的Java环境。本文聚焦于在Windows 11系统上,为JDK 21与

weixin_30940783的博客 450

STM32 cubeMX配置串口重定向

这篇文章主要讲解什么是串口重定向,为什么要串口串口重定向。使用printf函数和上位机通信是非常的方便的。希望大家都能够掌握。

m0_49476241的博客 4572

使用setup-msbuild GitHub Action配置MSBuild

使用setup-msbuild GitHub Action配置MSBuild 1. 项目介绍 setup-msbuild 是一个由微软提供的 GitHub Action,旨在帮助用户在 GitHub Actions 工作流中配置 MSBuild。MSBuild 是微软的构建平台,广泛用于构建 .NET Framework 应用程序。通过使用 setup-msbuild,用户可以轻松地将 MSBui...

gitblog_00523的博客 648

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

上一篇: 具有强大的DesignSurface的大DesignTime经验(扩展)类
下一篇: 使用il查看代码
andycode
博客等级 码龄17年 12粉丝 80原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值