Using bitbake and OpenEmbedded
Introduction
If your reading this manual you probably already have some idea of
what OpenEmbedded is all about, which is taking a lot of software and
creating something that you can run on another device. This involves
downloading some source code, compiling it, creating packages (like .deb
or .rpm) and/or creating boot images that can written to flash on the
device. The difficulties of cross-compiling and the variety of devices
which can be supported lead to a lot more complexity in an OpenEmbedded
based distribution than you'd find in a typical desktop distribution
(which cross-compiling isn't needed).
A major part of OpenEmbedded deals with compiling source code for
various projects. For each project this generally requires the same basic
set of tasks:
Download the source code, and any supporting files (such as
initscripts);
Extract the source code and apply any patches that might be
wanted;
Configure the software if needed (such as is done by running the
configure script);
Compile everything;
Package up all the files into some package format, like .deb or
.rpm or .ipk, ready for installation.
There's nothing particular unusual about this process when building
on the machine the package is to be installed on. What makes this
difficult is:
Cross-compiling: cross-compiling is difficult, and lots of
software has no support for cross-compiling - all packages included in
OE are cross-compiled;
Target and host are different: This means you can't compile up a
program and then run it - it's compiled to run on the target system,
not on the system compiling it. Lots of software tries to build and
run little helper and/or test applications and this won't work when
cross-compiling.
Tool chains (compiler, linker etc) are often difficult to
compile. Cross tool chains are even more difficult. Typically you'd go
out and download a tool chain made by someone else - but not when your
using OE. In OE the entire toolchain is built as part of the process.
This may make things take longer initially and may make it more
difficult to get started but makes it easier to apply patches and test
out changes to the tool chain.
Of course there's a lot more to OE then just compiling packages
though. Some of the features that OE supports includes:
Support for both glibc and uclibc;
Support for building for multiple target devices from the one
code base;
Automatically building anything that is required for the package
to compile and/or run (build and run time dependencies);
Creation of flash and disk images of any one of a number of
types (jffs2, ext2.gz, squashfs etc) for booting directly on the
target device;
Support for various packaging formats;
Automatic building all of the cross-compiling tools you'll
need;
Support for "native" packages that are built for the host
computer and not for the target and used to help during the build
process;
The rest of this chapter assumes you have mastered the Getting Start
guides to OpenEmbedded (see the OpenEmbedded web site for details), and
therefore have an appropriately configured setup and that you have managed
to actually build the cross-compilers for your target. This section talks
you through some of the background on what is happening with the aim of
helping you understand how to debug and develop within
OpenEmbedded.
You'll also not a lot of reference to variables that define specific
directories or change the behaviour of some part of the build process. You
should refer to for full details on
these variables.
Configuration
Configuration covers basic items such as where the various files can
be found and where output should be placed to more specific items such as
which hardware is being targeted and what features you want to have
included in the final image. The main configuration areas in OE
are:
conf/machine
This directory contains machine configuration information. For
each physical device a configuration file is required in this
directory that describes various aspects of the device, such as
architecture of the device, hardware features of the device (does it
have usb? a keyboard? etc), the type of flash or disk images needed
for the device, the serial console settings (if any) etc. If you are
adding support for a new device you would need to create a machine
configuration in this directory for the device.
conf/distro
This directory contains distribution related files. A
distribution decides how various activities are handled in the final
image, such as how networking configured, if usb devices will be
supported, what packaging system is used, which libc is used
etc.
conf/bitbake.conf
This is the main bitbake configuration file. This file is not
to be edited but it is useful to look at it since it declares a
larger number of the predefined variables used by OE and controls a
lot of the base functionality provided by OE.
conf/local.conf
This is the end-user specific configuration. This file needs
to be copied and edited and is used to specify the various working
directories, the machine to build for and the distribution to
use.
Work space
Let's start out by taking a look at a typically working area. Note
that this may not be exactly what see - there are a lot of options that
can effect exactly how things are done, but it gives us a pretty good idea
of whats going on. What we are looking at here is the tmp directory (as
specified by TMPDIR in your local.conf):~%> find tmp -maxdepth 2 -type d
tmp
tmp/stamps
tmp/cross
tmp/cross/bin
tmp/cross/libexec
tmp/cross/lib
tmp/cross/share
tmp/cross/sh4-linux
tmp/cache
tmp/cache/titan
tmp/work
tmp/work/busybox-1.2.1-r13
tmp/work/libice-1_1.0.3-r0
tmp/work/arpwatch-2.1a15-r2
...
tmp/rootfs
tmp/rootfs/bin
tmp/rootfs/usr
tmp/rootfs/media
tmp/rootfs/dev
tmp/rootfs/var
tmp/rootfs/lib
tmp/rootfs/sbin
tmp/rootfs/mnt
tmp/rootfs/boot
tmp/rootfs/sys
tmp/rootfs/proc
tmp/rootfs/etc
tmp/rootfs/home
tmp/rootfs/tmp
tmp/staging
tmp/staging/man
tmp/staging/x86_64-linux
tmp/staging/pkgdata
tmp/staging/pkgmaps
tmp/staging/var
tmp/staging/sh4-linux
tmp/staging/local
tmp/staging/etc
tmp/deploy
tmp/deploy/addons
tmp/deploy/ipk
tmp/deploy/sources
tmp/deploy/images
The various top level directories under tmp include:
stamps
Nothing of interest to users in here. These time stamps are
used by bitbake to keep track of what tasks it has completed and
what tasks it still has outstanding. This is how it knows that
certain actions have been completed and it doesn't need to do them
again.
cross
Contains the cross-compiler toolchain. That is the gcc and
binutils that run on the host system but produce output for the
target system.
cache
Nothing of interest to users in here. This contains the
bitbake parse cache and is used to avoid the need to parse all of
the recipes each time bitbake is run. This makes bitbake a lot
faster on the 2nd and subsequent runs.
work
The work directory. This is the directory in which all
packages are built - this is where the source code is extract,
patches applied, software configure, compiled, installed and
package. This is where you'll spend most of you time looking when
working in OE.
rootfs
The generated root filesystem image for your target device.
This is the contents of the root filesystem (NOTE: fakeroot means it
doesn't have the correct device special nodes and permissions to use
directly).
staging
Contains the staging area, which is used to stored natively
compiled tools and and libraries and headers for the target that are
required for building other software.
deploy
Contains the final output from OE. This includes the
installation packages (typically .ipkg packages) and flash and/or
disk images. This is where you go to get the final product.
When people refer to the "tmp directory" this
is the directory them are talking about.
To perform a complete rebuild from script you would usually rename
or delete tmp and then restart your build. I recommend keeping one old
version of tmp around to use for comparison if something goes wrong with
your new build. For example:%> rm -fr tmp.OLD
$> mv tmp tmp.OLD
%> bitbake bootstrap-image
work directory (tmp/work)
The work directory is where all source code is unpacked into,
where source is configured, compiled and packaged. In other words this
is where all the action happens. Each bitbake recipe will produce a
corresponding sub directory in the work directory. The sub directory
name will contain the recipe name, version and the release number (as
defined by the PR variable within the recipe).
Here's an example of a few of the subdirectories under the work
directory:~%> find tmp/work -maxdepth 1 -type d | head -4
tmp/work
tmp/work/busybox-1.2.1-r13
tmp/work/libice-1_1.0.3-r0
tmp/work/arpwatch-2.1a15-r2You can see that the first three (of
several hundred) recipes here and they are for release 13 of busybox
1.2.1, release 0 or libice 1.1.0.3 and release 2 of arpwatch 2.1a15.
It's also possible that you may just have a sub directory for your
targets architecture and operating system in which case these
directories will be in that additional subdirectory, as shown
here:~%> find tmp/work -maxdepth 2 -type d | head -4
tmp/work
tmp/work/sh4-linux
tmp/work/sh4-linux/busybox-1.2.1-r13
tmp/work/sh4-linux/libice-1_1.0.3-r0
tmp/work/sh4-linux/arpwatch-2.1a15-r2
The sh4-linux directory in the
above example is a combination of the target architecture (sh4) and
operating system (linux). This subdirectory has been added by the use of
one of OpenEmbedded's many features. In this case it's the
multimachine feature which is used to allow builds
for multiple targets within the one work directory and can be enabled on
a per distribution basis. This feature enables the sharing of native and
architecture neutral packages and building for multiple targets that
support the same architecture but require different linux kernels (for
example). We'll assume multimachine isn't being used for the rest of
this chapter, just remember to add the extra directory if your
distribution is using it.
Using lzo 1.08 as an example we'll examine the contents of the
working directory for a typical recipe:~%> find tmp/work/lzo-1.08-r14 -maxdepth 1
tmp/work/lzo-1.08-r14
tmp/work/lzo-1.08-r14/temp
tmp/work/lzo-1.08-r14/lzo-1.08
tmp/work/lzo-1.08-r14/install
tmp/work/lzo-1.08-r14/image
The directory, tmp/work/lzo-1.08-r14, is know as the
"working directory" for the recipe and is specified
via the WORKDIR variable in bitbake.
You'll sometimes see recipes refer directly to WORKDIR and this is the directory they are
referencing. The 1.08 is the version of
lzo and r14 is the release number, as
defined by the PR variable within the
recipe.
Under the working directory (WORKDIR) there are four subdirectories:
temp
The temp directories contains logs and in some cases scripts
that actually implement specific tasks (such as a script to
configure or compile the source).
You can look at the logs in this directory to get more
information into what happened (or didn't happen). This is usually
the first thing to look at when things are going wrong and these
usually need to be included when reporting bugs.
The scripts can be used to see what a particular task, such
as configure or compile, is trying to do.
lzo-1.08
This is the unpacked source code directory, which was
created when the lzo source code was extracted in this directory.
The name and format of this directory is therefore dependent on
the actual source code packaging. Within recipes this directory is
referred to as S and is usually
expected to be named like this, that is
"<name>-<version>". If the source
code extracts to somewhere else then that would need to be
declared in the recipe by explicitly setting the value of the
variable S to the appropriate
directory.
image
The image directory (or destination directory) is where the
software needs to be installed into in order to be packaged. This
directory is referred to as D in
recipes. So instead of installing binaries into /usr/bin and libraries into /usr/lib for example you would need to
install into ${D}/usr/bin and
${D}/usr/lib instead. When
installed on the target the ${D} will be not be included so
they'll end up in the correct place. You definitely don't wont
files on your host system being replaced by cross-compiled
binaries for your target!
install
The install directory is used to split the installed files
into separate packages. One subdirectory is created per package to
be generated and the files are moved from the image directory
(D) over to this directory, and
into the appropriate package subdirectory, as each packaging
instruction is processed. Typically there will be separate
documentation (-doc), debugging
(-dbg) and development
(-dev) packages automatically created. There
are variables such as FILES_ and
PACKAGES used in recipes which
control the separation of various files into individual
packages.
So lets show some examples of the useful information you now have
access to.
How about checking out what happened during the configuration of
lzo? Well that requires checking the log file for configure that is
generated in the temp directory:~%> less tmp/work/lzo-1.08-r14/temp/log.do_configure.*
...
checking whether ccache sh4-linux-gcc -ml -m4 suffers the -fschedule-insns bug... unknown
checking whether ccache sh4-linux-gcc -ml -m4 suffers the -fstrength-reduce bug... unknown
checking whether ccache sh4-linux-gcc -ml -m4 accepts -fstrict-aliasing... yes
checking the alignment of the assembler... 0
checking whether to build assembler versions... no
configure: creating ./config.status
config.status: creating Makefile
config.status: creating examples/Makefile
config.status: creating include/Makefile
config.status: creating ltest/Makefile
config.status: creating minilzo/Makefile
config.status: creating src/Makefile
config.status: creating tests/Makefile
config.status: creating config.h
config.status: executing depfiles commands
Or perhaps you want to see how the files were distributed into
individual packages prior to packaging? The install directory is where
the files are split into separate packages and so that shows us which
files end up where:~%> find tmp/work/lzo-1.08-r14/install
tmp/work/lzo-1.08-r14/install
tmp/work/lzo-1.08-r14/install/lzo-doc
tmp/work/lzo-1.08-r14/install/lzo-dbg
tmp/work/lzo-1.08-r14/install/lzo-dbg/usr
tmp/work/lzo-1.08-r14/install/lzo-dbg/usr/lib
tmp/work/lzo-1.08-r14/install/lzo-dbg/usr/lib/.debug
tmp/work/lzo-1.08-r14/install/lzo-dbg/usr/lib/.debug/liblzo.so.1.0.0
tmp/work/lzo-1.08-r14/install/lzo-dev
tmp/work/lzo-1.08-r14/install/lzo-dev/usr
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo2a.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo1y.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo1.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo1b.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo1f.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzoconf.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo1x.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo16bit.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo1a.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo1z.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzoutil.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/include/lzo1c.h
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/lib
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/lib/liblzo.a
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/lib/liblzo.so
tmp/work/lzo-1.08-r14/install/lzo-dev/usr/lib/liblzo.la
tmp/work/lzo-1.08-r14/install/lzo.shlibdeps
tmp/work/lzo-1.08-r14/install/lzo-locale
tmp/work/lzo-1.08-r14/install/lzo
tmp/work/lzo-1.08-r14/install/lzo/usr
tmp/work/lzo-1.08-r14/install/lzo/usr/lib
tmp/work/lzo-1.08-r14/install/lzo/usr/lib/liblzo.so.1
tmp/work/lzo-1.08-r14/install/lzo/usr/lib/liblzo.so.1.0.0
Tasks
When you go about building and installing a software package there
are a number of tasks that you generally follow with most software
packages. You probably need to start out by downloading the source code,
then unpacking the source code. Maye you need to apply some patches for
some reason. Then you might run the configure script of the package,
perhaps passing it some options to configure it to your liking. The you
might run "make install" to install the software. If your actually going
to make some packages, such as .deb or .rpm, then you'd have additional
tasks you'd perform to make them.
You find that building things in OpenEmbedded works in a similar way
- there are a number of tasks that are executed in a predefined order for
each recipe. Any many of the tasks correspond to those listed above like
"download the source". In fact you've probably
already seen some of the names of these tasks - bitbake displays them as
they are processed:~%> bitbake lzo
NOTE: Psyco JIT Compiler (http://psyco.sf.net) not available. Install it to increase performance.
NOTE: Handling BitBake files: \ (4541/4541) [100 %]
NOTE: Parsing finished. 4325 cached, 0 parsed, 216 skipped, 0 masked.
NOTE: build 200705041709: started
OE Build Configuration:
BB_VERSION = "1.8.2"
OE_REVISION = "<unknown>"
TARGET_ARCH = "sh4"
TARGET_OS = "linux"
MACHINE = "titan"
DISTRO = "erouter"
DISTRO_VERSION = "0.1-20070504"
TARGET_FPU = ""
NOTE: Resolving missing task queue dependencies
NOTE: preferred version 2.5 of glibc not available (for item virtual/sh4-linux-libc-for-gcc)
NOTE: Preparing Runqueue
NOTE: Executing runqueue
NOTE: Running task 208 of 226 (ID: 11, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_fetch)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_fetch: started
NOTE: package lzo-1.08-r14: task do_fetch: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 209 of 226 (ID: 2, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_unpack)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_unpack: started
NOTE: Unpacking /home/lenehan/devel/oe/sources/lzo-1.08.tar.gz to /home/lenehan/devel/oe/build/titan-glibc-25/tmp/work/lzo-1.08-r14/
NOTE: package lzo-1.08-r14: task do_unpack: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 216 of 226 (ID: 3, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_patch)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_patch: started
NOTE: package lzo-1.08-r14: task do_patch: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 217 of 226 (ID: 4, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_configure)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_configure: started
NOTE: package lzo-1.08-r14: task do_configure: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 218 of 226 (ID: 12, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_qa_configure)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_qa_configure: started
NOTE: Checking sanity of the config.log file
NOTE: package lzo-1.08-r14: task do_qa_configure: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 219 of 226 (ID: 0, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_compile)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_compile: started
NOTE: package lzo-1.08-r14: task do_compile: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 220 of 226 (ID: 1, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_install)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_install: started
NOTE: package lzo-1.08-r14: task do_install: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 221 of 226 (ID: 5, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_package)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_package: started
NOTE: DO PACKAGE QA
NOTE: Checking Package: lzo-dbg
NOTE: Checking Package: lzo
NOTE: Checking Package: lzo-doc
NOTE: Checking Package: lzo-dev
NOTE: Checking Package: lzo-locale
NOTE: DONE with PACKAGE QA
NOTE: package lzo-1.08-r14: task do_package: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 222 of 226 (ID: 8, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_package_write)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_package_write: started
Packaged contents of lzo-dbg into /home/lenehan/devel/oe/build/titan-glibc-25/tmp/deploy/ipk/sh4/liblzo-dbg_1.08-r14_sh4.ipk
Packaged contents of lzo into /home/lenehan/devel/oe/build/titan-glibc-25/tmp/deploy/ipk/sh4/liblzo1_1.08-r14_sh4.ipk
NOTE: Not creating empty archive for lzo-doc-1.08-r14
Packaged contents of lzo-dev into /home/lenehan/devel/oe/build/titan-glibc-25/tmp/deploy/ipk/sh4/liblzo-dev_1.08-r14_sh4.ipk
NOTE: Not creating empty archive for lzo-locale-1.08-r14
NOTE: package lzo-1.08-r14: task do_package_write: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 223 of 226 (ID: 6, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_populate_staging)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_populate_staging: started
NOTE: package lzo-1.08-r14: task do_populate_staging: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 224 of 226 (ID: 9, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_qa_staging)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_qa_staging: started
NOTE: QA checking staging
NOTE: package lzo-1.08-r14: task do_qa_staging: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 225 of 226 (ID: 7, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_distribute_sources)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_distribute_sources: started
NOTE: package lzo-1.08-r14: task do_distribute_sources: completed
NOTE: package lzo-1.08: completed
NOTE: Running task 226 of 226 (ID: 10, /home/lenehan/devel/oe/build/titan-glibc-25/packages/lzo/lzo_1.08.bb, do_build)
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_build: started
NOTE: package lzo-1.08-r14: task do_build: completed
NOTE: package lzo-1.08: completed
NOTE: Tasks Summary: Attempted 226 tasks of which 213 didn't need to be rerun and 0 failed.
NOTE: build 200705041709: completed
The output may look different depending on the version of
bitbake being used, and some tasks are only run when specific options
are enabled in your distribution. The important point to note is that
the various tasks are being run and bitbake shows you each time it
starts and completes a task.
So there's a set of tasks here which are being run to generate the
final packages. And if you'll notice that every recipe runs through the
same set of tasks (ok I'll admit that it is possible that some additional
tasks could be run for some recipes, but we'll talk about that later). The
tasks that you'll need to be most familiar with are:
fetch
The fetch task is responsible for
fetching any source code that is required. This means things such as
downloading files and checking out from source control repositories
such as git or svn.
unpack
The unpack task is responsible for
extracting files from archives, such as .tar.gz, into the working area and copying
any additional files, such as init scripts, into the working
area.
patch
The patch task is responsible for
applying any patches to the unpacked source code
configure
The configure task takes care of the
configuration of the package. Running a configure script
("./configure <options>") is probably the
form of configuration that is most recognised but it's not the only
configuration system that exists.
compile
The compile task actually compiles the
software. This could be as simple as running make.
populate_staging (stage)
The populate_staging task (stage is an
alternate, easier to type name, that can be used to refer to this
task) is responsible for making available libraries and headers (if
any) that may be required by other packages to build. For example if
you compile zlib then it's headers and the library need to be made
available for other applications to include and link against.
This is different to the install task
in that this is responsible for making available libraries and
headers for use during build on the development host. Therefore
it's libraries which normal have to stage things while
applications normally don't need to. The
install task on the other hand is making
files available for packaging and ultimately installation on the
target.
install
The install task is responsible for
actually installing everything. Now this needs to install the
software into the destination directory, D. This directory won't actually be a part of
the final package though. In other words if you install something
into ${D}/bin then it will end up
in the /bin directory in the
package and therefore on the target.
package
The package task takes the installed
files and splits them into separate directories under the ${WORKDIR}/install directory, one per
package. It moves the files for the destination directory, ${D}, that they were installed in into the
appropriate packages subdirectory. Usually there will be a main
package a separate documentation (-doc), development (-dev) and
debugging packages (-dbg) for example.
package_write
The package_write task is responsible for
taking each packages subdirectory and creating any actual
installation package, such as .ipk, .deb or .rpm. Currently .ipk is
the only fully supported packing format although .deb packages are
being actively worked on. It should be reasonably easy for an
experienced OpenEmbedded developer to add support for any other
packaging formats they might required.
You'll notice that the bitbake output had tasks prefixed with
do_, as in do_install vs
install. This is slightly confusing but any task
x is implemented via a function called
do_x in the class or recipe where it is defined.
See places refer to the tasks via their name only and some with the
do prefix.
You will almost certainly notice tasks beyond these ones - there are
various methods available to insert additional tasks into the tasks
sequence. As an example the insane.bbclass, which performs various QA checks,
does these checks by inserting a new task called
qa_configure between the
configure and compile tasks and
another new task called qa_staging between
populate_staging and build
tasks. The former validates the result of the
configure task and the late the results of the
populate_staging task.
To determine the full list of tasks available for a specific recipe
you can run bitbake on the recipe and asking it for the full list of
available tasks:~%> bitbake -b packages/perl/perl_5.8.8.bb -c listtasks
NOTE: package perl-5.8.8: started
NOTE: package perl-5.8.8-r11: task do_listtasks: started
do_fetchall
do_listtasks
do_rebuild
do_compile
do_build
do_populate_staging
do_mrproper
do_fetch
do_configure
do_clean
do_package
do_unpack
do_install
do_package_write
do_distribute_sources
do_showdata
do_qa_configure
do_qa_staging
do_patch
NOTE: package perl-5.8.8-r11: task do_listtasks: completed
NOTE: package perl-5.8.8: completed
~%>
If your being observant you'll note that
listtasks is in fact a task itself, and that the
-c option to bitbake allows you to
explicitly run specific tasks. We'll make use of this in the next section
when we discuss working with a recipe.
Working with a single recipe
During development you're likely to often find yourself working on a
single bitbake recipe - maybe trying to fix something or add a new version
or perhaps working on a totally new recipe. Now that you know all about
tasks you can use that knowledge to help speed up the development and
debugging process.
Bitbake can be instructed to deal directly with a single recipe file
by passing it via the -b parameter. This
option takes the recipe as a parameter and instructs bitbake to process
the named recipe only. Note that this ignores any dependencies that are in
the recipe, so these must have already been built previously.
Here's a typically example that cleans up the package (using the
clean task) and the rebuilds it with debugging output
from bitbake enabled:~%> bitbake -b <bb-file> -c clean
~%> bitbake -b <bb-file> -D
The options to bitbake that are most useful here are:
-b <bb-file>
The recipe to process;
-c <action>
The action to perform, typically the name of one of the tasks
supported by the recipe;
-D
Display debugging information, use two -D's for additional debugging;
-f
Force an operation. This is useful in getting bitbake to
perform some operation it normally wouldn't do. For example, if you
try and call the compile task twice in a row
then bitbake will not do anything on the second attempt since it has
already performed the task. By adding -f it will force it to perform the action
regardless of if it thinks it's been done previously.
The most common actions (used with -c) are:
fetch
Try to download all of the required source files, but don't do
anything else with them.
unpack
Unpack the source file but don't apply the patches yet.
Sometimes you may want to look at the extracted, but not patched
source code and that's what just unpacking will give you (some
time's handy to get diffs generated against the original
source).
patch
Apply any patches.
configure
Performs and configuration that is required for the
software.
compile
Perform the actual compilation steps of the software.
stage
If any files, such as header and libraries, will be required
by other packages then they need to be installed into the staging
area and that's what this task takes care of.
install
Install the software in preparation for packaging.
package
Package the software. Remember that this moves the files from
the installation directory, D, into the packing install area. So to
re-package you also need to re-install first.
clean
Delete the entire directory for this version of the software.
Usually done to allow a test build with no chance of old files or
changes being left behind.
Note that each of the actions that corresponds to task's will run
any preceding tasks that have not yet been performed. So starting with
compile will also perform the fetch, unpack, patch and configure
actions.
A typically development session might involve editing files in the
working directory and then recompiling until it all works:[... test ...]
~%> bitbake -b packages/testapp/testapp_4.3.bb -c compile -D
[... save a copy of main.c and make some changes ...]
~%> vi tmp/work/testapp-4.3-r0/main.c
~%> bitbake -b packages/testapp/testapp_4.3.bb -c compile -D -f
[... create a patch and add it to the recipe ...]
~%> vi packages/testapp/testapp_4.3.bb
[... test from clean ...]
~%> bitbake -b packages/testapp/testapp_4.3.bb -c clean
~%> bitbake -b packages/testapp/testapp_4.3.bb
[... NOTE: How to create the patch is not covered at this point ...]
Here's another example showing how you might go about fixing up the
packaging in your recipe:~%> bitbake -b packages/testapp/testapp_4.3.bb -c install -f
~%> bitbake -b packages/testapp/testapp_4.3.bb -c stage -f
~%> find tmp/work/testapp_4.3/install
...
~%> vi packages/testapp/testapp_4.3.bbAt this stage you play with
the PACKAGE_ and FILES_ variables and then repeat the above
sequence.
Note how we install and then stage. This is one of those things
where understanding the tasks helps a lot! Remember that stage moves the
files from where they were installed into the various subdirectories
(under ${WORKDIR}/install) for each
package. So if you try and run a stage task without a prior install there
won't be any files there to stage! Note also that the stage tasks clears
all the subdirectories in ${WORKDIR}/install so you won't get any left over
files. But beware, the install task doesn't clear ${D} directory, so any left over files from a
previous packing attempt will be left behind (which is ok if all you care
about it staging).
Interactive bitbake
To interactively test things use:~%> bitbake -ithis
will open the bitbake shell. From here there are a lot of commands
available (try help).
First thing you will want to do is parse all of the recipes (recent
bitbake version do this automatically when needed, so you don't need to
manually do this anymore):BB>> parseYou can now
build a specific recipe:BB>> build net-snmpIf it
fails you may want to clean the build before trying again:BB>> clean net-snmpIf
you update the recipe by editing the .bb file (to fix some issues) then
you will want to clean the package, reparse the modified recipe, and the
build again:BB>> clean net-snmp
BB>> reparse net-snmp
BB>> build net-snmpNote that you can use wildcards in the
bitbake shell as well:BB>> build t*
Devshell
One of the areas in which OpenEmbedded helps you out is by setting
various environment variables, such as CC
and PATH etc, to values suitable for
cross-compiling. If you wish to manually run configure scripts and compile
file during development it would be nice to have all those values set for
you. This is what devshell does - it provides you with an interactive
shell with all the appropriate variables set for cross-compiling.
devshell via inherit
This is the newer method of obtaining a devshell and is the
recommended way for most users now. The newer method requires that the
devshell class be added to you configuration by inheriting it. This is
usually done in your local.conf or your
distributions conf file:INHERIT += "src_distribute_local insane multimachine devshell"
With the inclusion of this class you'll find that devshell is
added as a new task that you can use on recipes:~%> bitbake -b packages/lzo/lzo_1.08.bb -c listtasks
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_listtasks: started
do_devshell
do_fetchall
do_listtasks
do_rebuild
do_compile
do_build
do_mrproper
do_fetch
do_configure
do_clean
do_populate_staging
do_package
do_unpack
do_install
do_package_write
do_distribute_sources
do_showdata
do_qa_staging
do_qa_configure
do_patch
NOTE: package lzo-1.08-r14: task do_listtasks: completed
NOTE: package lzo-1.08: completed
To bring up the devshell you call bitbake on a recipe and ask it
for the devshell task:~%> ./bb -b packages/lzo/lzo_1.08.bb -c devshell
NOTE: package lzo-1.08: started
NOTE: package lzo-1.08-r14: task do_devshell: started
[... devshell will appear here ...]
NOTE: package lzo-1.08-r14: task do_devshell: completed
NOTE: package lzo-1.08: completed
How the devshell appears depends on the settings of the TERMCMD variable - you can see the default
settings and other possible values in conf/bitbake.conf. Feel free to try settings this
to something else in your local.conf. Usually you will see a new
terminal window open which is the devshell window.
The devshell task is inserted after the patch task, so if you have
not already run bitbake on the recipe it will download the source and
apply any patches prior to opening the shell.
This method of obtaining a devshell works if you using bash as your shell, it does not work if you are
using zsh as your shell. Other shells
may or may not work.
devshell addon
The devshell addon was the original method that was used to create
a devshell.
It requires no changes to your configuration, instead you simply
build the devshell recipe:bitabike devshell
and then manually startup the shell. Once in the shell you'll
usually want to change into the working directory for the recipe you are
working on:~%> ./tmp/deploy/addons/sh4-linux-erouter-titan-devshell
bash: alias: `./configure': invalid alias name
[OE::sh4-linux-erouter-titan]:~$ cd tmp/work/lzo-1.08-r14/lzo-1.08
[OE::sh4-linux-erouter-titan]:~tmp/work/lzo-1.08-r14/lzo-1.08$
The name of the devshell addon depends on the target
architecture, operating system and machine name. So you name will be
different - just check for the appropriate name ending in
-devshell.
Working in the devshell
[To be done]
Patching and patch management
[To be done]