如果你和我一样一直都在用NAnt管理生成过程的话,那么你一定会高度关注MSBuild。原因很简单,因为它属于微软,你可以不喜欢它,但你一定要学会用它。

在熬过了几个晚上以后,我终于让自己适应了MSBuild的语法。这可真不容易,特别是当自己已经习惯了NAnt的小写规范之后。不过这不成问题,因 为随着自己对MSBuild的理解一点点加深,自己还真的喜欢上它了。

好吧,下面就让我来简单地介绍一下我在学习MSBuild使用过程中的一点经验。如果你还在MSBuild的大门外徘徊,那么希望这篇东西能带你进入那扇门。

准备工作

首先要提到的是有关如何使用MSBuild的一些重要资源。它们是:

1. Alex Kipman的MSDNTV Show:

http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040122VSNETAK/manifest.xml

2. Alex Kipman和Rajeev Goel在PDC2003上的演讲:

http://microsoft.sitestream.com/PDC2003/TLS/TLS347.htm

上面这两项出自MSBuild开发组的Alex Kipman,从理论上说他应该是了解MSBuild的第一人,他给出的几个演示的确给了我非常大的帮助。(不过我非常不喜欢他的声音,又尖又细。)

3. MSBuild Doc

http://msdn.microsoft.com/longhorn/toolsamp/default.aspx

这是最重要的,其中包括Alex Kipman主笔的五份重要文档:MSBuildFileFormat、MSBuildWalkthrough、MSBuildTasks、HowToWriteATask以及MSBuildCommandLine。这 可能是目前情况下外界能获得的有关MSBuild最详细的文档。

Demo

好了,一切准备工作就绪,让我们以一个简单的示例开始吧。

首先写一个简单的C# Console程序(你也可以把它改成VB.NET):

// HelloMSBuild.cs

using System;

class HelloMSBuild

{

public static void Main()

{

Console.WriteLine("Hello MSBuild!");

}

}

下面我们就要写一个.csproj文件来控制整个生成过程。值得注意的是,如果在调用MSBuild.exe时没有指定具体的项目 文件,MSBuild引擎会在当前目录下查找一个名为*.*proj的项目文件。如果你在同一目录中写了多个这样的项目文件,那么需要手动指定MSBuild.exe的目标文件,方法 是:

MSBuild a.csproj

否则MSBuild会提示出错,要求你手动指定目标项目文件。

以下是项目文件:

<!--  Build.csproj -->

<Project DefaultTargets="Run">

<Property Bin="bin" />

<Property OutputAssembly="HelloMSBuild" />

<Item Type="Source" Include="HelloMSBuild.cs" />

<Target Name="Build">

<Task   Name="MakeDir"

Directories="$(Bin)"

Condition="!Exists('$(Bin)')" />

<Task   Name="Csc"

Sources="@(Source)"

TargetType="exe"

OutputAssembly="$(Bin)\$(OutputAssembly).exe" />

</Target>

<Target Name="Run" DependsOnTargets="Build">

<Task   Name="Exec"

Command="$(Bin)\$(OutputAssembly).exe" />

</Target>

</Project>

如果你此前没有过NAnt的开发经验,那么上面这些东西肯定看起来挺吓人。这个时候最好的办法是打开那篇MSBuildFileFormat,对照 上面代码查找相应的项目元素的含义。下面我对其中重要的项目元素进行一下解释。

1.         Project元素。这是每一个项目文件的 最外层元素,它表示了一个项目的范围。如果缺少了这一元素,MSBuild会报错称Target元素无法识别或不被支持。

Project元素拥有多个属性,其中最常用 到的是DefaultTargets属性。我们都知道,在一个项目的生成过程中可能需要完成几项不同的任务(比如编译、单元测试、check-in到源代码控制服务器中 等),其中每一项任务都可以用Target来表示。对于拥有多个Target的项目,你可以通过设置Project的DefaultTargets(注意是复数)属性来指定需要运行哪(几)个Target,比如:

<Project DefaultTargets=”Build” >

...

或者:

<Project DefaultTargets=”Build;Test;Run” >

...

如果没有这个设置,MSBuild将只运行排在最前面的那个Target。

