[yocto] The BitBake equivalent of "Hello, World!"

Rudolf Streif rudolf.streif at linux.com
Thu Oct 4 11:58:58 PDT 2012


[Warning: lengthy post, and probably boring to most.]

My Bitbake "Hello World" is a little more than a basic "Hello World". It's
idea is to incorporate a layer and use a structure similar to what OE and
Yocto are using. You can do it simpler if you want to. I did this a while
ago with Bitbake 1.12.0. I would think it works with newer versions too
although I have not tested it. This is the layout I am using:

bbtest/
├── conf
│   ├── bblayers.conf
│   └── bitbake.conf
├── downloads
│   └── /* need to create but will be populated with downloads */
├── meta-test
│   ├── classes
│   │   └── base.bbclass
│   ├── conf

│   │   └── layer.conf

│   └── recipes-test

│       └── nano

│         └── nano.bb

└── tmp

    └── /* will be created and populated when building */

The first thing Bitbake looks for is a conf/bblayers.conf file in the
directory you started it from. This file must provide an initial setting
for BBPATH:

bblayers.conf:

BBPATH := "${TOPDIR}"
BBFILES ?= ""
BBLAYERS = " \
  ${TOPDIR}/meta-test \
  "

Without BBPATH Bitbake will not find any conf/<filename>.conf files and
recipe files at all. It will also not find bitbake.conf. I simply copied
bitbake.conf from the Bitbake download and edited DL_DIR:

bitbake.conf:

# comments omitted
B = "${S}"

CVSDIR = "${DL_DIR}/cvs"

DEPENDS = ""

DEPLOY_DIR = "${TMPDIR}/deploy"
DEPLOY_DIR_IMAGE = "${DEPLOY_DIR}/images"
DL_DIR = "${TOPDIR}/downloads"
FETCHCOMMAND = ""
FETCHCOMMAND_cvs = "/usr/bin/env cvs -d${CVSROOT} co ${CVSCOOPTS}
${CVSMODULE}"
FETCHCOMMAND_svn = "/usr/bin/env svn co ${SVNCOOPTS} ${SVNROOT}
${SVNMODULE}"
FETCHCOMMAND_wget = "/usr/bin/env wget -t 5 --passive-ftp -P ${DL_DIR}
${URI}"
FILESDIR = "${@bb.utils.which(bb.data.getVar('FILESPATH', d, 1), '.')}"
FILESPATH =
"${FILE_DIRNAME}/${PF}:${FILE_DIRNAME}/${P}:${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/files:${FILE_DIRNAME}"
FILE_DIRNAME = "${@os.path.dirname(bb.data.getVar('FILE', d))}"
GITDIR = "${DL_DIR}/git"
IMAGE_CMD = "_NO_DEFINED_IMAGE_TYPES_"
IMAGE_ROOTFS = "${TMPDIR}/rootfs"
MKTEMPCMD = "mktemp -q ${TMPBASE}"
MKTEMPDIRCMD = "mktemp -d -q ${TMPBASE}"
OVERRIDES = "local:${MACHINE}:${TARGET_OS}:${TARGET_ARCH}"
P = "${PN}-${PV}"
PERSISTENT_DIR = "${TMPDIR}/cache"
PF = "${PN}-${PV}-${PR}"
PN = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[0]
or 'defaultpkgname'}"
PR = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[2]
or 'r0'}"
PROVIDES = ""
PV = "${@bb.parse.BBHandler.vars_from_file(bb.data.getVar('FILE',d),d)[1]
or '1.0'}"
RESUMECOMMAND = ""
RESUMECOMMAND_wget = "/usr/bin/env wget -c -t 5 --passive-ftp -P ${DL_DIR}
${URI}"
S = "${WORKDIR}/${P}"
SRC_URI = "file://${FILE}"
STAMP = "${TMPDIR}/stamps/${PF}"
SVNDIR = "${DL_DIR}/svn"
T = "${WORKDIR}/temp"
TARGET_ARCH = "${BUILD_ARCH}"
TMPDIR = "${TOPDIR}/tmp"
UPDATECOMMAND = ""
UPDATECOMMAND_cvs = "/usr/bin/env cvs -d${CVSROOT} update ${CVSCOOPTS}"
UPDATECOMMAND_svn = "/usr/bin/env svn update ${SVNCOOPTS}"
WORKDIR = "${TMPDIR}/work/${PF}"
PERSISTENT_DIR = "${TMPDIR}/cache"

