Bitbake语法

1.基础语法

1.1 基础变量设置

下面的例子将VARIABLE赋值为"value"。当语句被解析时,赋值立刻生效。它是一种”硬(hard)“赋值。

VARIABLE = "value"

正如预期的,如果将前导(leading)或拖尾(trailing)空格包含在赋值中,这些空格会被保留。

VARIABLE = " value"
VARIABLE = "value "

将VARIABLE赋值为”“,会将它设为一个空字符串;但是将VARIABLE赋值为 ” “,会将它设为空格。

VARIABLE = ""
VARIABLE = " "

1.2 变量展开

Bitbake使用一种类似shell脚本的语法,支持变量引用另一个变量的内容。下面的例子展示了这一语法

A = "aval"
B = "pre${A}post"

A的当前值为"aval",B的值为"preavalpost"。但
要注意,在任意时刻,B的值都会依赖当时A的值。

1.3 设置默认值(?=)

可以使用”?=“对一个变量进行”软(soft)“赋值。如果在该语句被解析时,变量还未被定义,那么这种类型的赋值允许你定义一个变量;但是如果变量已经有值,那么原值将会保留。例如

A ?= "aval"

如果在上述语句执行时,A已经被赋过值,那么A保持之前的值;如果A没有被赋过值,它将被赋值为"aval"。

注意:这种类型的赋值也是立即生效的。也就是说,如果存在对一个变量的多次"?="赋值,只有第一次赋值有效。

1.4 设置弱(weak)默认值(??=)

可以使用”??=“运算符进行”更弱“的赋值。这种赋值除了在解析完成时才会生效,其他与"?=“完全一致。也就是说,如果对同一变量存在多个”??=“赋值,最后一个有效。此外,任意”=“或”?=“类型的赋值会覆盖”??=="类型的赋值。
例如

A ??= "somevalue"
A ??= "someothervalue"

如果A在上面的语句被解析前已经赋过值(这里应该是??=以外类型的赋值吧?),那么它保留之前的值;如果之前没有被赋过值,A将被设为"someothervalue"。

1.5 立即变量展开(:=)

":="操作符导致一个变量的内容被立即展开,而不是当它被实际使用时,例如

T = "123"
A := "${B} ${A} test ${T}"
T = "456"
B = "${T} bval"
C = "cval"
C := "${C}append"

A的值是”test 123“,因为对A进行":="赋值的语句被解析时,${B} 和 ${A}都是未定义的。

1.6 带有空格的向后追加(+=)和向前追加(=+)

”+=“和”=+“在当前值和新追加的值之间会插入一个空格。例如

B = "bval"
B += "additionaldata"
C = "cval"
C =+ "test"

B的值是"bval additionaldata",C的值是"test cval"。

1.7 不带空格的向后追加(+=)和向前追加(=+)

”+=“和”=+“在当前值和新追加的值之间不会插入空格。例如

B = "bval"
B .= "additionaldata"
C = "cval"
C =. "test"

B的值是"bvaladditionaldata" ,C的值是"testcval".

1.8 向后追加和向前追加(覆盖风格语法)

也可以使用覆盖风格语法来对一个变量进行向后或向前追加,使用这种语法,在当前值和新追加的值之间不会插入空格,类似”.=“和”=.“。但它们与”.=“和”=.“的不同在于,它们在解析完成后才会生效。

例如

B = "bval"
B_append = " additional data"
C = "cval"
C_prepend = "additional data "
D = "dval"
D_append = "additional data"

B变成 “bval additional data” ,C变成 “additional data cval”,D变成 “dvaladditional data”.

1.9移除(覆盖风格语法)

可以使用覆盖风格的移除语法从列表中移除值,变量中出现的所有待移除值都会被移除。
使用该语法时,Bitbake期望一个或多个字符串。周围的空格也会被移除。例如:

FOO = "123 456 789 123456 123 456 123 456"
FOO_remove = "123"
FOO_remove = "456"
FOO2 = "abc def ghi abcdef abc def abc def"
FOO2_remove = "abc def"

变量FOO成为”789 123456“,变量FOO2成为”ghi abcdef“。

1.10变量标记语法

变量标记是Bitbake对变量属性的实现方式。它是在一个变量上标记其他信息的一种方式。