2.         Property元素。在项目中你肯定需要 经常访问一些信息,例如需要创建的路径名、最终生成的程序集名称等。这些信息你最好别hard code进项目中,除非你一次写过之后永不更改。这时Property就能派上用场了。你把上面 提到的那些信息以name/value的形式添加进Property,随后就可以以$(PropertyName)的形式访问。这样你就无须为了改动一个文件名称而让整个项目文件伤筋动骨了。比如上面代码中的Bin就是将要创建的路径名称,而AssemblyName则是最终要生成的 程序集名称。这些属性的名称不是固定的,你完全可以按自己的习惯来进行命名。在使用时,你需要把属性名称放在”$(“和”)”对内(不包括引号),以表示这里将被替 换成一个Property元素的值。

另外,如果Property元素数量比较多,你还可以把它们分门别类地放在不同的PropertyGroup里,以提高代码的 可阅读性。这对Property本身没有任何影响。比如:

<PropertyGroup>

<Property ... />

<Property ... />

</PropertyGroup>

3.         Item元素。在整个项目文件中你肯定要提 供一些可被引用的输入性资源(inputs)信息,比如源代码文件、引用的程序集名称、需要嵌入的图标资源等。它们应该被放在Item里,以便随时引用。语法是:

<Item Type=”TheType” Include=”NameOrPath” />

其中Type属性可以被看作是资源的类别名称,比如对于.cs源文件,你可以把它们的Type都设置为Source,对于引用的程序集把Type都设置为Reference,这样在随后想引用这一类别的资源时只要引用这个Type就可以了,方法是@(TypeName)。可千万别和Property的引用方法弄混了。

既然Type是资源的类名,那么Include就是具体的资源名称了,比如在上面的示例代码中,Include引用的就是C#源代码文件的名称。你也可以用使用通配 符*来扩大引用范 围。比如下面这行代码就指定了当前目录下的所有C#文件都可以通过@(Source)来引用:

<Item Type=”Source” Include=”*.cs” />

另外,你也可以通过与PropertyGroup类似的方法把相关的Item放在ItemGroup里。

4.         Target元素。上面已经提到了,Target表示一个需要完成的虚拟的任务 单元。每个Project可以包括一个或多个Target,从而完成一系列定制的任务。你需要给每个Target设置一个Name属性(同一Project下的两个Target不能拥有同样的Name)以便引用和区别。

举例来说,在你的项目生成过程中可能需要完成三个阶段的任务:首先从VSS中check-out源代码,接下来编译这些代 码并执行单元测试,最后把它们check-in回VSS。那么通常情况下你可以创建三个不同的Target以清晰划分三个不同的阶段:

<Target Name=”CheckOut” >

...

</Target>

<Target Name=”Build” DependsOnTargets=”CheckOut”>

<Task     Name=”Build” .../>

<Task     Name=”UnitTest” ... />

</Target>

<Target Name=”CheckIn” DependsOnTargets=”CheckOut;Build”>

...

</Target>

这样,你就可以非常清晰地控制整个生成过程。为了反应不同Target之间的依赖关系(只有Check-in后才能编译,只有编译完成 才可能Check-out……),你需要设置Target的DependsOnTargets属性(注意是复数),以表示仅当这些Target执行完成之后才能执行当前的Target。当MSBuild引擎开始执行某项Target时(别忘了Project的DefaultTargets属性),会自动检测它所依赖的那些Target是否已经执行完成,从而避免因为某个生成环节缺失而导致整个生成过程发生意外。

你可以通过Project的DefaultTargets属性指定MSBuild引擎从哪(几)个Target开始执行,也可以在调用MSBuild.exe时使用t开关来手动指定将要运行的Target,方法如下:

MSBuild /t:CheckOut

这样,只有CheckOut(以及它所依赖的Target,在上文中没有)会被执行。

5.         Task元素。这可能是整个项目文件中最重 要的,因为它才是真正可执行的部分(这也是为什么我在上面说Target是虚拟的)。你可以在Target下面放置多个Task来顺序地执行相应的任务,比如我在上面示例代码中就在两个不同的Target中安排了MakeDir、Csc和Exec三个不同的Task。这些Task通过Name属性来相互区分,并各自拥有不同的其 它属性来完成不同的任务,比如Csc有Sources(源代码文件)、TargetType(目标类型)、OutputAssembly(生成程序集名称)等属性,而MakeDir则只需设置Directories(需要创建的路径名称列表)即可。

