.NET魔法堂:工程构建基石->MSBuild
一、前言
MSBuild是一个既熟悉又陌生的名字,Visual Studio的项目加载和构建均通过MSBuild来实现。VS中右键打开项目菜单,
对应MSBuild的Build目标,
对应MSBuild的Rebuild目标,
对应MSBuild的Clean目标,
对应MSBuild的PublishOnly目标。
到这里我想大家都明白MSBuild就和Ant一样就是一个用于项目构建的任务执行引擎,只不过它被融入到VS中,降低了入门难度。但融入VS中只是方便我们使用而已,并不代表不用了解学习,尤其项目规模愈发庞大时,编写结构良好的MSBuild Script来作为项目构建和管理的基石是必不可少。
本文是近日的学习记录,学习目标是看懂*.csproj项目文件的信息。若有纰漏请大家指正,谢谢。
附件知识 :
*.sln : 项目、解决方案在磁盘上的引用,VS通过该类文件加载整个项目、解决方案;
*.suo : 保存VS用户界面的自定义配置(包括布局、断电和项目最后编译后而又没有关闭的文件标签等),下一次打开VS时会恢复这些配置;
*.csproj.user: 保存VS的个人配置;
*.csproj : XML格式,保存项目的依赖项和项目构建步骤、任务等。(需要上传到版本库的)
注意:以下内容均以.NET Framework 4.0为环境。
目录一大坨:
二、MSBuild的组成
三、从实例学MSBuild Script
1. Project元素
2. ItemGroup/Item元素
3. PropertyGroup/Property元素
4. Task元素
5. UsingTask元素
6. Target元素
7. Choose元素
8. Import元素
9. ProjectExtensions元素
四、特殊字符
五、Condition的属性形式
六、通配符
七、生成解决方案中的特定目标
八、小结
九、参考
二、MSBuild的组成
MSBuild由两部分组成:脚本 和 执行引擎。
脚本:就是带变量、函数、流程控制的可编程语言。MSBuild Script是基于XML schema的,和Ant、Maven等差不多。
执行引擎:以脚本、变量、环境变量作为输入,对脚本进行解析执行。
三、从实例学MSBuild Script
直接到MSDN学习是一个不错的选择,但为了降低学习难度我们以**.csproj项目文件作为切入点。
在VS2013下新建名为LearnMSBuild的MVC4项目,然后在项目目录下有LearnMSBuild.csproj和LearnMSBuild.csproj.user两个项目文件,而里面就是MSBuild Script了。
在VS中查看LearnMSBuild.csproj的方法:右键点击项目->卸载项目->右键点击项目->编辑LearnMSBuild.csproj。
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)$(MSBuildToolsVersion)Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)$(MSBuildToolsVersion)Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{13508D65-AC7D-4462-9106-2E8EC81F677D}</ProjectGuid>
<ProjectTypeGuids>{E3E379DF-F4C6-4180-9B81-6769533ABE47};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MvcApplication1</RootNamespace>
<AssemblyName>MvcApplication1</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Data.Entity" />
<Reference Include="System.Drawing" />
<Reference Include="System.Web.DynamicData" />
<Reference Include="System.Web.Entity" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Web" />
<Reference Include="System.Web.Extensions" />
<Reference Include="System.Web.Abstractions" />
<Reference Include="System.Web.Routing" />
<Reference Include="System.Xml" />
<Reference Include="System.Configuration" />
<Reference Include="System.Web.Services" />
<Reference Include="System.EnterpriseServices" />
<Reference Include="EntityFramework">
<HintPath>..packagesEntityFramework.5.0.0libnet40EntityFramework.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..packagesMicrosoft.Web.Infrastructure.1.0.0.0libnet40Microsoft.Web.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Mvc.FixedDisplayModes, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..packagesMicrosoft.AspNet.Mvc.FixedDisplayModes.1.0.0libnet40Microsoft.Web.Mvc.FixedDisplayModes.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..packagesNewtonsoft.Json.4.5.11libnet40Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http">
<Private>True</Private>
<HintPath>..packagesMicrosoft.Net.Http.2.0.30506.0libnet40System.Net.Http.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.Formatting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..packagesMicrosoft.AspNet.WebApi.Client.4.0.30506.0libnet40System.Net.Http.Formatting.dll</HintPath>
</Reference>
<Reference Include="System.Net.Http.WebRequest">
<Private>True</Private>
<HintPath>..packagesMicrosoft.Net.Http.2.0.30506.0libnet40System.Net.Http.WebRequest.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..packagesMicrosoft.AspNet.WebApi.Core.4.0.30506.0libnet40System.Web.Http.dll</HintPath>
</Reference>
<Reference Include="System.Web.Http.WebHost, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..packagesMicrosoft.AspNet.WebApi.WebHost.4.0.30506.0libnet40System.Web.Http.WebHost.dll</HintPath>
</Reference>
<Reference Include="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..packagesMicrosoft.AspNet.Mvc.4.0.30506.0libnet40System.Web.Mvc.dll</HintPath>
</Reference>
<Reference Include="System.Web.Optimization">
<HintPath>..packagesMicrosoft.AspNet.Web.Optimization.1.0.0libnet40System.Web.Optimization.dll</HintPath>
</Reference>
<Reference Include="System.Web.Providers">
<HintPath>..packagesMicrosoft.AspNet.Providers.Core.1.2libnet40System.Web.Providers.dll</HintPath>
</Reference>
<Reference Include="System.Web.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..packagesMicrosoft.AspNet.Razor.2.0.30506.0libnet40System.Web.Razor.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..packagesMicrosoft.AspNet.WebPages.2.0.30506.0libnet40System.Web.WebPages.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Deployment, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..packagesMicrosoft.AspNet.WebPages.2.0.30506.0libnet40System.Web.WebPages.Deployment.dll</HintPath>
</Reference>
<Reference Include="System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..packagesMicrosoft.AspNet.WebPages.2.0.30506.0libnet40System.Web.WebPages.Razor.dll</HintPath>
</Reference>
<Reference Include="WebGrease">
<Private>True</Private>
<HintPath>..packagesWebGrease.1.3.0libWebGrease.dll</HintPath>
</Reference>
<Reference Include="Antlr3.Runtime">
<Private>True</Private>
<HintPath>..packagesWebGrease.1.3.0libAntlr3.Runtime.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="App_StartBundleConfig.cs" />
<Compile Include="App_StartFilterConfig.cs" />
<Compile Include="App_StartRouteConfig.cs" />
<Compile Include="App_StartWebApiConfig.cs" />
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
<Compile Include="PropertiesAssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="Contentthemesbaseimagesui-bg_flat_0_aaaaaa_40x100.png" />
<Content Include="Contentthemesbaseimagesui-bg_flat_75_ffffff_40x100.png" />
<Content Include="Contentthemesbaseimagesui-bg_glass_55_fbf9ee_1x400.png" />
<Content Include="Contentthemesbaseimagesui-bg_glass_65_ffffff_1x400.png" />
<Content Include="Contentthemesbaseimagesui-bg_glass_75_dadada_1x400.png" />
<Content Include="Contentthemesbaseimagesui-bg_glass_75_e6e6e6_1x400.png" />
<Content Include="Contentthemesbaseimagesui-bg_glass_95_fef1ec_1x400.png" />
<Content Include="Contentthemesbaseimagesui-bg_highlight-soft_75_cccccc_1x100.png" />
<Content Include="Contentthemesbaseimagesui-icons_222222_256x240.png" />
<Content Include="Contentthemesbaseimagesui-icons_2e83ff_256x240.png" />
<Content Include="Contentthemesbaseimagesui-icons_454545_256x240.png" />
<Content Include="Contentthemesbaseimagesui-icons_888888_256x240.png" />
<Content Include="Contentthemesbaseimagesui-icons_cd0a0a_256x240.png" />
<Content Include="Contentthemesbasejquery-ui.css" />
<Content Include="Contentthemesbasejquery.ui.accordion.css" />
<Content Include="Contentthemesbasejquery.ui.all.css" />
<Content Include="Contentthemesbasejquery.ui.autocomplete.css" />
<Content Include="Contentthemesbasejquery.ui.base.css" />
<Content Include="Contentthemesbasejquery.ui.button.css" />
<Content Include="Contentthemesbasejquery.ui.core.css" />
<Content Include="Contentthemesbasejquery.ui.datepicker.css" />
<Content Include="Contentthemesbasejquery.ui.dialog.css" />
<Content Include="Contentthemesbasejquery.ui.progressbar.css" />
<Content Include="Contentthemesbasejquery.ui.resizable.css" />
<Content Include="Contentthemesbasejquery.ui.selectable.css" />
<Content Include="Contentthemesbasejquery.ui.slider.css" />
<Content Include="Contentthemesbasejquery.ui.tabs.css" />
<Content Include="Contentthemesbasejquery.ui.theme.css" />
<Content Include="Contentthemesbaseminifiedimagesui-bg_flat_0_aaaaaa_40x100.png" />
<Content Include="Contentthemesbaseminifiedimagesui-bg_flat_75_ffffff_40x100.png" />
<Content Include="Contentthemesbaseminifiedimagesui-bg_glass_55_fbf9ee_1x400.png" />
<Content Include="Contentthemesbaseminifiedimagesui-bg_glass_65_ffffff_1x400.png" />
<Content Include="Contentthemesbaseminifiedimagesui-bg_glass_75_dadada_1x400.png" />
<Content Include="Contentthemesbaseminifiedimagesui-bg_glass_75_e6e6e6_1x400.png" />
<Content Include="Contentthemesbaseminifiedimagesui-bg_glass_95_fef1ec_1x400.png" />
<Content Include="Contentthemesbaseminifiedimagesui-bg_highlight-soft_75_cccccc_1x100.png" />
<Content Include="Contentthemesbaseminifiedimagesui-icons_222222_256x240.png" />
<Content Include="Contentthemesbaseminifiedimagesui-icons_2e83ff_256x240.png" />
<Content Include="Contentthemesbaseminifiedimagesui-icons_454545_256x240.png" />
<Content Include="Contentthemesbaseminifiedimagesui-icons_888888_256x240.png" />
<Content Include="Contentthemesbaseminifiedimagesui-icons_cd0a0a_256x240.png" />
<Content Include="Contentthemesbaseminifiedjquery-ui.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.accordion.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.autocomplete.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.button.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.core.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.datepicker.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.dialog.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.progressbar.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.resizable.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.selectable.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.slider.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.tabs.min.css" />
<Content Include="Contentthemesbaseminifiedjquery.ui.theme.min.css" />
<Content Include="Global.asax" />
<Content Include="ContentSite.css" />
<None Include="Scriptsjquery-1.8.2.intellisense.js" />
<Content Include="Scriptsjquery-1.8.2.js" />
<Content Include="Scriptsjquery-1.8.2.min.js" />
<None Include="Scriptsjquery.validate-vsdoc.js" />
<Content Include="Scriptsjquery-ui-1.8.24.js" />
<Content Include="Scriptsjquery-ui-1.8.24.min.js" />
<Content Include="Scriptsjquery.unobtrusive-ajax.js" />
<Content Include="Scriptsjquery.unobtrusive-ajax.min.js" />
<Content Include="Scriptsjquery.validate.js" />
<Content Include="Scriptsjquery.validate.min.js" />
<Content Include="Scriptsjquery.validate.unobtrusive.js" />
<Content Include="Scriptsjquery.validate.unobtrusive.min.js" />
<Content Include="Scriptsknockout-2.2.0.debug.js" />
<Content Include="Scriptsknockout-2.2.0.js" />
<Content Include="Scriptsmodernizr-2.6.2.js" />
<Content Include="Scripts_references.js" />
<Content Include="Web.config" />
<Content Include="Web.Debug.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="Web.Release.config">
<DependentUpon>Web.config</DependentUpon>
</Content>
<Content Include="ViewsWeb.config" />
<Content Include="Views_ViewStart.cshtml" />
<Content Include="ViewsSharedError.cshtml" />
<Content Include="ViewsShared_Layout.cshtml" />
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data" />
<Folder Include="Controllers" />
<Folder Include="Models" />
</ItemGroup>
<ItemGroup>
<Content Include="packages.config" />
</ItemGroup>
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)MicrosoftVisualStudiov$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)WebApplicationsMicrosoft.WebApplication.targets" Condition="'$(VSToolsPath)' != ''" />
<Import Project="$(MSBuildExtensionsPath32)MicrosoftVisualStudiov10.0WebApplicationsMicrosoft.WebApplication.targets" Condition="false" />
<Target Name="MvcBuildViews" AfterTargets="AfterBuild" Condition="'$(MvcBuildViews)'=='true'">
<AspNetCompiler VirtualPath="temp" PhysicalPath="$(WebProjectOutputDir)" />
</Target>
<ProjectExtensions>
<VisualStudio>
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>40646</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:40646/</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
</CustomServerUrl>
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
</WebProjectProperties>
</FlavorProperties>
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target> -->
<ItemGroup>
<F Include="test.txt">
<OP>tst/</OP>
</F>
<F Include="test1.txt">
<OP>tst/</OP>
</F>
</ItemGroup>
<Target Name="HW" Inputs="@(F)" Outputs="@(F->'%(OP)%(Filename)%(Extension)')">
<Message Text="%(F.OP)"/>
<Copy SourceFiles="@(F)" DestinationFolder="%(F.OP)" />
</Target>
</Project>
1. Project元素
作用:根节点,用于配置项目级信息。
属性名 |
说明 |
---|---|
ToolsVersion |
指定执行引擎的版本号 |
InitialTargets |
指定初始化时执行的目标组,多个目标间通过分号(;)分隔 |
DefaultTargets |
指定默认执行的目标组,多个目标间通过分号(;)分隔 |
2. ItemGroup/Item元素
ItemGroup 用于对N个Item元素进行分类整理,并可通过Condition属性对旗下的Item元素进行是否生效的统一控制。
Item
作用:对一个或多个文件的命名引用。可包含元数据(如文件名、路径和版本号),元数据均以子元素的形式定义。
Item的子元素作为其元数据。获取元数据: %(ItemType.ItemMetadata)
示例——定义名为Script的Item
<Script Include="Script/jquery.js;Script/app.js">
<Version>0.1</Version>
</Script>
<Target Name="Nothing">
<Message Text="@(Script)+%(Script.Version)" />
</Target>
// 执行结果:Script/jquery.js;Script/app.js+01
MSBuild执行引擎中内置部分预定义的Item,具体如下:
MSBuild执行引擎中为每个Item预设的元数据,具体如下:
元数据名 |
元数据说明 |
---|---|
FullPath |
当前项所指向的文件的绝对路径 |
RootDir |
当前项所指向的文件的根目录 |
Filename |
当前项所指向的文件的不含扩展名的名称 |
Extension |
当前项所指向的文件的扩展名 |
RelativeDir |
当前项所指向的文件的相对路径(以为结尾) |
Directory |
当前项所指向的文件的目录(以为结尾) |
RecursiveDir |
当项的Include中包含**,则存放**匹配到的目录路径 |
Identity |
%(RelativeDir)%(Filename)%(Extension) |
ModifiedTime |
最后修改时间 |
CreatedTime |
创建时间 |
AccessedTime |
最后访问时间 |
示例:
<MyItem Include="HelloWorld.cs">
</MyItem>
<Target Name="Test">
<Message Text="%(MyItem.FileName)"/>
</Target
// 输出 HelloWorld
*元数据转换(MSBuild Transform)*
增量生成就会用到MSBuild Transform。
作用:将一组Item转换为一组输出值
语法: @(ItemType->'%(metadata)')
<Target Name="CopyOutputs"
Inputs="@(BuiltAssemblies)"
Outputs="@(BuiltAssemblies -> '$(OutputPath)%(Filename)%(Extension)')">
<Copy
SourceFiles="@(BuiltAssemblies)"
DestinationFolder="$(OutputPath)"/>
</Target>
假定BuiltAssemblies如下
<BuiltAssemblies Include="a.txt"></BuiltAssemblies>
<BuiltAssemblies Include="b.txt"></BuiltAssemblies>
<BuiltAssemblies Include="c.txt"></BuiltAssemblies>
Inputs="@(BuiltAssemblies)"
Outputs="@(BuiltAssemblies -> '$(OutputPath)%(Filename)%(Extension)')"
会建立以下的mapping
a.txt(时间戳) <-> bina.txt(时间戳)
b.txt(时间戳) <-> binb.txt(时间戳)
c.txt(时间戳) <-> binc.txt(时间戳)
在执行Target时,会根据Mapping来检查两者的时间戳,若Output的没有时间戳或小于Input的时间戳则该Input项会列入执行的范围,否则则不再被解析执行。
3. PropertyGroup/Property元素
PropertyGroup:属性组,用于整理归类Property
Property:配置信息的键值对
4. Task元素
执行具体任务的任务执行程序。
属性:
子元素:
<Target Name="Compile" DependsOnTargets="Resources">
<Csc Sources="@(CSFile)"
TargetType="library"
Resources="@(CompiledResources)"
EmitDebugInformation="$(includeDebugInformation)"
References="@(Reference)"
DebugType="$(debuggingType)"
OutputAssembly="$(builtdir)$(MSBuildProjectName).dll" >
<Output TaskParameter="OutputAssembly"
ItemName="FinalAssemblyName" />
<Output TaskParameter="BuildSucceeded"
PropertyName="BuildWorked" />
</Csc>
</Target>
分类:
5. UsingTask元素
作用:定义和引入任务执行程序
属性:
属性名 |
说明 |
注意 |
---|---|---|
AssemblyName |
要加载的程序集的名称,设置后不能设置AssemblyFile |
任务的实现类,必须继承ITask接口 |
AssemblyFile |
要加载的程序集的路径,设置后不能设置AssemblyName |
任务的实现类,必须继承ITask接口 |
TaskFactory |
指定用于创建Task实例的工厂类 |
|
TaskName |
任务名称 |
|
Condition |
生效条件 |
子元素:
定义内联任务——Task元素详解
1. 直接在项目文件中编写任务,而不必引用外部包含继承ITask接口的类的程序集
2. 可用支持.NET CodeDom 语言(例如,Visual Basic、Visual C# 或 JScript)来编写任务逻辑
子元素:
注意:当UsingTask中出现子元素Task时,则UsingTask的属性TaskFactory必须为CodeTaskFactory,AssemblyFile为$(MSBuildToolsPath)Microsoft.Build.Tasks.v12.0.dll。
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask TaskName="Nothing" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)Microsoft.Build.Tasks.v12.0.dll">
<ParameterGroup/>
<Task Type="Fragment" Language="cs">
<Reference Include="System.Core"/>
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Using Namespace="System.Net" />
<Using Namespace="Microsoft.Build.Framework" />
<Using Namespace="Microsoft.Build.Utilities" />
<Code Type="Fragment" Language="cs">
<![CDATA[
try {
OutputFilename = Path.GetFullPath(OutputFilename);
Log.LogMessage("Downloading latest version of NuGet.exe...");
WebClient webClient = new WebClient();
webClient.DownloadFile("https://www.nuget.org/nuget.exe", OutputFilename);
return true;
}
catch (Exception ex) {
Log.LogErrorFromException(ex);
return false;
}
]]>
</Code>
</Task>
</Project>
6. Target元素
作用:针对某项工作,有序地组织多个Task。是对外的最小执行单位
属性:
属性名 |
说明 |
---|---|
Name |
目标名称 |
DependsOnTargets |
在执行该目标前,先执行指定的目标。多个目标时,通过分号(;)分隔 |
Condition |
生效条件 |
Inputs |
指定存储目标输入的文件路径,多个文件路径间通过分号(;)分隔 |
Outputs |
指定存储目标输出的文件路径,多个文件路径间通过分号(;)分隔 |
BeforeTargets |
执行指定的目标(多个目标间通过分号分隔)前,先要执行当前目标 |
AfterTargets |
执行指定的目标(多个目标间通过分号分隔)后,要执行当前目标 |
Label |
标识 |
KeepDuplicateOutputs |
true:Outputs中含有多个重复的Reference不会被排重。默认为false |
Returns |
目标的一组返回项,返回给调用该目标的任务。若没有设置该项,则会返回Outputs的内容 |
子元素:
注意:1.一次生成过程仅会执行同一个Target一次,当出现重复调用时会忽略,且返回第一次调用后的返回值;
2.Target重复定义时,采取最后定义有效的原则
7. Choose元素
作用:根据条件使部分Property/PropertyGroup/ItemGroup生效
子元素:
元素 |
说明 |
---|---|
When |
<When Condition="'StringA' == 'StringB'">成立即生效</When> |
Otherwise |
<Otherwise>所有When均不成立即生效</Otherwise> |
8. Import元素
作用:将另一个项目文件导入到当前的项目文件
属性:
属性名 |
说明 |
---|---|
Project 项目文件的绝对或相对路径 |
1. 相对路径,是相对于当前项目文件的路径而言; 2. 可使用通配符(*,**和?) |
Condition |
生效条件 |
注意:1. 若当前项目文件没有DefaultTargets属性,则会按引入顺序寻找各被导入的项目文件的DefaultTargets属性,并执行第一个搜索到的DefaultTargets属性值;
2. 共享的导入项目文件的命名规范是以.targets作为扩展名(如:.nuget/NuGet.targets)
ImportGroup元素用于组织整理Import元素。
9. ProjectExtensions元素
作用:内部包含的内容,将不被MSBuild解析执行
四、特殊字符
特殊字符:在MSBuild Script有特殊含义和用途的字符,若将它们作为普通字符输出时,需要通过%xx,xx为字符的ASCII的十六进制值的字面量来表示。
特殊字符 |
%xx字面量 |
---|---|
* |
%2A |
% |
% |
@ |
%40 |
' |
%27 |
? |
%3F |
$ |
%24 |
; |
%3B |
五、Condition属性的形式
断言/作用 |
语法 |
---|---|
等于 |
'stringA' == 'stringB' |
不等于 |
'stringA' != 'stringB' |
小于、大于、小于等于和大于等于 |
<,>,<=,>= |
存在 |
Exists('stringA') |
以正斜线为结尾 |
HasTrailingSlash('stringA') |
非 |
! |
逻辑与 |
And |
逻辑或 |
Or |
提高优先级 |
() |
六、通配符
假定目录结构为 workspace |-------- i.gif | test.gif |-------- cd |------- c.gif
通配符 |
说明 |
示例 |
---|---|---|
* |
配置任意数量的任意字符,仅限于文件级别 |
1. *.gif匹配出 i.gif和test.gif 2. t*.gif匹配出 test.gif |
** |
配置无限制的目录级别 |
1. **匹配出 i.gif、test.gif和cd/c.gif 2. **/*.gif匹配出 cd/c.gif |
? |
配置一个任意字符 |
?.gif匹配出 i.gif |
七、生成解决方案中的特定目标
MSBuild.exe <SolutionName>.sln /t:<ProjectName>:<TargetName>[;<ProjectName>:<TargetName>]*
八、小结
本文主要是针对**.csproj中出现的元素来学习MSBuild Script,日后理论*实践后继续补充。
九、参考
https://msdn.microsoft.com/zh-cn/library/dd637714.aspx
- git 简易使用说明
- 开发篇-MySQL分区(一)
- Establishing SSL connection without server's identity verification is not recommended. According to
- Django-认证系统
- javascript:双链表-插入排序
- javascript:二叉搜索树 实现
- 自然语言处理 语言模型介绍
- 口水先擦干!从大数据看外卖如何拯救“忙”与“宅”
- javascript:巧用eval函数组装表单输入项为json对象
- Django——model基础
- java学习:日期的运算
- ORACLE:写Function时,传入参数变量名的注意事项
- spring boot 登录注册 demo (二) -- 数据库访问
- spring boot 登录注册 demo (三) -- 前后端传递
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android实现时钟特效
- 解决Android Studio Design界面不显示layout控件的问题
- Android读写文件工具类详解
- Kotlin实现在类里面创建main函数
- AndroidStudio 设置格式化断行宽度教程
- 从 SpringBoot 到 SpringMVC
- AndroidManifest.xml中含盖的安全问题详解
- Android Studio实现格式化XML代码顺序
- android自动生成dimens适配文件的图文教程详解(无需Java工具类)
- Android Studio自动提取控件Style样式教程
- 基于Android studio3.6的JNI教程之ncnn人脸检测mtcnn功能
- Kotlin 使用Lambda来设置回调的操作
- Kotlin之自定义 Live Templates详解(模板代码)
- Android Studio设置颜色拾色器工具Color Picker教程
- Kotlin中常见的符号详解