`

MSBuild使用初步

 
阅读更多

了解一下msbuild工程文件的基本结构,作为练习,用它编译一个用到Qt库的C++控制台程序

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

可是如果我想用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这两个东西。

  • 属性类似于宏,一个简单的键值对,在任务中可以直接通过 $(...)来引用
  • Item 比较复杂,在任务中通过 @(...)来引用,大致相当于一个数组吧(fixme)
    • Include和Exclude,中还支持通配符

    <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程序

简单的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>

现在,我们在里面指定了:

  • 源文件
  • 可执行程序名
  • 需要的Qt模块名

但是我们需要有一个Task来做这件事情

QTC任务

为了让我们前面的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程序了


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics