Common Use-cases/tasks
Creating a new Distribution Creating a new distribution is not complicated, however we urge you to try existing distributions first, because it's also very easy to do wrong. The config needs to be created in $OEBASE/openembedded/conf/distro directory. So what has to be inside? DISTRO_VERSION so users will know which version of the distribution they are using. DISTRO_TYPE (release/debug) variable is used in some recipes to enable/disable some features - for example kernel output on screen for "debug" builds. Type of libc used: will it be glibc (TARGET_OS = "linux") or uclibc (TARGET_OS = "linux-uclibc")? Toolchain versions - for example gcc 3.4.4 based distro will have: PREFERRED_PROVIDERS += " virtual/${TARGET_PREFIX}gcc-initial:gcc-cross-initial" PREFERRED_PROVIDERS += " virtual/${TARGET_PREFIX}gcc:gcc-cross" PREFERRED_PROVIDERS += " virtual/${TARGET_PREFIX}g++:gcc-cross" PREFERRED_VERSION_binutils = "2.16" PREFERRED_VERSION_binutils-cross = "2.16" PREFERRED_VERSION_gcc = "3.4.4" PREFERRED_VERSION_gcc-cross = "3.4.4" PREFERRED_VERSION_gcc-initial-cross = "3.4.4" DISTRO_FEATURES which describe which features distro has. More about it in task-base section. Versions of kernels used for supported devices: PREFERRED_VERSION_linux-omap1_omap5912osk ?= "2.6.18+git" PREFERRED_VERSION_linux-openzaurus ?= "2.6.17" To get more stable build it is good to make use of sane-srcdates.inc file which contain working SRCDATE for many of floating recipes. require conf/distro/include/sane-srcdates.inc It also should have global SRCDATE value set (format is ISO date: YYYYMMDD): SRCDATE = "20061014"
Adding a new Machine To be able to build for a device OpenEmbedded has to know about it, so a machine config file needs to be written. All of the machine configs are stored in $OEBASE/openembedded/conf/machine/ directory. As usual some variables are required: TARGET_ARCH describes which CPU architecture the machine uses. MACHINE_FEATURES which describes which features the device has. More about it in task-base section. PREFERRED_PROVIDER_virtual/kernel has to point to the proper kernel recipe for this machine. There are also some optional variables that can be defined: SOC_FAMILY describes a family of processors that all share common features such as kernel versions, bootloaders, etc. This is used to allow overrides for a whole set of devices rather than per machine overrides being used. The use of SOC_FAMILY as an override is currently a distribution or local setting. NOTE: SOC_FAMILY is different than MACHINE_CLASS in that MACHINE_CLASS is intended to specify a grouping of devices that may have different processors but share common features. For example all OMAP3 devices can be described using the SOC_FAMILY "omap3" and this value can be used in overrides to prevent requiring multiple machine specific overrides. MACHINE_CLASS might be used to describe a class of devices such as a cell phone in which the processor may be different but the features such as touchscreen, GPS, modem, etc are the same. Next the kernel recipe needs to be added if it doesn't already exist.
Adding a new Package This section is a stub, help us by expanding it. Learn by example, go through the recipes that are already there and mimic them to do what you want.
building from unstable source code Building against the latest, bleeding-edge source has some intricacies of its own. For one, it is desirable to pin down a code revision that is known to build to prevent random breakage in OE at the most inopportune time for all OE users. Here is how to do that properly. for svn: add 'PV = "1.1+svnr${SRCREV}"' to your bb file. for cvs: add 'PV = "1.1+cvs${SRCREV}"' to your bb file. Accompany either with an entry to conf/distro/include/sane-srcrevs.inc for a revision that you know builds successfully. It is also common to define the stable SRCREV for your package directly in the package recipe. If you really absolutely have to follow the latest commits, you can do that by adding 'SRCREV_pn-linux-davinci ?= ${AUTOREV}' to your local.conf, for example. In this case, you'd build against the most recent and unstable source for the pn-linux-davinci package.
Creating your own image Creating own image is easy - only few variables need to be set: IMAGE_BASENAME to give a name for your own image PACKAGE_INSTALL to give a list of packages to install into the image RDEPENDS to give a list of recipes which are needed to be built to create this image IMAGE_LINGUAS is an optional list of languages which has to be installed into the image Then add the image class using: inherit image And the image recipe is ready for usage.
Using a prebuilt toolchain to create your packages It might be necessary to integrate a prebuilt toolchain and other libraries but still be use OpenEmbedded to build packages. One of many approaches is shown and discussed here.
The toolchain We assume the toolchain provides a C and C++ compiler, an assembler and other tools to build packages. The list below shows a gcc 3.4.4 toolchain for ARM architectures using glibc. We assume that the toolchain is in your PATH. $ ls pre-built/cross/bin arm-linux-g++ arm-linux-ld arm-linux-ranlib arm-linux-ar arm-linux-g77 arm-linux-readelf arm-linux-as arm-linux-gcc arm-linux-gcc-3.4.4 arm-linux-c++ arm-linux-size arm-linux-c++filt arm-linux-nm arm-linux-strings arm-linux-cpp arm-linux-objcopy arm-linux-strip arm-linux-objdump
The prebuilt libraries We need the header files and the libraries itself. The following directory layout is assumed. PRE_BUILT has two subdirectories one is called include and holds the header files and the other directory is called lib and holds the shared and static libraries. Additionally a Qt2 directory is present having a include and lib sub-directory. $ ls $PRE_BUILT include lib qt2
Setting up OpenEmbedded OpenEmbedded will be setup here. We assume that your machine and distribution is not part of OpenEmbedded and they will be created ad-hoc in the local.conf file. You will need to have BitBake and a current OpenEmbedded version available.
Sourceable script To ease the usage of OpenEmbedded we start by creating a source-able script. This is actually a small variation from the already seen script. We will name it build_source and you will need to source it. BITBAKE_PATH=/where/is/bitbake/bin TOOLCHAIN=/where/is/toolchain/bin HOST_TOOLS=/where/is/hosttools/bin export PRE_BUILT=/where/is/pre-built export PATH=$BITBAKE_PATH:$TOOLCHAIN:$HOST_TOOLS:$PATH export OEDIR=$PWD export LOCALDIR=$PWD/secret-isv Use source build_source to source the script, use env to check that the variables were exported.
Creating the local.conf We will configure OpenEmbedded now, it is very similar to what we have done above. DL_DIR = "${OEDIR}/sources" BBFILES := "${OEDIR}/openembedded/recipes/*/*.bb ${LOCALDIR}/recipes/*/*.bb" BBFILE_COLLECTIONS = "upstream local" BBFILE_PATTERN_upstream = "^${OEDIR}/openembedded/recipes/" BBFILE_PATTERN_local = "^${LOCALDIR}/recipes/" BBFILE_PRIORITY_upstream = "5" BBFILE_PRIORITY_local = "10" BBMASK = "" ${OEDIR}/openembedded will be a upstream release of OpenEmbedded. Above we have assumed it is in the current working directory. Additionally we have a ${LOCALDIR}, we combine these two directories as a special BitBake Collection. # # machine stuff # MACHINE = "secret-killer" PACKAGE_EXTRA_ARCHS = "armv4 armv4t armv5te iwmmxt xscale"" TARGET_CC_ARCH = "-mcpu=xscale -mtune=iwmmxt" TARGET_ARCH = "arm" PACKAGE_ARCH="xscale" We tell OpenEmbedded that we build for the ARM platform and optimize for xscale and iwmmxt. INHERIT += " package_ipk debian" TARGET_OS = "linux" TARGET_FPU = "soft" DISTRO = "secret-disro" DISTRO_NAME = "secret-distro" DISTRO_VERSION = "x.y.z" DISTRO_TYPE = "release" Create a distribution ad-hoc as well. We tell OpenEmbedded that we build for linux and glibc using soft float as fpu. If your toolchain is a uclibc toolchain you will need to set TARGET_OS to linux-uclibc. export CC="${CCACHE}arm-linux-gcc-3.4.4 ${HOST_CC_ARCH}" export CXX="${CCACHE}arm-linux-g++ ${HOST_CC_ARCH}" export CPP="arm-linux-gcc-3.4.4 -E" export LD="arm-linux-ld" export AR="arm-linux-ar" export AS="arm-linux-as" export RANLIB="arm-linux-ranlib" export STRIP="arm-linux-strip" The above variables replace the ones from bitbake.conf. This will make OpenEmbedded use the prebuilt toolchain. # # point OE to the lib and include directory # TARGET_CPPFLAGS_append = " -I${PRE_BUILT}/include " TARGET_LDFLAGS_prepend = " -L${PRE_BUILT}/qt2/lib -L${PRE_BUILT}/lib \ -Wl,-rpath-link,${PRE_BUILT}/lib -Wl,-rpath-link,${PRE_BUILT}/qt2/lib " # special to Qt/Qtopia QTDIR = "${PRE_BUILT}/qt2" QPEDIR = "${PRE_BUILT}" palmtopdir = "/opt/Qtopia" palmqtdir = "/opt/Qtopia" We will add the PRE_BUILT libraries to the include and library paths. And the same is done for the special version of Qt we have in your PRE_BUILT directory. ASSUME_PROVIDED += " virtual/${TARGET_PREFIX}gcc " ASSUME_PROVIDED += " virtual/libc " ASSUME_PROVIDED += " virtual/qte " ASSUME_PROVIDED += " virtual/libqpe " ASSUME_PROVIDED += " libqpe-opie " Now we have told BitBake that the C library, compiler and Qtopia is already provided. These lines will avoid building binutils, gcc initial, glibc, gcc. source build_source bitbake your-killer-app You should be able to create the packages you want to using the prebuilt toolchain now.
Useful hints If you have more prebuilt libraries you need to add additional ASSUME_PROVIDED lines to your local.conf. Using bitbake -vvv PACKAGE you can easily see the package names you could ASSUME_PROVIDED if you have some prebuilt.
Issues with this approach NOTE: Couldn't find shared library provider for libqtopia.so.1 NOTE: Couldn't find shared library provider for libqtopia2.so.2 NOTE: Couldn't find shared library provider for libqpe.so.1 NOTE: Couldn't find shared library provider for libpthread.so.0 NOTE: Couldn't find shared library provider for libstdc++.so.6 NOTE: Couldn't find shared library provider for libqte.so.2 NOTE: Couldn't find shared library provider for libgcc_s.so.1 NOTE: Couldn't find shared library provider for libc.so.6 NOTE: Couldn't find shared library provider for libm.so.6 OpenEmbedded tries to automatically add run-time dependencies (RDEPENDS) to generated packages. It is inspecting binaries and libraries and uses the shlibs system to do add dependencies for the linked libraries, however in this case it was not able to find packages providing these libraries as they were prebuilt. One way to resolve this problem is to provide an explicit mapping using the ASSUME_SHLIBS variable in a config file local.conf. For example, for the libraries above (partial): ASSUME_SHLIBS = "libqtopia2.so.2:qtopia2_2.4 libc.so.6:libc" The format is shlib_file_name:package[_version]. If a version is specified it will be used as the minimal (>=) version for the dependency.
Using a new package format This section is a stub, help us by expanding it
Creating Software Development Kits (SDKs)
What is provided by a SDK The Software Development Kit (SDK) should be easy to install and enable your user-base to create binaries and libraries that work on the target hardware. To accomplish this goal OpenEmbedded SDKs contain tools for the host and tools for the target hardware. Among these tools is a cross compiler, libraries and header files for additional dependencies, pkg-config files to allow buildsystems to easily find the dependencies, a file with results for autoconf and a script that can be sourced to setup the environment.
Creating a SDK with your libraries pre-installed
Preparing the host side Your SDK might need utilities that will run on the host. These could include scripts, buildsystem software like cmake, or an emulator like qemu. For these dependencies it is imported that they inherit sdk and by convention end with -sdk in the PN. A new task should be created that will assure that all host utilities will be installed. Place a file called task-YOUR-toolchain-host.bb in the recipes/tasks directory and place the following content in it: require task-sdk-host.bb DESCRIPTION = "Host packages for YOUR SDK" LICENSE = "MIT" ALLOW_EMPTY = "1" RDEPENDS_${PN} += "YOUR-DEPENDENCY-sdk"
Preparing the target side Your SDK should provide your user with header files and libraries he will need when doing application development. In OpenEmbedded the ${PN}-dev is providing the header files, pkg-config files and symbolic links to libraries to allow using the library. The SDK should install these development packages to the SDK. To install the development packages you will need to create a new task. Create a new file task-YOUR-toolchain-target.bb in the recipes/tasks directory and place the following content in it: DESCRIPTION = "Target package for YOUR SDK" LICENSE = "MIT" ALLOW_EMPTY = "1" PR = "r0" RDEPENDS_${PN} += "\ task-sdk-bare \ your-lib-dev \ your-data "
Putting it together In the previous two sections we have prepared the host and target side. One thing that is missing is combining the two newly created tasks and actually creating the SDK. This is what we are going to do now. Create meta-toolchain-YOU.bb in the recipes/meta directory and place the following content in it: PR = "r0" TOOLCHAIN_TARGET_TASK = "task-YOUR-toolchain-target" TOOLCHAIN_HOST_TASK = "task-YOUR-toolchain-host" require meta-toolchain.bb SDK_SUFFIX = "toolchain-YOUR" Using bitbake meta-toolchain-YOU the SDK creation should be started and you should find a sdk directory inside your deploy directory with a SDK waiting for you. With the above command you still need to have OE configured with your conf/local.conf to select the machine and distribution you are targeting. SDK creation currently does not work with the DISTRO set to micro. If the environment-setup script packaged in the SDK should require more environment look at the meta-toolchain-qte.bb to accomplish this.
Creating and Using a Qt Embedded SDK
Creating the SDK The SDK should contain a build of Qt Embedded, but also optional dependencies like directFB, glib-2.0, gstreamer-0.10, tslib and more esoteric dependencies like mysql and postgres. This allows developers to simply start developing using Qt and enables system integrators to easily recompile Qt and base libraries without tracking down extra dependencies. OpenEmbedded provides an easy way to create a Qt Embedded SDK. In recipes/tasks/task-qte-toolchain-host.bb host tools like moc, uic, rcc, qmake will get installed and in recipes/tasks/task-qte-toolchain-target.bb the Qt4 header files and libraries will be installed. To build the SDK, setup OpenEmbedded in the usual way by picking a DISTRO and MACHINE. Issue the below command and after the operation finished you should find a SDK in the deployment directory. $ bitbake meta-toolchain-qte The deployment directory depends on the distribution and used C library. In the case of Angstrom and glibc it is located in tmp/deploy/glibc/sdk. Change qt4-embedded.inc and qt4.inc for using different Qt configuration flags. This might include a custom qconfig.h to produce a reduced size build. When distributing the SDK make sure to include a written offer to provide the sourcecode of GPL licensed applications or provide parts of the sources folder. The sources folder is located right next to the sdk one.
Using the Qt Embedded SDK In this example we are assuming that the target hardware is an armv5t system and the SDK targets the Angstrom Distribution. You should start by downloading the SDK and untar it to the root folder (/). Once this operation is finished you will find a new directory /usr/local/angstrom/arm/ and it contains the environment-setup file to setup the QMAKESPEC and various other paths. Untar the SDK once $ tar -C / -xjf angstrom-armv5te-linux-gnueabi-toolchain-qte.tar.bz2 Before using it source the environment $ . /usr/local/angstrom/arm/environment-setup Use qmake2 to build software for the target $ qmake2 Creating and building a simple example. We will create a simple Qt Embedded application and use qmake2 and make to cross compile. $ . /usr/local/angstrom/arm/environment-setup $ cd $HOME $ mkdir qte-example $ cd qte-example $ echo "TEMPLATE=app SOURCES=main.cpp " > qte-example.pro $ echo '#include <QApplication> #include <QPushButton> int main(int argc, char** argv) { QApplication app(argc, argv); QPushButton btn("Hello World"); btn.show(); btn.showMaximized(); return app.exec(); } ' > main.cpp $ qmake2 $ make