That's more than you need but it's convenient.

Bitbake will require a base.bbclass file somewhere in a classes
subdirectory of BBPATH. I used the base.bbclass file from the Bitbake
download. As a minimum it should contain a do_build task. That's the target
that Bitbake invokes by default if you do not use the -c option explicitly.
It's empty and does not do anything but it functions as an anchor for tasks
you define in your recipes:

base.bbclass:

# comments omitted
die() {
        bbfatal "$*"
}

bbnote() {
        echo "NOTE:" "$*"
}

bbwarn() {
        echo "WARNING:" "$*"
}

bbfatal() {
        echo "FATAL:" "$*"
        exit 1
}

addtask showdata
do_showdata[nostamp] = "1"
python do_showdata() {
        import sys
        # emit variables and shell functions
        bb.data.emit_env(sys.__stdout__, d, True)
        # emit the metadata which isnt valid shell
        for e in bb.data.keys(d):
                if bb.data.getVarFlag(e, 'python', d):
                        sys.__stdout__.write("\npython %s () {\n%s}\n" %
(e, bb.data.getVar(e, d, 1)))
}

addtask listtasks
do_listtasks[nostamp] = "1"
python do_listtasks() {
        import sys
        for e in bb.data.keys(d):
                if bb.data.getVarFlag(e, 'task', d):
                        sys.__stdout__.write("%s\n" % e)
}

addtask build
do_build[dirs] = "${TOPDIR}"
do_build[nostamp] = "1"
python base_do_build () {
        bb.note("The included, default BB base.bbclass does not define a
useful default task.")
        bb.note("Try running the 'listtasks' task against a .bb to see what
tasks are defined.")
}

EXPORT_FUNCTIONS do_clean do_mrproper do_build

Again, it's more than you need. It's just convenient to use it. I put this
file inside the layer but you can also create a classes directory in
${TOPDIR} (bbtest in this example). Next, create a layer (meta-bbtest in my
example, name does not matter, meta-* is convention). It needs a
conf/layer.con file:

layer.conf:

# We have a metadata layer directory, add to BBPATH
BBPATH .= ":${LAYERDIR}"

# We have a recipe directory, add to BBFILES
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
            ${LAYERDIR}/recipes-*/*/*.bbappend"

BBFILE_COLLECTIONS += "test"
BBFILE_PATTERN_test := "^${LAYERDIR}/"
BBFILE_PRIORITY_test = "5"

The path expression for the recipes is more complex than necessary, it just
follows the convention. Finally a recipe to build the Nano editor:

DESCRIPTION = "Recipe to build the 'nano' editor"

PN = "nano"
PV = "2.2.6"

SRC_URI = "http://www.nano-editor.org/dist/v2.2/nano-2.2.6.tar.gz"

python do_fetch() {
   bb.note("Downloading source tarball from ${SRC_URI} ...")

   src_uri = (bb.data.getVar('SRC_URI', d, True) or "").split()
   if len(src_uri) == 0:
      bb.fatal("Empty URI")

   try:
      bb.fetch.init(src_uri, d)
      bb.fetch.go(d)
   except FetchError:
      bb.fatal("Could not fetch source tarball.")

   bb.note("Download successful.")
}

addtask fetch before do_build


python do_unpack() {
   bb.note("Unpacking source tarball ...")

   os.system("tar x -C ${WORKDIR} -f ${DL_DIR}/${P}.tar.gz")

   bb.note("Unpacked source tarball.")
}

addtask unpack before do_build after do_fetch


python do_configure() {
   bb.note("Configuring source package ...")

   os.system("cd ${WORKDIR}/${P} && ./configure")

   bb.note("Configured source package.")
}

addtask configure before do_build after do_unpack


python do_compile() {
   bb.note("Compiling package...")

   os.system("cd ${WORKDIR}/${P} && make")

   bb.note("Compiled package.")
}

addtask compile before do_build after do_configure


Nano is an autotooled package. This recipe simply at a very basic level
does what you would do manually. OECore's autotools.bbclass is much more
sophisticated and so are the fetcher class files.

:rjs
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.yoctoproject.org/pipermail/yocto/attachments/20121004/00166d50/attachment.html>


More information about the yocto mailing list