也许你会奇怪这些Task的名称和属性从哪里来。好吧,请用文本编译器打开%windir%\Microsoft.NET\Framework\v1.2.30703\Microsoft.BuildTasks文件,看到了吗?默认情况下里面应该是这样的(不同的版本可能会有细微差别):

<!-- This file lists all the tasks that ship by default with MSBuild -->

<DefaultTasks>

<UsingTask TaskName="Microsoft.Build.Tasks.Csc" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.MSBuild" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.Exec" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.Vbc" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.MakeDir" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.ResGen" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.Copy" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.NetAssemblyResolver" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.TransformPath" AssemblyName="MSBuildTasks"/>

</DefaultTasks>

你会注意到,在DefaultTasks元素下面排列的全是UsingTask,其中指明每一个Task的TaskName(名称)和AssemblyName(程序集)。比如说第一个UsingTask就对应着我们上面用过的Csc任务,它的完整名称(namespace+class)是Microsoft.Build.Tasks.Csc,位于MSBuildTasks.dll程序集中(请在同一目录下确认这一.dll文件的存在)。这样,MSBuild引擎在遇到对Csc任务的调用时就会通过这里的注册信息来确定Csc所在的程序集,从而最终运行相应的托管代码。这样,如果你自己也写了不同的Task,请按同样的方式对它进行注册以便 使用。如果你引用了一个还没有注册的Target,那么MSBuild引擎将无法找到它的存在而导致生成失败。

当然,MSBuild Task的注册方式不止以上一种。以上注册方法的影响范围是全局,你可以在每一个Project里应用上面注册的那些Task。但你也可以选择在Project范围内注册Task,这将对应着另外一种略有不同的方 法。我会在后面的一篇文章里给出具体介绍。在这里,你只需明白你所需要的Task在哪里找到,而它们的具体用法可以通过参考MSBuildTasks一文来获得,在这里我就不细说了。

OK,介绍了一长串,还是快点把我们的Build.csproj运行起来吧。请在shell的同一目录下输入以下命令:

MSBuild

或者:

MSBuild Build.csproj

运行结果如下:

d:\Dev\MyMSBuildDemo>msbuild Build.csproj

msbuild Build.csproj

Microsoft (R) .NET Build Engine version 1.2.30703.4

[Microsoft .Net Framework, Version 1.2.30703.4]

Copyright (C) Microsoft Corporation 2003. All rights reserved.

Target "Build" in project "Build.csproj"

Task "MakeDir"

Creating directory "bin".

Task "Csc"

Csc.exe /out:"bin\HelloMSBuild.exe" /target:exe "HelloMSBuild.cs"

Target "Run" in project "Build.csproj"

Task "Exec"

Hello MSBuild!

可见,在Build.csproj指定的两个Target和三个Task均按相应的顺序依次运行,在Csc执行时MSBuild还显示出了当前执行的具体命令,而在原来的Visual Studio .NET年代,你是无法获知当前正在执行的编译命令是什 么(据Alex Kipman称,连Visual Studio .NET自己也不知道正在执行的具体命令,因为那些命令已经被hard code进了“黑盒子”,根本无法 提取)。

好了,一个简单的MSBuild文件用法示例就到这儿了。如果你此前还没接触过MSBuild或者NAnt,那么希望这篇文章能让你对MSBuild的用法有个初步的了解。还有 很多的细节我在文中没有涉及,如果你感兴趣的话就请下载前面我提到的那些MSBuild文档来自己研究吧。我会在下一篇文章里介绍如何开发自己的MSBuild Task。

--------------------------------------------------------------------------

musicland

http://blog.joycode.com/musicland

如果你和我一样一直都在用NAnt管理生成过程的话,那么你一定会高度关注MSBuild。原因很简单,因为它属于微软,你可以不喜欢它,但你一定要学会用它。

