新增一个C#工程,用记事本打开工程文件(.csproj结尾),滚动条拉到最后,大家可以看到一段如下的代码,其中<Target Name="BeforeBuild">和<Target Name="AfterBuild">大家根据名字也就可以看出,在编译前后似乎可以做些什么,不着急慢慢来。
<Project> ......
<Import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" /> <!-- 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> --> </Project>
首先了解下MSBuild 项目文件架构引用,这里介绍了这些烦人的XML节点的定义。
http://msdn.microsoft.com/zh-cn/library/5dy88c2e.aspx
另外一些MS封装好的任务我们也浏览下
http://msdn.microsoft.com/zh-cn/library/7z253716.aspx
这里的任务我们就可以直接在 <Target></Target>中使用了,例如我们想在编译后执行一个拷贝任务,就可以这样写:
<Project> ...... <ItemGroup> <CopySourceFiles Include="copyTest.txt" /> </ItemGroup> <ItemGroup /> <PropertyGroup> <TargetFolder>binDebug</TargetFolder> </PropertyGroup> <Import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" /> <!-- 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"> <Copy SourceFiles="@(CopySourceFiles)" DestinationFolder="$(TargetFolder)" SkipUnchangedFiles="true" /> </Target> </Project>
这样几句简单的语句就可以在我们每次编译的时候将copyTest.txt拷贝到指定的binDebug文件夹下了,当然你也可以说,直接将文件添加的工程,将文件的编译属性改成总是拷贝不就可以 吗,何必这么麻烦,是的这样对于简单的拷贝操作的确不需要这么操作,这里是为了简单介绍下编译任务,何况上面连接地址那么多任务不是简单设置下文件属性就是可以实现的。
以上任务可以通过各种组合实现更加复杂的任务,可见MSBuild没想象的那么单纯,它不仅是简简单单的只能执行编译操作,他也可以是一个强大的任务引擎。这里有一篇文章比较详细介绍MSBuild:http://blog.csdn.net/mittermeyer/article/details/3839101
不仅如此,我们还可以自定义任务,新建一个类库工程,添加引用Microsoft.Build开头的那些库,自定义的任务就得继承任务接口ITask接口
public interface ITask { IBuildEngine BuildEngine { get; set; } ITaskHost HostObject { get; set; } bool Execute(); }
当然这个接口看起来实现有些复杂,为了实现一个简单的任务我们可以从实现ITask类的抽象类Task继承,这样我们只需要重写Execute方法即可,以下我们实现一个创建文件夹的目录的任务,首先我们先定义一个目录属性OutPutDir 上面特性[Required]表示这个属性是必须输入的。这样一个简单的MSBuild扩展任务就完成了。
public class DoTask : Task { private string _OutPutDir; [Required] public string OutPutDir { get { return _OutPutDir; } set { _OutPutDir = value; } } public override bool Execute() { if(!Directory.Exists(_OutPutDir)) { Directory.CreateDirectory(_OutPutDir); } return true; } }
下面看下我们如何调用我们生产的这个任务吧,把生成的dll文件放到我们测试工程下,用记事本打开工程文件在文件最后添加以下节点:
<Project> ...... <Import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" /> <!-- 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> --> <UsingTask TaskName="DoTask" AssemblyFile="MSTaskExtensionTest.dll"/> <Target Name="AfterBuild"> <DoTask OutPutDir="$(MSBuildProjectDirectory)HelloWorld"/> </Target> </Project>
使用UsingTask对我们的任务进行引用,其中TaskName为我们定义的任务名称,AssemblyFile为我们任务编译后的dll文件地址,
其中有一句$(MSBuildProjectDirectory),这个是对当前工程文件目录的引用,更多引用:
MSBuildProjectDirectory : 项目文件所在目录的绝对路径,例如,C:/MyCompany/MyProduct。
MSBuildProjectFile : 项目文件的完整文件名(包括文件扩展名),例如,MyApp.proj。
MSBuildProjectExtension : 项目文件的文件扩展名(包括点号),例如,.proj。
MSBuildProjectFullPath : 项目文件的绝对路径和完整文件名,例如,C:/MyCompany/MyProduct/MyApp.proj。
MSBuildProjectName : 项目文件的文件名(不包括文件扩展名),例如,MyApp。
MSBuildBinPath : 当前使用的 MSBuild 二进制文件所在目录的绝对路径。
MSBuildProjectDefaultTargets : Project元素的 DefaultTargets 属性中指定的目标的完整列表。
MSBuildExtensionsPath : MSBuild 文件夹位于 Program Files 目录下。此位置用于存放自定义目标文件。
参考:http://blog.csdn.net/livelylittlefish/article/details/3410733
最后查看我们任务运行后截图吧:
HelloWorld就是我们编译后使用自定义任务生成的文件夹。现在我们可以随心所欲进行更复杂的任务了...