了解一下msbuild工程文件的基本结构,作为练习,用它编译一个用到Qt库的C++控制台程序
一个简单的例子:
// file: hello.cs using System; class CSharpTest { static void Main() { Console.WriteLine("Hello world not using Qt"); } }
如果直接用命令行的话,可以直接这么编译:
csc /out:hello_cs.exe hello.cs
可是如果我想用msbuild,工程文件怎么写呢?
恩,大致可以这样:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Target Name="Compile"> <CSC Sources="hello.cs" OutputAssembly="hello_cs.exe" /> </Target> </Project>
而后直接
msbuild hello.csproj
即可。
一个工程中可以有多个目标(Target),如果这样的话,我们需要指定执行哪一个(和nmake是类似的)
msbuild hello.csproj /t:Compile
也可以在Project的属性中指定
<Project DefaultTargets="Compile"
每一个目标(Target)由若干个任务(Task)组成。比如:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Target Name="Compile"> <CSC Sources="hello.cs" OutputAssembly="hello_cs.exe" /> </Target> <Target Name="Compile2"> <Message Text="Before"/> <CSC Sources="hello.cs" OutputAssembly="hello_cs.exe" /> <Message Text="After"/> </Target> </Project>
然后我们
msbuild hello.csproj /t:Compile2
这样在编译命令前后分别输出一条信息。其中CSC和Message都是MSBuild内置的Task
前面的东西太简陋了,一般情况下,我们需要将一些东西分开设置,也就是需要变量或宏一类的东西
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <appname>hello_cs</appname> </PropertyGroup> <ItemGroup> <CSSource Include="hello.cs"/> </ItemGroup> <Target Name="Compile"> <CSC Sources="@(CSSource)" OutputAssembly="$(appname).exe" /> </Target> </Project>
这儿引入的Property(属性)和Item这两个东西。
<ItemGroup> <CSSource Include="hello.cs"/> <CSSource Include="class1.cs"/> <CSSource Include="class2.cs;class3"/> </ItemGroup>
用Visual Studio创建一个具体的C#控制台工程,然后打开看看
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> ... <ItemGroup> <Compile Include="Program.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> ... </Project>
真够复杂的,尽管大量东西都隐藏在Microsoft.CSharp.targets中了
简单的Qt的例子:
#include <QtGui/QLabel> #include <QtGui/QApplication> int main(int argc, char **argv) { QApplication app(argc, argv); QLabel label("Qt Program built using MSBuild...."); label.show(); app.exec(); }
使用命令行时,只需:
E:\msbuild>cl hello.cpp /ID:\Qt\4.7.3\include /link /libpath:D:\Qt\4.7.3\lib QtCore4.lib QtGui4.lib
现在我想试试MSBuild,可以快速写个工程文件 hello.qtproj ?
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <appname>hello_qt</appname> </PropertyGroup> <ItemGroup> <QtPart Include="core;gui" /> </ItemGroup> <ItemGroup> <QtSource Include="hello.cpp"/> </ItemGroup> <Target Name="Compile"> <QTC Sources="@(QTSource)" QtParts="@(QtPart)" Output="$(appname).exe" /> </Target> </Project>
现在,我们在里面指定了:
但是我们需要有一个Task来做这件事情
为了让我们前面的QTC能工作,需要先为MSBuild写个Task插件
using System; using System.Collections.Generic; using System.Diagnostics; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Dbzhang800 { public class QTC:Task { public override bool Execute() { string qtdir = Environment.GetEnvironmentVariable("QTDIR"); var arguments = new List<string>(); foreach (string src in sourcesname) { arguments.Add(src); } arguments.Add(string.Format("/Fe{0}", outputname)); arguments.Add(string.Format("/I{0}\\include", qtdir)); arguments.Add(string.Format("/link /libpath:{0}\\lib", qtdir)); foreach (string part in partsname) { arguments.Add(String.Format("Qt{0}4.lib", part)); } Process proc = new Process(); proc.StartInfo.UseShellExecute = false; proc.StartInfo.FileName = "cl"; proc.StartInfo.Arguments = string.Join(" ", arguments.ToArray()); proc.Start(); Console.WriteLine("{0}", string.Join(" ", arguments.ToArray())); return true; } private string outputname; public string Output { get {return outputname;} set {outputname = value;} } private string[] sourcesname; public string[] Sources { get {return sourcesname;} set {sourcesname = value;} } private string[] partsname; public string[] QtParts { get {return partsname;} set {partsname = value;} } } }
这是一个C#文件,编译成dll文件
csc /target:library /r:Microsoft.Build.Framework.dll;Microsoft.Build.Utilities.v3.5.dll qttask.cs
而后在工程 hello.qtproj 中注册一下这个Task
... <UsingTask TaskName="QTC" AssemblyFile="qttask.dll"/> <Target Name="Compile"> <QTC Sources="@(QTSource)" QtParts="@(QtPart)" Output="$(appname).exe" /> </Target> ...
现在,总算可以用
msbuild test.qtproj
来生成我们的Qt程序了