可以定义、向后追加和向前追加值到变量标记。前面提到的除了覆盖风格语法(_prepend、_append和_remove)之外的标准语法操作也适用于变量标记。例如

 FOO[a] = "abc"
 FOO[b] = "123"
 FOO[a] += "456"

变量FOO有两个标记:a和b。它们的值分别被立刻设置为”abc“和”123“。然后a的值变成了”abc 456“(原文中是"abc456",应该是写错了)。

1.11 内联(inline)Python变量展开

可以使用内联python变量扩展来为变量赋值。例如

DATE = "${@time.strftime('%Y%m%d',time.gmtime())}"

DATE变量被赋值为当前的日期。

1.12 提供路径名

当指定路径名给Bitbake使用时,不要使用"~"作为家目录的缩写。这可能导致Bitbake无法识别该路径。
相反,应像下面的例子一样,提供一个完整的路径

BBLAYERS ?= " \
       /home/scott-lenovo/LayerA \
       "

2.条件语法(Overrides)

Bitbake使用OVERRIDES来控制在Bitbake解析recipes和配置文件后哪些变量被覆盖。

  • 这一节有一些难懂!!!!!!

2.1 条件元数据

可以使用OVERRIDES来有条件的选择一个变量的指定版本 和/或 有条件的前向追加或后向追加值到一个变量。

  • 选择一个变量:OVERRIDES变量是一个冒号(:)分隔的列表,其中的项目用来满足前提。因此,如果你有一个变量以”arm“为前提,且”arm“在OVERRIDES中,那么"arm"特定版本的变量会被使用,而不是无条件的版本。例如
OVERRIDES = "architecture:os:machine"
TEST = "default"
TEST_os = "osspecific"
TEST_nooverride = "othercondvalue"

在这个例子中,OVERRIDES变量列出了三个重写/覆盖(overrides):”architecture“、”os“和”machine“。变量TEST具有默认值"default",你通过在TEST后面追加os重写(override)来选择os指定版本的TEST变量。

  • 向后追加与向前追加:Bitbake也支持根据一个特定项目是否在OVERRIDES中,来对一个变量进行向后追加或向前追加。例如,
DEPENDS = "glibc ncurses"
OVERRIDES = "machine:local"
DEPENDS_append_machine = "libmad"

在这个例子中,DEPENDS变成”glibc ncurses libmad“。

2.2 Key展开

Key expansion happens when the BitBake datastore is finalized just before BitBake expands overrides. 例如,

 A${B} = "X"
 B = "2"
 A2 = "Y"

在这个例子中,在所有的解析完成后,在重写(overrides)被处理之前,Bitbake将${B}展开成2。这个展开导致前被设置为”Y“的A2变成”X“。

3.共享功能

Bitbake允许通过包含(include)文件(.inc)和类(class)文件(.bbclass)来共享元数据。例如,假设你有一些通用功能(例如一个任务定义)想要在多个recipe之间共享。可以创建一个包含通用功能的.bbclass文件,然后在recipes中使用inherit指令继承这个类。
本节介绍Bitbake提供的在recipes之间共享功能的机制,包括include、inherit、INHERIT和require指令。

3.1定位包含文件和类文件

Bitbake使用BBPATH变量来定位需要的包含文件和类文件。BBPATH变量与环境变量PATH类似。
为了使Bitbake能找到包含文件和类文件,它们需要被放在一个可以在BBPATH中找的路径的"classes"子目录中。

3.2 inherit指令

编写recipe或class文件时,可以使用inherit指令来继承一个类的功能。Bitbake只在recipe和class文件中支持该指令。

inherit指令是说明recipe需要哪些功能类(classes of functionality)的基础方法。例如,可以很容易地抽象出使用Autoconf和Automake构建一个包时所涉及到的任务,将这些任务放在一个可以被recipe使用的class文件中。

作为例子,你的recipes可以使用下面的指令来继承autotools.bbclass文件。这个class文件包含可以在recipes间共享的、使用Autotools的通用功能:

inherit autotools

在这个例子中,Bitbake将会在BBPATH中搜村文件classes/autotools.bbclass。

在”inherit“语句之后,可以在recipe中重写继承来的值和函数。

3.3 include指令

