MSBuild简单介绍
背景
托博客园的福,上周六,有家开发医疗行业系统的初创公司联系我,说在博客园上看到我关于WPF的几篇文章,邀请我去他们那里交流WPF相关的技术知识和心得体会。作为非大拿的我自然是受宠若惊,但对方好意相约,我便欣然前往。
诸事按过不表,在交流过程中,谈到了单独一个产品的版本控制的问题。
(以下该公司人员简称为对方)
对方:“我们用SVN,还不错。只是现在产品的版本越来越多。”
我:“怎么说?”
对方:“我们开发平台有2.0、4.0,目前正在尝试4.5,特性和语法还是有些许不一样的。但是我们不可能为每个.net framework单独维护一个解决方案。少数不同的地方,我们采用SVN分支的方式进行。”
我:“你们产品的市场版本应该也有若干个吧……”
对方:“唔,客户的需求大同小异,所以我们的版本是按模块和功能的不同而区分的,比如标准版、决策分析版、旗舰版等等,但每个版本具体到某个模块,基本上保持一致,偶尔需要微调下。”
我:“微调也是通过SVN来管理?”
对方:“是的,所以现在分支越来越多,其实代码都大同小异。”
我:“哦,我没理解错的话,很多情况下,当主干代码修改了,那所有的这些分支都需要进行相应的合并?”
对方:“是这样没错,有时候想想,如果主干修改的内容能自动无错地合并到分支就好了。”
我:“SVN我只会简单使用,不过我认为你们的这种情况,可以使用另一种方式——vs原本就支持的……”
说到这里,对方的眼睛突然亮了,我和他相视一笑,我知道他也想到了。这也暗合了我自己总结的一套哲理中的其中一条:汝握秘之钥,just forget it。而这么显而易见的处理方法被整个开发团队忽略,这是一个典型的“群体性失明”案例。
“MD,早该想到,条件编译符号!”
没错,条件编译符号结合#if、#else、#endif之类,恰当地使用它们,可以将SVN的各个分支重新整合在一起(当然并行开发过程仍然需要SVN进行管控)。前提是各分支不要有太大差异,有些分支项目结构都变了,那更没必要整在一起了。
各位看官,是不是有点疑惑——不是说MSBuild吗,怎么扯到条件编译符号上去了?
隔天晚上,我正在安装前几天卸载掉的快播软件,准备用来观看这两天落下的新闻联播时,手机响了,是上面那家公司的技术主管(以下仍称对方)。在这个关键时刻打我电话,肯定是发生了紧急的事情,于是我淡定地按了接听键。
对方:“XX,我们用WPF版本的项目做整合,发现有个问题。”
我:“不会吧,什么问题?”
对方:“代码文件没问题,通过条件编译符号能生成特定版本的程序集,但是xaml文件似乎并不支持#if、#elif这些指令。”
我一惊:“what?!”
对方:“某些情况,我们通过binding方式,就是说,在代码文件中根据编译符号设置某一属性的值,然后前台根据这个值来显示特定版本的内容。但是另外有些情况不晓得怎么处理。电话说不清楚,我发你QQ。”
挂了电话,我不情愿地中止了快播安装进程,打开QQ,一段代码跳了出来。
<!--SmartGridView.Title绑定至后台代码,可以在后台通过条件编译符号设置合适的值-->
<his:SmartGridView AutoGenerateColumns="True"
Title="{Binding Title}"
ItemsSource="{Binding GridDataItems}">
<!--当为版本A时,需要下面这段代码,其余版本不需要-->
<his:SmartGridView.RowDetailsTemplate>
<DataTemplate>
<his:MedicineStockDetailsTemplate />
</DataTemplate>
</his:SmartGridView.RowDetailsTemplate>
<!--当为版本A时,需要上面这段代码,其余版本不需要-->
</his:SmartGridView>
对方表示第6行到第10行是目前难点所在。我半晌之后回过神,确实,编译指令+条件编译符号对cs文件有用,在xaml中能结合binding达到一部分效果,当遇到一段xaml要么存在,要么不存在的情况,这三者就无能为力了。怎么办?
我查阅头脑中的知识库,无果,上网搜索也没搜出个所以然来,难道又要怪微软这个坑爹货,不在xaml中加入预编译指令这么拉轰的功能?正当拙计之时,猛然发现有个单词在谷歌的怀抱中向我抛着媚眼,定睛一看——“MSBuild”!
基本概念
MSBuild基于项目文件发挥作用。我们以Visual C# 项目文件为例。当在Visual Studio中新建一个项目,VS自动给我们生成了一个.csproj项目文件。一个典型的项目文件格式如下:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<AssemblyName>MSBuildSample</AssemblyName>
<OutputPath>Bin\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="helloworld.cs" />
</ItemGroup>
<Target Name="Build" Inputs="@(Compile)" Outputs="$(OutputPath)$(AssemblyName).exe">
<MakeDir Directories="$(OutputPath)" Condition="!Exists('$(OutputPath)')" />
<Csc Sources="@(Compile)" OutputAssembly="$(OutputPath)$(AssemblyName).exe" />
</Target>
<Target Name="Clean" >
<Delete Files="$(OutputPath)$(AssemblyName).exe" />
</Target>
<Target Name="Rebuild" DependsOnTargets="Clean;Build" />
</Project>
- 其中PropertyGroup定义各种属性键值对,类似于字符串变量;
- ItemGroup定义各种项,项可以有元数据(MetaData),我们可以将之看作对象(class),一般用于定义文件/文件夹;
- Target,目标,其中一般包含若干Task,针对生成程序集这个过程来讲,Target即为执行一系列任务完成的一个生成步骤,当预定的所有生成步骤都完成之后,程序集也就生成成功了。
- 以$(PropertyName)方式获取属性值;
- @(ItemType)语法引用项,直接打印为Include指定的字符串,要获取项的元数据,使用%(ItemType.MetaDataName);
- 可以将项列表转换为新的项列表。语法:@(ItemType -> '%(MetadataName)')。当然右边可以是任意你想要的格式,可以使用属性、函数或自定义字符串等等;
- Target中设置Inputs和Outputs属性将改变该步骤为增量模式,即MSBuild会比对这两者之间最晚的文件修改时间以决定是否执行该步骤;
- Target中的DependsOnTargets表示该Target依赖于其它Target,其它Target执行完毕之后该Target才能执行,且其它Target的执行顺序为DependsOnTargets中定义的顺序。
- 另外,几乎所有MSBuild元素都可以有Condition特性,只有当Condition的计算结果为“true”时,才会定义或重新定义相关元素。
假设上述文件保存为Test.csproj,我们可以在Visual Studio 命令提示键入
msbuild Test.csproj /t:Rebuild
/t表示要执行的Target,若去除/t:Rebuild,则会执行Build Target,因为Project节点有个DefaultTargets,指定了默认的Target。
以上为基本概念,详情请参看:演练:使用 MSBuild
进阶
- 有些系统预定义的Target.前边说道vs会帮我们自动生成一个项目文件,用记事本打开看,会发现Project的DefaultTargets="Build",但是文件中并未定义名称为"Build"的Target,这就是系统预定义的。另外末尾有两个被注释掉的Target,在Build Target执行前后要做些额外事情,我们就可以使用它们.
- 项(Item)也有很多预定义的元数据,比如Filename、Extension、FullPath,从字面就能理解它们的意思,具体请看MSBuild: By Example—Introducing Well-Known Metadata;
- 也有若干保留属性,参考MSBuild 保留属性;
- 在 .NET Framework 4 版和 4.5 版中,可以使用属性函数来计算 MSBuild 脚本。参考属性函数;
- 动态创建项.有时候需要根据已有条件创建新项,比如在磁盘中动态生成了一些文件,我们就可以为这些文件创建对应的项,以便使之有机会参与Build的过程.注意项Include特性指向的文件如果不存在,在生成过程中可能会抛出error导致生成中止.3.5之前,可以使用CreateItem;3.5及以后版本对这方面做了改进,可以直接在Target中嵌入ItemGroup,不但能创建新Item,还能Remove或者Modify原有的Item.参考CreateItem vs ItemGroup;
- 前边说过Target里包含若干Task,表示按顺序执行的步骤,咱们也可以自定义Task.比如自定义了一个Task名称为PreprocessXaml,它包含在BuildTasks.dll的程序集中,可以使用以下方式获得该Task的引用.
<PropertyGroup>
<BuildTasksPath Condition="'$(BuildTasksPath)' == ''">..\BuildTasks\</BuildTasksPath>
<BuildTasksLib>$(BuildTasksPath)BuildTasks.dll</BuildTasksLib>
</PropertyGroup> <UsingTask AssemblyFile="$(BuildTasksLib)" TaskName="PreprocessXaml" />然后可以这么使用之.
<Target Name="MyTarget">
<PreprocessXaml SourceFile="%(PreprocessedXaml.FullPath)"
DestinationFile="$(ProjectDir)%(PreprocessedXaml.OutputFile)">
</PreprocessXaml>
</Target> - 第1条说道我们可以在项目文件末尾取消默认注释掉的两个Target,在其中插入我们想要在Build之前之后执行的逻辑.当然还有另一种方法,覆盖预定义的BuildDependsOn属性.
<PropertyGroup>
<BuildDependsOn>
MyBeforeTarget;
$(BuildDependsOn);
MyAfterTarget;
</BuildDependsOn>
</PropertyGroup>还有其它预定义东东可以覆盖,更多详情:如何:扩展 Visual Studio 生成过程;
- 除了在项目文件中写一份完整的MSBuild文档,还可以将之分离成多个.targets格式文件,targets文档格式同.csproj/.vbproj文件.then我们可以在项目文件中使用<Import Project=".XXX.targets" />引入,targets文件也能引入其它targets,MSBuild根据引入顺序执行生成过程;
- 生成过程如果出错,就会终止,而使用vs不能像普通项目一样进行运行时调试.往往出错都是出自自定义Task,Task有个Log对象,我们可以使用它在vs底部的错误列表中输出错误\警告\普通消息.如base.Log.LogErrorFromException(exception);
使用MSBuild给XAML增加条件编译符号的支持
概念方面,算是基本把该写到的点都写到,哎,累了,特别是这种相对枯燥的概念学习、解释、搬运,刚开始根本无从下手,各种繁杂困惑。接下去就是完成咱们最初的目的。大家先自己思考下怎么个方案可行。这下篇再写吧。刚说了,哥累了。
转载请注明本文出处:http://www.cnblogs.com/newton/p/3156873.html
MSBuild简单介绍的更多相关文章
- [原创]关于mybatis中一级缓存和二级缓存的简单介绍
关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...
- 利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍
一.pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主要目的是为了数据分析.它提供了大量高级的数据结构和对数据处理的方法. pandas 有两个主要的数据结构 ...
- 利用Python进行数据分析(4) NumPy基础: ndarray简单介绍
一.NumPy 是什么 NumPy 是 Python 科学计算的基础包,它专为进行严格的数字处理而产生.在之前的随笔里已有更加详细的介绍,这里不再赘述. 利用 Python 进行数据分析(一)简单介绍 ...
- yii2的权限管理系统RBAC简单介绍
这里有几个概念 权限: 指用户是否可以执行哪些操作,如:编辑.发布.查看回帖 角色 比如:VIP用户组, 高级会员组,中级会员组,初级会员组 VIP用户组:发帖.回帖.删帖.浏览权限 高级会员组:发帖 ...
- angular1.x的简单介绍(二)
首先还是要强调一下DI,DI(Denpendency Injection)伸手获得,主要解决模块间的耦合关系.那么模块是又什么组成的呢?在我看来,模块的最小单位是类,多个类的组合就是模块.关于在根模块 ...
- Linux的简单介绍和常用命令的介绍
Linux的简单介绍和常用命令的介绍 本说明以Ubuntu系统为例 Ubuntu系统的安装自行百度,或者参考http://www.cnblogs.com/CoderJYF/p/6091068.html ...
- iOS-iOS开发简单介绍
概览 终于到了真正接触IOS应用程序的时刻了,之前我们花了很多时间去讨论C语言.ObjC等知识,对于很多朋友而言开发IOS第一天就想直接看到成果,看到可以运行的IOS程序.但是这里我想强调一下,前面的 ...
- iOS开发多线程篇—多线程简单介绍
iOS开发多线程篇—多线程简单介绍 一.进程和线程 1.什么是进程 进程是指在系统中正在运行的一个应用程序 每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内 比如同时打开QQ.Xcod ...
- iOS开发UI篇—UITabBarController简单介绍
iOS开发UI篇—UITabBarController简单介绍 一.简单介绍 UITabBarController和UINavigationController类似,UITabBarControlle ...
随机推荐
- HBase with MapReduce (Summary)
我们知道,hbase没有像关系型的数据库拥有强大的查询功能和统计功能,本文实现了如何利用mapreduce来统计hbase中单元值出现的个数,并将结果携带目标的表中, (1)mapper的实现 pac ...
- Notes of learning AutoLayout
在XCode5中,如果我们添加一个Button或者Label,或者其他的什么标准View,而不设置任何constraints,IB会自动生成constraints,而这些constraints是fix ...
- OD调试篇6--对一些真正的小程序进行一点点的修改
先打开这个程序看看,提醒你这是一个未注册版本的软件.会发现只能添加4个联系人,这显然是我不想看见的,于是我要对这个程序进行一些修改,嘿嘿... 通过OD载入这个程序 有一些(SEH)也就是异常,我们可 ...
- 【技术无关】GPS转北斗卫星定位 系统调研
前言 陆地交通运输是当前GPS卫星定位系统最大的应用领域,我省自08年实施卫星定位系统建设以来,在车辆监控和调度方面发挥了突出的作用:主要功能包括车辆跟踪.线路规划和导航.信息查询.交通指挥.紧急援助 ...
- 视频转gif
如何把视频变成GIF https://shop16541393.koudaitong.com/v2/feature/1x6q09fa?openid=ov0dfwb6-DBFqTzvekSNAjT59U ...
- 国产AR SDK介绍
说到VR,大家都知道虚拟现实有多火.可是VR之后呢,还有AR.相较于VR,AR的应用意义更加的强大. 相信在不久的将来AR和VR将会融为一体,把现实世界的数据信息完全联通在我们的眼前.这其中的领头羊莫 ...
- Model1
jsp+javabean的开发模式 此处JavaBean也可是封装的业务逻辑 流程: 浏览器端访问jsp,jsp交给Javabean处理,javabean处理后台数据,交还给Jsp
- POJ 1837 DP
一开始看到这个题 第一反应:暴搜! 看看数据范围 ...放弃了 然后就在各种憋状态转移方程. 各种不会 还是看了Discuss里面说的才有点儿思路 直接放状态转移方程: f[i][ j+ w[i]*c ...
- VC++ ADO相关
<VC对ADO的操作> ADO概述: ADO是Microsoft为最新和最强大的数据访问范例 OLE DB 而设计的,是一个便于使用的应用程序层接口. ADO 使您能够编写应用程序以通过 ...
- 黑马程序员——JAVA基础之IO流缓冲区,转换流,字节流
------- android培训.java培训.期待与您交流! ---------- 字符流的缓冲区 缓冲区的出现提高了对数据的读写效率. 对应类 • BufferedWriter ...