在熬过了几个晚上以后,我终于让自己适应了MSBuild的语法。这可真不容易,特别是当自己已经习惯了NAnt的小写规范之后。不过这不成问题,因 为随着自己对MSBuild的理解一点点加深,自己还真的喜欢上它了。

好吧,下面就让我来简单地介绍一下我在学习MSBuild使用过程中的一点经验。如果你还在MSBuild的大门外徘徊,那么希望这篇东西能带你进入那扇门。

准备工作

首先要提到的是有关如何使用MSBuild的一些重要资源。它们是:

1. Alex Kipman的MSDNTV Show:

http://msdn.microsoft.com/msdntv/episode.aspx?xml=episodes/en/20040122VSNETAK/manifest.xml

2. Alex Kipman和Rajeev Goel在PDC2003上的演讲:

http://microsoft.sitestream.com/PDC2003/TLS/TLS347.htm

上面这两项出自MSBuild开发组的Alex Kipman,从理论上说他应该是了解MSBuild的第一人,他给出的几个演示的确给了我非常大的帮助。(不过我非常不喜欢他的声音,又尖又细。)

3. MSBuild Doc

http://msdn.microsoft.com/longhorn/toolsamp/default.aspx

这是最重要的,其中包括Alex Kipman主笔的五份重要文档:MSBuildFileFormat、MSBuildWalkthrough、MSBuildTasks、HowToWriteATask以及MSBuildCommandLine。这 可能是目前情况下外界能获得的有关MSBuild最详细的文档。

Demo

好了,一切准备工作就绪,让我们以一个简单的示例开始吧。

首先写一个简单的C# Console程序(你也可以把它改成VB.NET):

// HelloMSBuild.cs

using System;

class HelloMSBuild

{

public static void Main()

{

Console.WriteLine("Hello MSBuild!");

}

}

下面我们就要写一个.csproj文件来控制整个生成过程。值得注意的是,如果在调用MSBuild.exe时没有指定具体的项目 文件,MSBuild引擎会在当前目录下查找一个名为*.*proj的项目文件。如果你在同一目录中写了多个这样的项目文件,那么需要手动指定MSBuild.exe的目标文件,方法 是:

MSBuild a.csproj

否则MSBuild会提示出错,要求你手动指定目标项目文件。

以下是项目文件:

<!--  Build.csproj -->

<Project DefaultTargets="Run">

<Property Bin="bin" />

<Property OutputAssembly="HelloMSBuild" />

<Item Type="Source" Include="HelloMSBuild.cs" />

<Target Name="Build">

<Task   Name="MakeDir"

Directories="$(Bin)"

Condition="!Exists('$(Bin)')" />

<Task   Name="Csc"

Sources="@(Source)"

TargetType="exe"

OutputAssembly="$(Bin)\$(OutputAssembly).exe" />

</Target>

<Target Name="Run" DependsOnTargets="Build">

<Task   Name="Exec"

Command="$(Bin)\$(OutputAssembly).exe" />

</Target>

</Project>

如果你此前没有过NAnt的开发经验,那么上面这些东西肯定看起来挺吓人。这个时候最好的办法是打开那篇MSBuildFileFormat,对照 上面代码查找相应的项目元素的含义。下面我对其中重要的项目元素进行一下解释。

1.         Project元素。这是每一个项目文件的 最外层元素,它表示了一个项目的范围。如果缺少了这一元素,MSBuild会报错称Target元素无法识别或不被支持。

Project元素拥有多个属性,其中最常用 到的是DefaultTargets属性。我们都知道,在一个项目的生成过程中可能需要完成几项不同的任务(比如编译、单元测试、check-in到源代码控制服务器中 等),其中每一项任务都可以用Target来表示。对于拥有多个Target的项目,你可以通过设置Project的DefaultTargets(注意是复数)属性来指定需要运行哪(几)个Target,比如:

<Project DefaultTargets=”Build” >

...

或者:

<Project DefaultTargets=”Build;Test;Run” >

...

如果没有这个设置,MSBuild将只运行排在最前面的那个Target。