Bitbake理解include指令。该指令导致Bitbake解析被include指令指定的文件,并将该文件插入include指令的位置。如果include指令指定的是一个相对路径,Bitbake会使用它在BBPATH中找到的第一个文件。

作为例子,假设你要在一个recipe中包含一些自我测试定义

include test_defs.inc

注意:指定的文件不存在时,include指令不会产生错误。如果指定的文件不存在时需要产生错误,推荐使用require。

3.4 require指令

Bitbake理解require指令。require指令与include指令类似,但在被指定的文件不存在是会产生解析错误。

require指令指定的文件会被插入到require指令所在的位置。

如果require指令指定的是一个相对路径,Bitbake会使用它在BBPATH中找到的第一个文件。

require foo.inc

3.5 INHERIT配置指令

编写配置文件(.conf)时,可以使用INHERIT指令来继承一个类。Bitbake只在配置文件中支持该指令。
作为例子,假设你要在一个配置文件中继承一个名为abc.bbclass的类文件

INHERIT += "abc"

与inherit指令一样,.bbclass文件必需放在BBPATH所包含的目录中的其中一个的classes子目录中。

4.函数

Bitbake支持以下类型的函数

  • shell函数
  • Bitbake风格的python函数
  • python函数
  • 匿名python函数
    不管是哪种类型的函数,只能被定义在class文件(.bbclass)和recipe文件(.bb)中。

4.1 Shell函数

Functions written in shell script and executed either directly as functions, tasks, or both. They can also be called by other shell functions.例如

some_function () {
         echo "Hello World"
     }

编写shell函数是,需要遵循shell编程规则,不能使用Bash特定脚本。

4.2 Bitbake风格的python函数

这些函数使用python编写,被Bitbake或其他python函数使用bb.build.exec_func()调用。例如

python some_python_function () {
         d.setVar("TEXT", "Hello World")
         print d.getVar("TEXT", True)
     }

由于Python的”bb“和”os“模块已经被导入,不需要再次导入这些模块。另外在该类型的函数中,数据存储(datastore,“d”)是一个全局变量,且总是自动可用的。

4.3 python函数

这些函数使用python编写,被其他python代码执行。例如

def get_depends(d):
         if d.getVar('SOMECONDITION', True):
             return "dependencywithcond"
         else:
             return "dependency"
     SOMECONDITION = "1"
     DEPENDS = "${@get_depends(d)}"

该例子使得DEPENDS变量的值为dependencywithcond。

还有一些关于python函数的信息需要知道

  • python函数可以接受参数
  • Bitbake数据存储不是自动可用的。因此,要将它作为参数传递。
  • ”bb“和”os“模块已经是自动可用的,不需要再次引入。

4.4 匿名python函数

有时,在解析过程中执行一些代码来设置变量或者程序化地执行一些操作是很有用的。为此,可以定义匿名python函数。例如

python __anonymous () {
         if d.getVar('SOMEVAR', True) == 'value':
             d.setVar('ANOTHERVAR', 'value2')
     }

”__anonymous“函数名是可选的,所以下面的例子与上面是等价的

 python () {
         if d.getVar('SOMEVAR', True) == 'value':
             d.setVar('ANOTHERVAR', 'value2')
     }

与其他python函数不同,匿名python函数在解析过程中被执行。匿名python函数中的"d"变量代表了整个recipe的数据存储,因此,你可以在这里设置变量值并在其他函数中使用。

  • datastore????

4.5 对类函数的灵活继承

通过编码技巧和使用EXPORT_FUNCTIONS,Bitbake支持从一个类中导出一个函数,使得类函数成为那个函数的默认实现,但当一个继承了该类的recipe要实现该函数的时,类实现仍然可以被调用。(Through coding techniques and the use of EXPORT_FUNCTIONS, BitBake supports exporting a function from a class such that the class function appears as the default implementation of the function, but can still be called if a recipe inheriting the class needs to define its own version of the function.)

要理解该功能带来的好处,考虑如下的基本场景:一个类定义了一个任务函数(task function),你的recipe继承了这个类。在这个基本场景中,你的recipe继承了类中定义的任务函数。如果有需要,你的recipe可以分别使用"_prepend"和”_append“在函数的起始或结束出增加,也可以完全重定义这个函数。但是,如果recipe重定义该函数,就没有办法调用该函数的类版本。EXPORT_FUNCTIONS提供了一种机制,使得该函数的recipe版本可以调用该函数的原始版本(类版本)。

