Qt构建工具QBS之一 ——从一个简单的工程开始

来源:互联网 发布:淘宝退货的运费险理赔 编辑:程序博客网 时间:2024/06/09 22:48

在这篇文章中通过在一个简单的工程初步了解 Qbs 是怎么构建一个工程的, 涉及到的语言项有 Product, Application, CppApplication, Depends, FileTagger, Group. 涉及到的模块有 cpp 和 qbs 模块.

创建一个简单的工程

按下列步骤创建一个简单的工程, 本系列文章都将基于这个工程来做讲解实验.

  1. 打开 Qt Creator
  2. 单击菜单 [文件]->[新建文件或项目] 打开对话框
  3. 在左边项目下面选择 [Non-Qt Project], 中间选择 [Plain C++ Application], 单击按钮 [Choose…]
  4. 名称: 输入 QbsDemo, 单击按钮 [下一步]
  5. 构建系统选择 Qbs, [下一步]
  6. [下一步]
  7. [完成]
  8. 构建运行. 正常的情况应该会在控制台中输出 Hello World!

Product 及其派生出的 CppApplication 和 Application.

打开 QbsDemo.qbs 文件, 可以看到内容如下

import qbsCppApplication {    type: "application" // To suppress bundle generation on Mac    consoleApplication: true    files: "main.cpp"    Group {     // Properties for the produced executable        fileTagsFilter: product.type        qbs.install: true    }}

对于非 Mac 平台上, 第 4 行的 type: "application" // To suppress bundle generation on Mac 是不需要的. 因为 CppApplication 派生自 Application, 而 Application 已经隐含了 type: "application" 了. 为了更清晰些, 删掉第4行, 构建运行, 可以验证没什么影响.

由上一篇文章我们已经知道 CppApplication 派生自 Application. 其等效于 Application, 加上对 “cpp” 模块的依赖.

将 QbsDemo.qbs 中的内容改成如下, 可以验证之(第 4 行加入了 cpp 模块依赖)

import qbsApplication {    Depends { name: "cpp" }    consoleApplication: true    files: "main.cpp"    Group {     // Properties for the produced executable        fileTagsFilter: product.type        qbs.install: true    }}

注: 可以先去掉第 4 行的 Depends { name: "cpp" }, 构建运行, 发现无法运行, 因为没有生成可执行程序.

同样再看派生了 Application 的 Product 项. 同样上面的代码可以改成(第 4 行指定了类型为 “application”)

import qbsProduct {        type: "application"    Depends { name: "cpp" }    consoleApplication: true    files: "main.cpp"    Group {     // Properties for the produced executable        fileTagsFilter: product.type        qbs.install: true    }}

注: 同样可以先去掉第 4 行的 type: "application", 构建后也无法运行

所以上一篇文章列出 30 个语言项, Product 及其派生的项可以看成一个, 剩下就 10 几个语言项了, 而一般能用到的就更少了. 所以 Qbs 也还是挺简单的.


属性

再看代码中 type: "application"consoleApplication: true 这样的键值对语句. 这是是相应语言项/模块的属性和属性值. 这里的几个属性都是 Product 的属性值, 其中:

  • type 指出了该 Product 是一个可执行程序. 常用的类型还有 dynamiclibrary(动态库), staticlibrary 静态库.
  • consoleApplication 指出了是否是一个控制台程序
  • files 则列出了源文件(不仅仅只是 C++头文件和源文件, 以后会看到)

以后会见到更多各种语言项/模块的属性, 完整的属性和属性用法说明参加相关语言项/模块的各自文档.


Depands 项

Depends 就是添加依赖模块, 通过 name 属性指定要引入模块的名称, 如上面的 “cpp” 模块是 Qbs 自带的预定义模块, 用来处理 C/C++, Objective-C/C++ 源码. 有点类似于 qmake 中 Qt += core gui, qmake 通过这样的方式添加了对 core, gui 模块的依赖.

目前对模块的理解, 只需有个大致的理解即可, 后面会通过学习自定义模块来进一步理解模块.


FileTagger 项

现在来先看一个上面代码未出现过的 FileTagger 项. 为什么先讲这个, 基于三个原因:

  1. 这个语言项很简单, 只有 2 个属性, 是所有语言项中属性最少
  2. 没有理解这个语言项, 影响其它好几个语言项的理解, 包括上面已经出现过的 Group 项
  3. 理解了这个语言项, 能或多或少对 Qbs 整个运行机制有点模糊的理解.

FileTagger 的两个属性: patterns 和 fileTags, 前者指定了匹配模式, 后者为文件标记名.

先不对 FileTagger 作更详细的讲解, 我们先来做几个实验, 做实验之前想几个问题:

  • Qbs 为什么会认为 main.cpp 是 C++ 源代码, 而不是一个资源文件之类的?
  • 是因为它的扩展名 .cpp 吗?
  • 把它的扩展名改成别的, 还能成功构建出 Hello World程序吗?
  • 如果不能构建出来, 那么在扩展名已改的情况下, 如何让 Qbs 依然认为这个文件是 C++ 源代码呢?

现在把 main.cpp 的文件名改成 main.src, 将 QbsDemo.qbs 中的内容修改成:

import qbsProduct {        type: "application"    Depends { name: "cpp" }    consoleApplication: true    files: "main.src"    Group {     // Properties for the produced executable        fileTagsFilter: product.type        qbs.install: true    }}

如上, 修改的地方在第 8 行, main.cpp 改成了 main.src了.

构建运行, 发现没有生产可执行程序.

现在请出 FileTagger, 将上面代码修改成:

import qbsProduct {        type: "application"    Depends { name: "cpp" }    consoleApplication: true    files: "main.src"    FileTagger {        patterns: "main.src"        fileTags: "cpp"    }    Group {     // Properties for the produced executable        fileTagsFilter: product.type        qbs.install: true    }}

构建运行, Hello World又出来了.

再将 mian.src 文件名改成 main1.src, QbsDemo.qbs 文件中的 files: “main.src” 改成 files: “main1.src”, 注意: 这里 patterns: “main.src” 暂时不改.

构建运行, 不行, 将 patterns: “main.src” 改成 patterns: “main1.src” 则又可以了.

还有一种解决方案则是将改成 patterns: “*.src”, 也就是匹配模式支持通配符, 用来表示所有扩展名为 src 的文件都将视为 C++ 源文件.

fileTags: “cpp” 这里的fileTags为什么是 “cpp”, 可以是别的吗? 答案是一般情况是不行的. 因为这是由 Depends { name: “cpp” } 引入的 cpp 模块决定的(注意是由这个模块决定的, 和 name: “cpp” 中的那个 cpp 是没什么直接联系的). 我们打开 Qbs 自带的文件 CppModule.qbs (cpp 模块就是在这个文件中定义的), 看看 cpp 这个标记名是怎么定义的:

FileTagger {    patterns: ["*.C", "*.cpp", "*.cxx", "*.c++", "*.cc"]    fileTags: ["cpp"]}

和我们刚才定义的形式有点不一样, 我们没这个 [], 说明这两个属性是一个列表, 只有一个值时这个[]可以省略.

这里我们可以看出 cpp 模块认为扩展名为 C/cpp/cxx/c++/cc 的文件是 C++ 源码.

Group 项

Group 项是将一组在某些行为上是一样的文件组合成一组. 比如某些将安装到同一目录下的文件, 某些 Windows 平台上需要的文件, 某些 Linux 平台上需要的文件.

注意: Group 分组的对象是文件, 如果 Group 项内没有指定有效文件, 那么这个 Group 是会被忽略的.

Group 项指定文件可以用 files 属性或 fileTagsFilter 属性, 这两个属性是互斥的, 只能用其一.

files: 指定文件列表, 如同 Product 项中的 files.

fileTagsFilter: 指定文件标记名, 通过标记名来匹配文件. 标记名就是上文那样使用 FileTagger 定义出来的.

回到 QbsDemo.qbs 中 Group 项

Group {     // Properties for the produced executable    fileTagsFilter: product.type    qbs.install: true}

这里的 Group 指定文件的方式就是用文件标记名, product.type 就是 Product 项的 type 的属性值, 在这里等效于 fileTagsFilter: “application”. 另外说一句, Product 内的任何一个子项都可以使用 product.属性名 的方式访问 Product 项的属性值.

qbs.install: true 表明这些文件是用于安装的. qbs 是一个模块, 在每个产品中, 都会隐含这个模块的依赖. 这个模块包含了一些常用的基本属性. 那么文件安装到哪呢? 安装到 qbs.installDir 指定的位置, 这里没有指定则默认安装到构建目录下的 install-root 目录下. 更多关于 qbs 模块的信息, 可以参考文档中关于 qbs 模块的说明.

可以去 install-root 目录下找找, 应该有一个 QbsDemo.exe.

现在假如我们需要把 C++ 源文件也安装过去(这只是个实验, 现实中这么做应该没什么太大的意义), 我们可以这么做:

import qbsProduct {    type: "application"    Depends { name: "cpp" }    consoleApplication: true    files: "main1.src"    FileTagger {        patterns: "*.src"        fileTags: "cpp"    }    Group {     // Properties for the produced executable        fileTagsFilter: [product.type[0], "cpp"] // product.type        qbs.install: true    }}

如上, 我们在fileTagsFilter, 又加入了一个标记名 “cpp”, 注意: type后面那个[0], 因为 product.type 实际是一个列表. 也可以写成 fileTagsFilter: product.type.concat(“cpp”).

构建后, 去 install-root 目录下除了 QbsDemo.exe 外, 应该还有一个 main1.src.

一个小练习:

创建一个工程, 其有两个 C++ 源文件, 一个为 main1.cpp, 一个为 main2.cpp, 下面两者环境选一个即可

  1. 分别生成一个32位程序和一个64位程序, 如果检查到环境为 x86 架构使用 main1.cpp 输出 Hello X86, 如果是 x64 架构使用 mian2.cpp 输出 Hello X64. (这个环境需要装32bit和64bit两个Qt)
  2. 根据平台, 如果是 Windows 平台使用 main1.cpp 输出 Hello Windows, 如果是 Linux 平台使用 main2.cpp 输出 Hello Linux. (这个环境需要两个操作系统)

使用 Group 来实现怎么来选择对应的源文件, 两个环境根据自身哪个方便来选择, 也可以自己设计个实验做.

结尾

这篇文章初步认识了 QBS, 其实很 qmake 的 pro 文件差不多, 也都是由 Qt Creator 自动生成的, 对于使用惯了 qmake 的人来说, 可能里面的东西不多, 但是还是有种不熟悉的感觉. 其实你到后面, 你会发现, 从某种角度来说 QBS 比 qmake 更简单.

比如, qmake 的 pro 文件中有 HEADERS 来指定头文件, SOURCES 来指定 C++ 源文件, FORMS 指定 ui 文件, RESOURCES 指定 qrc 文件, RC_FILE 指定微软的资源文件. 麻烦不? 这个在 QBS 中就简单多了, files 一个属性全包. 全自动分类. 而且 QBS 也是支持直接在 IDE 中删除添加文件的, 怕需要手动写人不用担心了.

也许有人文, 都是自动添加的为什么你就说 QBS 更简单呢? 反正不用手写. 其实很多情况手写是避免不了的, 比如上面提到的那个练习.

下一篇文章, 会通过一个比较实用的例子, 也更能展现 QBS 强大的地方.

最后把工程恢复到原始状态, 为下一篇文章做准备.
即把 main1.src 重命名回 main.cpp, QbsDemo.qbs 恢复为:

import qbsCppApplication {    type: "application" // To suppress bundle generation on Mac    consoleApplication: true    files: "main.cpp"    Group {     // Properties for the produced executable        fileTagsFilter: product.type        qbs.install: true    }}

转载请加上原文链接, 并保证文章的完整性. 鉴于自己的能力可能有表达失当或者错误的地方, 希望大家包含. 如您能提出意见或建议, 本人不甚感激. li_wey AT 163.com

0 0
原创粉丝点击