语言介绍

Qbs使用项目文件 (*.qbs) 描述项目的内容。一个项目包含一个或多个产品。产品是构建过程的目标,通常是应用程序、库或是压缩包。

注意:假设Qbs源文件使用UTF-8编码。

必要的Hello World示例

Qbs项目文件使用QML方言编写。一个非常简单的C++hello world项目看起来像这样

---helloworld.qbs---
Application {
    name: "helloworld"
    files: "main.cpp"
    Depends { name: "cpp" }
}

Application描述了我们想要构建的产品。在这种情况下,是一个应用程序。这仅是一个方便书写的快捷方式

Product {
    type: "application"
    // ...
}

名称是产品的名称。在这种情况下,它也是生成可执行文件(在Windows上,默认添加".exe"扩展名)的名称。

在属性files中,我们指定产品的源文件。与QML不同,右侧可以是字符串或字符串列表。单个字符串转换为只包含一个元素的字符串列表。所以我们也可以这样写

files: [ "main.cpp" ]

Depends将依赖项添加到cpp模块。这是必要的,以便让Qbs知道我们有C++项目,并希望使用C++编译器编译main.cpp。有关Qbs模块的更多信息,请参阅模块

重用项目文件代码

QML类似继承也适用于Qbs。

---CrazyProduct.qbs---
Product {
    property string craziness: "low"

    files: [
        "Crazy.h",
        "Crazy.cpp"
    ]
}

---hellocrazyworld.qbs---
import "CrazyProduct.qbs" as CrazyProduct

CrazyProduct {
    craziness: "enormous"
    name: "hellocrazyworld"
    files: base.concat(["main.cpp"])
    // ...
}

您可以将JS代码放入单独的.js文件中,然后导入它们。

---helpers.js---
function planetsCorrectlyAligned()
{
    // implementation
}

---myproject.qbs---
import "helpers.js" as Helpers

Product {
    name: "myproject"
    Group {
        condition: Helpers.planetsCorrectlyAligned()
        file: "magic_hack.cpp"
    }
    // ...
}

有关特殊属性值的更多详细信息和base属性,请参阅。

模块

模块是一组属性和语言项目,如果产品依赖于(或加载)该模块,则用于构建产品。

例如,cpp模块看起来像这样(简化版):

Module {
    name: "cpp"
    property string warningLevel
    property string optimization
    property bool debugInformation
    property pathList includePaths
    // ...
    FileTagger {
        patterns: "*.cpp"
        fileTags: ["cpp"]
    }
    Rule {...}  // compiler
    Rule {...}  // application linker
    Rule {...}  // static lib linker
    Rule {...}  // dynamic lib linker
}

可以为cpp模块设置的属性用于控制您的C++工具链的行为。此外,您可以将后面解释的FileTaggers和Rules。

一旦产品依赖于模块,它就可以设置模块的属性。您可以使用以下方式指定产品的优化级别(以及所有构建变体)

Application {
    name: "helloworld"
    files: ["main.cpp"]
    cpp.optimization: "ludicrousSpeed"
    Depends { name: "cpp" }
}

模块可以依赖于其他模块。例如,Qt.core模块依赖于cpp模块。模块依赖是传递性的,即在一个产品中,所有依赖的模块都是可访问的

Application {
    name: "helloworld"
    files: ["main.cpp"]
    Depends { name: "Qt.core" }
    // the "cpp" module is available since
    // "Qt.core" depends on "cpp".
    cpp.optimization: "ludicrousSpeed"
}

单个文件的不同属性

不仅产品,产品的所有源文件也可以有自己的模块属性集。例如,假设您有一些文件,如果您打开优化选项,则这些文件会导致编译器崩溃。您只想为这些文件关闭优化,这是如何做到的

Application {
    name: "helloworld"
    files: "main.cpp"
    Group {
        files: ["bad_file.cpp", "other_bad_file.cpp"]
        cpp.optimization: "none"
    }
    Depends { name: "cpp" }
}

通过属性选择文件

有时你会有一个文件只会在特定平台上编译。这样做就可以了

Group {
    condition: qbs.targetOS.includes("windows")
    files: [
        "harddiskdeleter_win.cpp",
        "blowupmonitor_win.cpp",
        "setkeyboardonfire_win.cpp"
    ]
}
Group {
    condition: qbs.targetOS.includes("linux")
    files: [
        "harddiskdeleter_linux.cpp",
        "blowupmonitor_linux.cpp",
        "setkeyboardonfire_linux.cpp"
    ]
}

在上面的例子中,qbs.targetOSqbs 模块的属性。这个 qbs 模块总是被隐式加载。它的主要属性包括

  • buildVariant 指定当前编译的构建变体名称。
  • targetOS 指定你想为该项目构建的操作系统。

你可以在命令行或使用配置文件来设置这些属性。

$ qbs                             # qbs.buildVariant:debug, profile:<default profile> (or profile:none, if no default profile exists)
$ qbs config:release              # qbs.buildVariant:release, profile:<default profile>
$ qbs config:debug config:release # builds two configurations of the project
$ qbs profile:none                # all module properties have their default values