要使用该机制,需要以下操作

  • 在类中,要按如下方式定义函数
<classname>_<functionname>

例如,如果你有一个类文件bar.bbclass和一个名为do_foo的函数,类必需以如下方式定义函数

bar_do_foo
  • 在类中,要按如下方式包含EXPORT_FUNCTIONS语句
EXPORT_FUNCTIONS <functionname>

例如,承接上面的例子,bar.bbclass中的语句为

EXPORT_FUNCTIONS do_foo
  • 在自己的recipe中要以适当的方式调用函数
    承接上面的例子,如果你的recipe要调用类版本的函数,要调用bar_do_foo。假设do_foo是一个shell函数并且按照上面的方式使用了EXPORT_FUNCTIONS,recipe版本的函数可以有条件的调用类版本的函数,例如
do_foo() {
             if [ somecondition ] ; then
                     bar_do_foo
             else
                     # Do something else
             fi
     }

要在自己的recipe中调用修改版的函数,调用do_foo即可。

如果上述条件都满足,那么可以在recipe中选择使用类中定义的原始函数或recipe中的修改版;否则,只能二选一使用。

5.任务

任务(task)是Bitbake的执行单元,它源自函数,构成了Bitbake运行一个给定recipe时需要的步骤。任务只能出现在recipe(.bb或.inc)和class(.bbclass)文件中。按照惯例,任务名以字符串"do_"开头。
下面是一个示例任务,它打印日期

python do_printdate () {
         import time
         print time.strftime('%Y%m%d', time.gmtime())
     }
     addtask printdate after do_fetch before do_build

5.1 将函数提升为任务

任何函数都可以使用addtask命令提升为任务。addtask命令还描述了任务间的依赖关系。下面的例子使用了上一节的函数,但是使用了addtask将它提升为一个任务,并定义了一些依赖关系:

python do_printdate () {
         import time
         print time.strftime('%Y%m%d', time.gmtime())
     }
     addtask printdate after do_fetch before do_build

在这个例子中,函数首先被定义,然后被提升为任务。do_printdate任务成为do_build任务的依赖。do_build任务是默认任务。do_printdate任务会依赖于do_fetch任务。do_task任务的执行,会导致do_printdate任务首先被执行。

5.2 删除一个任务

除了可以添加任务,还可以删除任务。删除任务可以使用deltask命令。例如,要删除前面的示例任务,需要使用

deltask printdate

5.3 传递信息到构建任务环境(Build Task Environment)

当运行一个任务时,Bitbake严格控制构建任务的执行环境,以确保来自构建主机的不想要的污染不会污染构建。所以,如果想要传递信息到构建任务环境,需要执行一下两个步骤:

  1. 告诉Bitbake从环境变量加载你想要的信息到datastore。可以通过BB_ENV_EXTRAWHITE变量达到这一目的。例如,假设你想要阻止构建系统访问$HOME/.ccache目录。下面的命令告诉Bitbake从环境变量加载CCACHE_DIR到datastore:
export BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE CCACHE_DIR"
  1. 告诉Bitbake将你加载到datastore中的变量导出每个正在运行的任务的任务环境。从环境变量加载信息到datastore中只能让信息在datastore中可以使用。要将它导出到每个正在运行的任务的任务环境,需要在本地配置文件local.conf或发行版配置文件中添加类似以下的命令
export CCACHE_DIR

有时,从原始执行环境中获取信息是很有用的。Bitbake保存了原始执行环境的一个拷贝在名为BB_ORIGENV的特殊变量中。

BB_ORIGENV变量返回一个datastore对象,可以使用标准的datastore操作,例如getVar()对它进行查询。

默认情况下,Bitbake清理环境变量,只会包含那些被导出或在其白名单中列出的东西,以确保构建环境是一致、可复现的。

6.变量标记(variable flags)

变量标记(varflags)帮助控制任务的功能和依赖。Bitbake使用如下命令从datastore中读写varflags

<variable> = d.getVarFlags("<variable>")
self.d.setVarFlags("FOO", {"func": True})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值