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]