2.         Property元素。在项目中你肯定需要 经常访问一些信息,例如需要创建的路径名、最终生成的程序集名称等。这些信息你最好别hard code进项目中,除非你一次写过之后永不更改。这时Property就能派上用场了。你把上面 提到的那些信息以name/value的形式添加进Property,随后就可以以$(PropertyName)的形式访问。这样你就无须为了改动一个文件名称而让整个项目文件伤筋动骨了。比如上面代码中的Bin就是将要创建的路径名称,而AssemblyName则是最终要生成的 程序集名称。这些属性的名称不是固定的,你完全可以按自己的习惯来进行命名。在使用时,你需要把属性名称放在”$(“和”)”对内(不包括引号),以表示这里将被替 换成一个Property元素的值。

另外,如果Property元素数量比较多,你还可以把它们分门别类地放在不同的PropertyGroup里,以提高代码的 可阅读性。这对Property本身没有任何影响。比如:

<PropertyGroup>

<Property ... />

<Property ... />

</PropertyGroup>

3.         Item元素。在整个项目文件中你肯定要提 供一些可被引用的输入性资源(inputs)信息,比如源代码文件、引用的程序集名称、需要嵌入的图标资源等。它们应该被放在Item里,以便随时引用。语法是:

<Item Type=”TheType” Include=”NameOrPath” />

其中Type属性可以被看作是资源的类别名称,比如对于.cs源文件,你可以把它们的Type都设置为Source,对于引用的程序集把Type都设置为Reference,这样在随后想引用这一类别的资源时只要引用这个Type就可以了,方法是@(TypeName)。可千万别和Property的引用方法弄混了。

既然Type是资源的类名,那么Include就是具体的资源名称了,比如在上面的示例代码中,Include引用的就是C#源代码文件的名称。你也可以用使用通配 符*来扩大引用范 围。比如下面这行代码就指定了当前目录下的所有C#文件都可以通过@(Source)来引用:

<Item Type=”Source” Include=”*.cs” />

另外,你也可以通过与PropertyGroup类似的方法把相关的Item放在ItemGroup里。

4.         Target元素。上面已经提到了,Target表示一个需要完成的虚拟的任务 单元。每个Project可以包括一个或多个Target,从而完成一系列定制的任务。你需要给每个Target设置一个Name属性(同一Project下的两个Target不能拥有同样的Name)以便引用和区别。

举例来说,在你的项目生成过程中可能需要完成三个阶段的任务:首先从VSS中check-out源代码,接下来编译这些代 码并执行单元测试,最后把它们check-in回VSS。那么通常情况下你可以创建三个不同的Target以清晰划分三个不同的阶段:

<Target Name=”CheckOut” >

...

</Target>

<Target Name=”Build” DependsOnTargets=”CheckOut”>

<Task     Name=”Build” .../>

<Task     Name=”UnitTest” ... />

</Target>

<Target Name=”CheckIn” DependsOnTargets=”CheckOut;Build”>

...

</Target>

这样,你就可以非常清晰地控制整个生成过程。为了反应不同Target之间的依赖关系(只有Check-in后才能编译,只有编译完成 才可能Check-out……),你需要设置Target的DependsOnTargets属性(注意是复数),以表示仅当这些Target执行完成之后才能执行当前的Target。当MSBuild引擎开始执行某项Target时(别忘了Project的DefaultTargets属性),会自动检测它所依赖的那些Target是否已经执行完成,从而避免因为某个生成环节缺失而导致整个生成过程发生意外。

你可以通过Project的DefaultTargets属性指定MSBuild引擎从哪(几)个Target开始执行,也可以在调用MSBuild.exe时使用t开关来手动指定将要运行的Target,方法如下:

MSBuild /t:CheckOut

这样,只有CheckOut(以及它所依赖的Target,在上文中没有)会被执行。

5.         Task元素。这可能是整个项目文件中最重 要的,因为它才是真正可执行的部分(这也是为什么我在上面说Target是虚拟的)。你可以在Target下面放置多个Task来顺序地执行相应的任务,比如我在上面示例代码中就在两个不同的Target中安排了MakeDir、Csc和Exec三个不同的Task。这些Task通过Name属性来相互区分,并各自拥有不同的其 它属性来完成不同的任务,比如Csc有Sources(源代码文件)、TargetType(目标类型)、OutputAssembly(生成程序集名称)等属性,而MakeDir则只需设置Directories(需要创建的路径名称列表)即可。