通过构建变体选择文件

Group {
    condition: qbs.buildVariant == "debug"
    files: "debughelper.cpp"
}

为构建变体设置属性

Properties {
    condition: qbs.buildVariant == "debug"
    cpp.debugInformation: true
    cpp.optimization: "none"
}

或者,使用更类似 QML 的风格

cpp.debugInformation: qbs.buildVariant == "debug" ? true : false
cpp.optimization: qbs.buildVariant == "debug" ? "none" : "fast"

属性类型

虽然 Qbs 中的属性通常与 QML 中的使用方式相同,但可能支持的属性类型集合已经根据构建工具的具体需求进行了调整。支持的类型如下

属性类型示例描述
boolproperty bool someBoolean: false常用的布尔值。
intproperty int theAnswer: 42整数。
pathproperty path aFile: "file.txt"文件路径相对于产品所在目录解析。
pathListproperty pathList twoFiles: ["file1.txt", "./file2.txt"]一系列 path 类型的值。
stringproperty string parentalAdvisory: "explicit lyrics"JavaScript 字符串。
stringListproperty stringList realWorldExample: ["no", "not really"]JavaScript 字符串列表。
varproperty var aMap: ({ key1: "value1", key2: "value2" })通用数据,如 QML 中一样。
varListproperty var aMapList: [{ key1: "value1", key2: "value2" }, { key1: "value3" }]通用数据列表,通常是 JavaScript 对象。

从命令行覆盖属性值

可以在命令行中覆盖项目文件或配置文件中设置的属性值。语法是 <prefix>.<prop-name>:<prop-value>。以下命令行演示了如何设置不同类型的属性

$ qbs projects.someProject.projectProperty:false          # set a property of a project
$ qbs products.someProduct.productProperty:false          # set a property of a product
$ qbs modules.cpp.treatWarningsAsErrors:true              # set a module property for all products
$ qbs products.someProduct.cpp.treatWarningsAsErrors:true # set a module property for one product

命令行上的属性值也可以采用 JavaScript 表达式,就像你在项目文件中写入的方式一样。请确保正确引用,以免外壳本身解释任何值。如果字符串中不包含特殊字符,则 stringList 类型的属性也可以作为以逗号分隔的值提供

$ qbs projects.someProject.listProp:'["a", "b", "c"]'
$ qbs projects.someProject.listProp:a,b,c               # same as above
$ qbs projects.someProject.listProp:'["a b", "c"]'      # no CSV equivalent

文件标签和标签器

Qbs 本身对 C++ 文件或文件扩展名一无所知。产品中的所有源文件都平等处理。但是,你可以为工件分配 文件标签,用作标记或指定文件类型。

一个工件可以有多个文件标签。例如,你可以使用 Group 项来分组具有相同文件标签(或一组属性)的文件。

Product {
    Group {
        files: ["file1.cpp", "file2.cpp"]
        fileTags: ["cpp"]
    }
    Group {
        files: "mydsl_scanner.l"
        fileTags: ["flex", "foobar"]
    }
    // ...
}

当你加载 cpp 模块时,你也加载以下项

FileTagger {
    patterns: "*.cpp"
    fileTags: ["cpp"]
}

这个结构表示所有符合模式 *.cpp(且没有显式设置文件标签)的源文件都会获得文件标签 cpp

上面的例子可以简化为

Product {
    Depends: "cpp"
    files: ["file1.cpp", "file2.cpp"]
    Group {
        files: "mydsl_scanner.l"
        fileTags: ["flex", "foobar"]
    }
    // ...
}

FileTaggercpp 模块自动将 cpp 文件标签分配给源文件。只需要包含 files 属性的群组可以用产品中 files 属性的 files 属性更简单地表达。

文件标签被规则用于将一种工件转换为另一种工件。例如,C++ 编译器规则将具有文件标签cpp的工件转换为具有文件标签obj的工件。

此外,可以使用文件标签器来标记文件并指定自定义文件标签

Product {
    Depends: "cpp"
    Group {
        overrideTags: false     // The overrideTags property defaults to true.
        fileTags: ["foobar"]
        files: ["main.cpp"]     // Gets the file tag "cpp" through a FileTagger item and
                                // "foobar" from this group's fileTags property.
    }
    // ...
}

规则

Qbs将对一组工件(最初是项目源文件集合)应用规则,并选择符合规则指定的输入文件标签的工件。然后,它在构建图中创建具有其他文件名和文件标签的输出工件。它还创建一个脚本,将输入工件转换为输出工件。一个规则创建的工件可以(也通常)用作另一个规则的输入。通过这种方式,规则通过它们的输入和输出文件标签相互连接。

有关规则的示例,请参阅Qbs存储库中的share/qbs/modules目录。

您可以在自己的模块中定义规则,并将其与项目一起提供。或者,您可以直接在项目文件中放置规则。

有关更多信息,请参阅规则

©2023 Qt公司有限公司。本文档包含的贡献的版权属于各自的所有者。本文档按由自由软件基金会发布、内容授权许可协议版本1.3的GNU自由文档许可证条款许可。