当前位置: 首页 > news >正文

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


相关文章:

  • python库--pandas--写入文本文件
  • WPF程序编译(从命令行到Visual Studio)
  • Hibernate学习(1)- 初识
  • C#下.NET配置文件使用(一)
  • JS运行机制(进程与线程的区分)
  • C#下.NET配置文件使用(二)
  • MAC为Apache2服务器配置多个虚拟主机
  • WPF下的布局(Layout、Panel)小记
  • let 与 const 的用法
  • 从CT技术想到的软件测试
  • Linux CentOS7 VMware 文件和目录权限chmod、更改所有者和所属组chown、umask、隐藏权限lsattr/chattr...
  • Linux WebSphere DB2
  • c\c++ 基本知识
  • 设计模式——责任链模式
  • 【Android】 Eclipse : ERROR: Unknown option '--no-crunch'的解决办法
  • __proto__ 和 prototype的关系
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • 4. 路由到控制器 - Laravel从零开始教程
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • echarts的各种常用效果展示
  • Linux中的硬链接与软链接
  • Mysql优化
  • node入门
  • Promise面试题,控制异步流程
  • React+TypeScript入门
  • SQL 难点解决:记录的引用
  • windows下mongoDB的环境配置
  • XForms - 更强大的Form
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 如何设计一个微型分布式架构?
  • 如何选择开源的机器学习框架?
  • 设计模式 开闭原则
  • 深度解析利用ES6进行Promise封装总结
  • 微信公众号开发小记——5.python微信红包
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • # 数据结构
  • #Ubuntu(修改root信息)
  • (27)4.8 习题课
  • (java版)排序算法----【冒泡,选择,插入,希尔,快速排序,归并排序,基数排序】超详细~~
  • (NO.00004)iOS实现打砖块游戏(十二):伸缩自如,我是如意金箍棒(上)!
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (zhuan) 一些RL的文献(及笔记)
  • (草履虫都可以看懂的)PyQt子窗口向主窗口传递参数,主窗口接收子窗口信号、参数。
  • (二)c52学习之旅-简单了解单片机
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (过滤器)Filter和(监听器)listener
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (转)利用PHP的debug_backtrace函数,实现PHP文件权限管理、动态加载 【反射】...
  • .NET 4.0网络开发入门之旅-- 我在“网” 中央(下)
  • .NET gRPC 和RESTful简单对比
  • .net/c# memcached 获取所有缓存键(keys)
  • .NET导入Excel数据
  • .net实现头像缩放截取功能 -----转载自accp教程网
  • .Net中间语言BeforeFieldInit