也许你会奇怪这些Task的名称和属性从哪里来。好吧,请用文本编译器打开%windir%\Microsoft.NET\Framework\v1.2.30703\Microsoft.BuildTasks文件,看到了吗?默认情况下里面应该是这样的(不同的版本可能会有细微差别):

<!-- This file lists all the tasks that ship by default with MSBuild -->

<DefaultTasks>

<UsingTask TaskName="Microsoft.Build.Tasks.Csc" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.MSBuild" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.Exec" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.Vbc" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.MakeDir" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.ResGen" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.Copy" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.NetAssemblyResolver" AssemblyName="MSBuildTasks"/>

<UsingTask TaskName="Microsoft.Build.Tasks.TransformPath" AssemblyName="MSBuildTasks"/>

</DefaultTasks>

你会注意到,在DefaultTasks元素下面排列的全是UsingTask,其中指明每一个Task的TaskName(名称)和AssemblyName(程序集)。比如说第一个UsingTask就对应着我们上面用过的Csc任务,它的完整名称(namespace+class)是Microsoft.Build.Tasks.Csc,位于MSBuildTasks.dll程序集中(请在同一目录下确认这一.dll文件的存在)。这样,MSBuild引擎在遇到对Csc任务的调用时就会通过这里的注册信息来确定Csc所在的程序集,从而最终运行相应的托管代码。这样,如果你自己也写了不同的Task,请按同样的方式对它进行注册以便 使用。如果你引用了一个还没有注册的Target,那么MSBuild引擎将无法找到它的存在而导致生成失败。

当然,MSBuild Task的注册方式不止以上一种。以上注册方法的影响范围是全局,你可以在每一个Project里应用上面注册的那些Task。但你也可以选择在Project范围内注册Task,这将对应着另外一种略有不同的方 法。我会在后面的一篇文章里给出具体介绍。在这里,你只需明白你所需要的Task在哪里找到,而它们的具体用法可以通过参考MSBuildTasks一文来获得,在这里我就不细说了。

OK,介绍了一长串,还是快点把我们的Build.csproj运行起来吧。请在shell的同一目录下输入以下命令:

MSBuild

或者:

MSBuild Build.csproj

运行结果如下:

d:\Dev\MyMSBuildDemo>msbuild Build.csproj

msbuild Build.csproj

Microsoft (R) .NET Build Engine version 1.2.30703.4

[Microsoft .Net Framework, Version 1.2.30703.4]

Copyright (C) Microsoft Corporation 2003. All rights reserved.

Target "Build" in project "Build.csproj"

Task "MakeDir"

Creating directory "bin".

Task "Csc"

Csc.exe /out:"bin\HelloMSBuild.exe" /target:exe "HelloMSBuild.cs"

Target "Run" in project "Build.csproj"

Task "Exec"

Hello MSBuild!

可见,在Build.csproj指定的两个Target和三个Task均按相应的顺序依次运行,在Csc执行时MSBuild还显示出了当前执行的具体命令,而在原来的Visual Studio .NET年代,你是无法获知当前正在执行的编译命令是什 么(据Alex Kipman称,连Visual Studio .NET自己也不知道正在执行的具体命令,因为那些命令已经被hard code进了“黑盒子”,根本无法 提取)。

好了,一个简单的MSBuild文件用法示例就到这儿了。如果你此前还没接触过MSBuild或者NAnt,那么希望这篇文章能让你对MSBuild的用法有个初步的了解。还有 很多的细节我在文中没有涉及,如果你感兴趣的话就请下载前面我提到的那些MSBuild文档来自己研究吧。我会在下一篇文章里介绍如何开发自己的MSBuild Task。

--------------------------------------------------------------------------

musicland

http://blog.joycode.com/musicland

转载于:https://www.cnblogs.com/fromchaos/archive/2010/06/21/1762099.html

[转]MSBuild入门相关推荐

  1. MSBuild学习总结

    MSBuild的简单介绍与使用 http://www.cnblogs.com/shanyou/p/3452938.html MSBuild 是 Microsoft 和 Visual Studio的生成 ...

  2. MSBuild的简单介绍与使用

    MSBuild 是 Microsoft 和 Visual Studio的生成系统.它不仅仅是一个构造工具,应该称之为拥有相当强大扩展能力的自动化平台.MSBuild平台的主要涉及到三部分:执行引擎.构 ...

  3. [独孤九剑]持续集成实践(二)– MSBuild语法入门

    本系列文章包含: [独孤九剑]持续集成实践(一)- 引子 [独孤九剑]持续集成实践(二)– MSBuild语法入门 [独孤九剑]持续集成实践(三)- Jenkins安装与配置(Jenkins+MSBu ...

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

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

  5. msbuild 语法_MSBuild入门(续)

    MSBuild基本概念(续) 在上一篇简单的介绍了下MSBuild中的四个基本块,每块介绍比较单薄,在这里对在大多数的项目模版生成的*.*proj文件中比较常见一些用法和概念做些补充.主要有一下几方面 ...

  6. msbuild 语法_[独孤九剑]持续集成实践(二)– MSBuild语法入门

    本系列文章包含: 1.开始 在这篇文章中,我们会从头开始,一步步完成一个属于我们自己的MSBuild脚本.在它完成以后,我们只需要一个命令就可以删除之前的构建产物,构建.NET应用,运行单元测试.后面 ...

  7. 第一次运行OSG入门程序失败记和搞定的情况

    一 OSG简介 OpenSceneGraph(简称OSG)使用OpenGL技术开发,是一套基于C++平台的应用程序接口(API),它让程序员能够更加快速.便捷地创建高性能.跨平台的交互式图形程序.它作 ...

  8. WPF入门教程系列三——Application介绍(续)

    接上文WPF入门教程系列二--Application介绍,我们继续来学习Application 三.WPF应用程序的关闭 WPF应用程序的关闭只有在应用程序的 Shutdown 方法被调用时,应用程序 ...

  9. 如何创建一个基于 MSBuild Task 的跨平台的 NuGet 工具包

    MSBuild 的 Task 为我们扩展项目的编译过程提供了强大的扩展性,它使得我们可以用 C# 语言编写扩展:利用这种扩展性,我们可以为我们的项目定制一部分的编译细节.NuGet 为我们提供了一种自 ...

最新文章

  1. 互联网数据中心安全管理方案
  2. 医疗信息季节:在医疗行业未来的变化(继续前传)
  3. 使用GDB调试器(一)
  4. 基于springboot的健身管理系统
  5. 【Python】调用WPS V9 API,实现PPT转PDF
  6. java qlv转mp4 代码_如何将QLV视频格式转换成MP4视频
  7. 上传txt文件乱码问题
  8. 反垃圾邮件黑名单申诉工作相关步骤说明
  9. JS JavaScript 实现文字上下滚动效果
  10. 计算机二级学多少天能过,如何七天过计算机二级
  11. PPT中图表不同粘贴方式的区别
  12. 三层架构Bll中报错找不到可接受类型为“Lesson.DAL.StudentDal”的第一个参数的扩展方法
  13. 用fread()和fwrite()读写文件
  14. python空列表列表初始化_Python如何初始化列表?
  15. 设计师专用WIN10系统集成1449元的AI人工智能软件可动态提高设计程序性能提升高达394%
  16. 基于springboot的药店进销存管理系统
  17. 抖音小程序可做类目--资讯
  18. 体育场馆管理系统-体育场馆智能化系统-云上铺
  19. 小白学Python 基础数据类型
  20. MATLAB数据分析方法第2章数据描述性分析

热门文章

  1. 教你学会Sql中 ROW_NUMBER的用法
  2. PHP中上传文件文件名乱码
  3. 在线rss阅读聚合器lilina-0.7安装笔记
  4. c++-swap nodes in pairs
  5. 三款运用二维码分享与预览的原型设计工具
  6. vGPU作为主流平台的进化之路
  7. springsession 实现session 共享
  8. python多线程下载文件
  9. Quartz2D简单绘制之不规则形状
  10. Lucene学习之——停用词