1636 lines
69 KiB
ReStructuredText
1636 lines
69 KiB
ReStructuredText
|
.. SPDX-License-Identifier: CC-BY-SA-2.0-UK
|
|||
|
|
|||
|
Writing a New Recipe
|
|||
|
********************
|
|||
|
|
|||
|
Recipes (``.bb`` files) are fundamental components in the Yocto Project
|
|||
|
environment. Each software component built by the OpenEmbedded build
|
|||
|
system requires a recipe to define the component. This section describes
|
|||
|
how to create, write, and test a new recipe.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
For information on variables that are useful for recipes and for
|
|||
|
information about recipe naming issues, see the
|
|||
|
":ref:`ref-manual/varlocality:recipes`" section of the Yocto Project
|
|||
|
Reference Manual.
|
|||
|
|
|||
|
Overview
|
|||
|
========
|
|||
|
|
|||
|
The following figure shows the basic process for creating a new recipe.
|
|||
|
The remainder of the section provides details for the steps.
|
|||
|
|
|||
|
.. image:: figures/recipe-workflow.png
|
|||
|
:align: center
|
|||
|
:width: 50%
|
|||
|
|
|||
|
Locate or Automatically Create a Base Recipe
|
|||
|
============================================
|
|||
|
|
|||
|
You can always write a recipe from scratch. However, there are three choices
|
|||
|
that can help you quickly get started with a new recipe:
|
|||
|
|
|||
|
- ``devtool add``: A command that assists in creating a recipe and an
|
|||
|
environment conducive to development.
|
|||
|
|
|||
|
- ``recipetool create``: A command provided by the Yocto Project that
|
|||
|
automates creation of a base recipe based on the source files.
|
|||
|
|
|||
|
- *Existing Recipes:* Location and modification of an existing recipe
|
|||
|
that is similar in function to the recipe you need.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
For information on recipe syntax, see the
|
|||
|
":ref:`dev-manual/new-recipe:recipe syntax`" section.
|
|||
|
|
|||
|
Creating the Base Recipe Using ``devtool add``
|
|||
|
----------------------------------------------
|
|||
|
|
|||
|
The ``devtool add`` command uses the same logic for auto-creating the
|
|||
|
recipe as ``recipetool create``, which is listed below. Additionally,
|
|||
|
however, ``devtool add`` sets up an environment that makes it easy for
|
|||
|
you to patch the source and to make changes to the recipe as is often
|
|||
|
necessary when adding a recipe to build a new piece of software to be
|
|||
|
included in a build.
|
|||
|
|
|||
|
You can find a complete description of the ``devtool add`` command in
|
|||
|
the ":ref:`sdk-manual/extensible:a closer look at \`\`devtool add\`\``" section
|
|||
|
in the Yocto Project Application Development and the Extensible Software
|
|||
|
Development Kit (eSDK) manual.
|
|||
|
|
|||
|
Creating the Base Recipe Using ``recipetool create``
|
|||
|
----------------------------------------------------
|
|||
|
|
|||
|
``recipetool create`` automates creation of a base recipe given a set of
|
|||
|
source code files. As long as you can extract or point to the source
|
|||
|
files, the tool will construct a recipe and automatically configure all
|
|||
|
pre-build information into the recipe. For example, suppose you have an
|
|||
|
application that builds using Autotools. Creating the base recipe using
|
|||
|
``recipetool`` results in a recipe that has the pre-build dependencies,
|
|||
|
license requirements, and checksums configured.
|
|||
|
|
|||
|
To run the tool, you just need to be in your :term:`Build Directory` and
|
|||
|
have sourced the build environment setup script (i.e.
|
|||
|
:ref:`structure-core-script`). To get help on the tool, use the following
|
|||
|
command::
|
|||
|
|
|||
|
$ recipetool -h
|
|||
|
NOTE: Starting bitbake server...
|
|||
|
usage: recipetool [-d] [-q] [--color COLOR] [-h] <subcommand> ...
|
|||
|
|
|||
|
OpenEmbedded recipe tool
|
|||
|
|
|||
|
options:
|
|||
|
-d, --debug Enable debug output
|
|||
|
-q, --quiet Print only errors
|
|||
|
--color COLOR Colorize output (where COLOR is auto, always, never)
|
|||
|
-h, --help show this help message and exit
|
|||
|
|
|||
|
subcommands:
|
|||
|
create Create a new recipe
|
|||
|
newappend Create a bbappend for the specified target in the specified
|
|||
|
layer
|
|||
|
setvar Set a variable within a recipe
|
|||
|
appendfile Create/update a bbappend to replace a target file
|
|||
|
appendsrcfiles Create/update a bbappend to add or replace source files
|
|||
|
appendsrcfile Create/update a bbappend to add or replace a source file
|
|||
|
Use recipetool <subcommand> --help to get help on a specific command
|
|||
|
|
|||
|
Running ``recipetool create -o OUTFILE`` creates the base recipe and
|
|||
|
locates it properly in the layer that contains your source files.
|
|||
|
Following are some syntax examples:
|
|||
|
|
|||
|
- Use this syntax to generate a recipe based on source. Once generated,
|
|||
|
the recipe resides in the existing source code layer::
|
|||
|
|
|||
|
recipetool create -o OUTFILE source
|
|||
|
|
|||
|
- Use this syntax to generate a recipe using code that
|
|||
|
you extract from source. The extracted code is placed in its own layer
|
|||
|
defined by :term:`EXTERNALSRC`::
|
|||
|
|
|||
|
recipetool create -o OUTFILE -x EXTERNALSRC source
|
|||
|
|
|||
|
- Use this syntax to generate a recipe based on source. The options
|
|||
|
direct ``recipetool`` to generate debugging information. Once generated,
|
|||
|
the recipe resides in the existing source code layer::
|
|||
|
|
|||
|
recipetool create -d -o OUTFILE source
|
|||
|
|
|||
|
Locating and Using a Similar Recipe
|
|||
|
-----------------------------------
|
|||
|
|
|||
|
Before writing a recipe from scratch, it is often useful to discover
|
|||
|
whether someone else has already written one that meets (or comes close
|
|||
|
to meeting) your needs. The Yocto Project and OpenEmbedded communities
|
|||
|
maintain many recipes that might be candidates for what you are doing.
|
|||
|
You can find a good central index of these recipes in the
|
|||
|
:oe_layerindex:`OpenEmbedded Layer Index <>`.
|
|||
|
|
|||
|
Working from an existing recipe or a skeleton recipe is the best way to
|
|||
|
get started. Here are some points on both methods:
|
|||
|
|
|||
|
- *Locate and modify a recipe that is close to what you want to do:*
|
|||
|
This method works when you are familiar with the current recipe
|
|||
|
space. The method does not work so well for those new to the Yocto
|
|||
|
Project or writing recipes.
|
|||
|
|
|||
|
Some risks associated with this method are using a recipe that has
|
|||
|
areas totally unrelated to what you are trying to accomplish with
|
|||
|
your recipe, not recognizing areas of the recipe that you might have
|
|||
|
to add from scratch, and so forth. All these risks stem from
|
|||
|
unfamiliarity with the existing recipe space.
|
|||
|
|
|||
|
- *Use and modify the following skeleton recipe:* If for some reason
|
|||
|
you do not want to use ``recipetool`` and you cannot find an existing
|
|||
|
recipe that is close to meeting your needs, you can use the following
|
|||
|
structure to provide the fundamental areas of a new recipe::
|
|||
|
|
|||
|
DESCRIPTION = ""
|
|||
|
HOMEPAGE = ""
|
|||
|
LICENSE = ""
|
|||
|
SECTION = ""
|
|||
|
DEPENDS = ""
|
|||
|
LIC_FILES_CHKSUM = ""
|
|||
|
|
|||
|
SRC_URI = ""
|
|||
|
|
|||
|
Storing and Naming the Recipe
|
|||
|
=============================
|
|||
|
|
|||
|
Once you have your base recipe, you should put it in your own layer and
|
|||
|
name it appropriately. Locating it correctly ensures that the
|
|||
|
OpenEmbedded build system can find it when you use BitBake to process
|
|||
|
the recipe.
|
|||
|
|
|||
|
- *Storing Your Recipe:* The OpenEmbedded build system locates your
|
|||
|
recipe through the layer's ``conf/layer.conf`` file and the
|
|||
|
:term:`BBFILES` variable. This
|
|||
|
variable sets up a path from which the build system can locate
|
|||
|
recipes. Here is the typical use::
|
|||
|
|
|||
|
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
|
|||
|
${LAYERDIR}/recipes-*/*/*.bbappend"
|
|||
|
|
|||
|
Consequently, you need to be sure you locate your new recipe inside
|
|||
|
your layer such that it can be found.
|
|||
|
|
|||
|
You can find more information on how layers are structured in the
|
|||
|
":ref:`dev-manual/layers:understanding and creating layers`" section.
|
|||
|
|
|||
|
- *Naming Your Recipe:* When you name your recipe, you need to follow
|
|||
|
this naming convention::
|
|||
|
|
|||
|
basename_version.bb
|
|||
|
|
|||
|
Use lower-cased characters and do not include the reserved suffixes
|
|||
|
``-native``, ``-cross``, ``-initial``, or ``-dev`` casually (i.e. do not use
|
|||
|
them as part of your recipe name unless the string applies). Here are some
|
|||
|
examples:
|
|||
|
|
|||
|
.. code-block:: none
|
|||
|
|
|||
|
cups_1.7.0.bb
|
|||
|
gawk_4.0.2.bb
|
|||
|
irssi_0.8.16-rc1.bb
|
|||
|
|
|||
|
Running a Build on the Recipe
|
|||
|
=============================
|
|||
|
|
|||
|
Creating a new recipe is usually an iterative process that requires
|
|||
|
using BitBake to process the recipe multiple times in order to
|
|||
|
progressively discover and add information to the recipe file.
|
|||
|
|
|||
|
Assuming you have sourced the build environment setup script (i.e.
|
|||
|
:ref:`structure-core-script`) and you are in the :term:`Build Directory`, use
|
|||
|
BitBake to process your recipe. All you need to provide is the
|
|||
|
``basename`` of the recipe as described in the previous section::
|
|||
|
|
|||
|
$ bitbake basename
|
|||
|
|
|||
|
During the build, the OpenEmbedded build system creates a temporary work
|
|||
|
directory for each recipe
|
|||
|
(``${``\ :term:`WORKDIR`\ ``}``)
|
|||
|
where it keeps extracted source files, log files, intermediate
|
|||
|
compilation and packaging files, and so forth.
|
|||
|
|
|||
|
The path to the per-recipe temporary work directory depends on the
|
|||
|
context in which it is being built. The quickest way to find this path
|
|||
|
is to have BitBake return it by running the following::
|
|||
|
|
|||
|
$ bitbake -e basename | grep ^WORKDIR=
|
|||
|
|
|||
|
As an example, assume a Source Directory
|
|||
|
top-level folder named ``poky``, a default :term:`Build Directory` at
|
|||
|
``poky/build``, and a ``qemux86-poky-linux`` machine target system.
|
|||
|
Furthermore, suppose your recipe is named ``foo_1.3.0.bb``. In this
|
|||
|
case, the work directory the build system uses to build the package
|
|||
|
would be as follows::
|
|||
|
|
|||
|
poky/build/tmp/work/qemux86-poky-linux/foo/1.3.0-r0
|
|||
|
|
|||
|
Inside this directory you can find sub-directories such as ``image``,
|
|||
|
``packages-split``, and ``temp``. After the build, you can examine these
|
|||
|
to determine how well the build went.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
You can find log files for each task in the recipe's ``temp``
|
|||
|
directory (e.g. ``poky/build/tmp/work/qemux86-poky-linux/foo/1.3.0-r0/temp``).
|
|||
|
Log files are named ``log.taskname`` (e.g. ``log.do_configure``,
|
|||
|
``log.do_fetch``, and ``log.do_compile``).
|
|||
|
|
|||
|
You can find more information about the build process in
|
|||
|
":doc:`/overview-manual/development-environment`"
|
|||
|
chapter of the Yocto Project Overview and Concepts Manual.
|
|||
|
|
|||
|
Fetching Code
|
|||
|
=============
|
|||
|
|
|||
|
The first thing your recipe must do is specify how to fetch the source
|
|||
|
files. Fetching is controlled mainly through the
|
|||
|
:term:`SRC_URI` variable. Your recipe
|
|||
|
must have a :term:`SRC_URI` variable that points to where the source is
|
|||
|
located. For a graphical representation of source locations, see the
|
|||
|
":ref:`overview-manual/concepts:sources`" section in
|
|||
|
the Yocto Project Overview and Concepts Manual.
|
|||
|
|
|||
|
The :ref:`ref-tasks-fetch` task uses the prefix of each entry in the
|
|||
|
:term:`SRC_URI` variable value to determine which
|
|||
|
:ref:`fetcher <bitbake-user-manual/bitbake-user-manual-fetching:fetchers>`
|
|||
|
to use to get your source files. It is the :term:`SRC_URI` variable that triggers
|
|||
|
the fetcher. The :ref:`ref-tasks-patch` task uses the variable after source is
|
|||
|
fetched to apply patches. The OpenEmbedded build system uses
|
|||
|
:term:`FILESOVERRIDES` for scanning directory locations for local files in
|
|||
|
:term:`SRC_URI`.
|
|||
|
|
|||
|
The :term:`SRC_URI` variable in your recipe must define each unique location
|
|||
|
for your source files. It is good practice to not hard-code version
|
|||
|
numbers in a URL used in :term:`SRC_URI`. Rather than hard-code these
|
|||
|
values, use ``${``\ :term:`PV`\ ``}``,
|
|||
|
which causes the fetch process to use the version specified in the
|
|||
|
recipe filename. Specifying the version in this manner means that
|
|||
|
upgrading the recipe to a future version is as simple as renaming the
|
|||
|
recipe to match the new version.
|
|||
|
|
|||
|
Here is a simple example from the
|
|||
|
``meta/recipes-devtools/strace/strace_5.5.bb`` recipe where the source
|
|||
|
comes from a single tarball. Notice the use of the
|
|||
|
:term:`PV` variable::
|
|||
|
|
|||
|
SRC_URI = "https://strace.io/files/${PV}/strace-${PV}.tar.xz \
|
|||
|
|
|||
|
Files mentioned in :term:`SRC_URI` whose names end in a typical archive
|
|||
|
extension (e.g. ``.tar``, ``.tar.gz``, ``.tar.bz2``, ``.zip``, and so
|
|||
|
forth), are automatically extracted during the
|
|||
|
:ref:`ref-tasks-unpack` task. For
|
|||
|
another example that specifies these types of files, see the
|
|||
|
":ref:`dev-manual/new-recipe:building an autotooled package`" section.
|
|||
|
|
|||
|
Another way of specifying source is from an SCM. For Git repositories,
|
|||
|
you must specify :term:`SRCREV` and you should specify :term:`PV` to include
|
|||
|
the revision with :term:`SRCPV`. Here is an example from the recipe
|
|||
|
``meta/recipes-core/musl/gcompat_git.bb``::
|
|||
|
|
|||
|
SRC_URI = "git://git.adelielinux.org/adelie/gcompat.git;protocol=https;branch=current"
|
|||
|
|
|||
|
PV = "1.0.0+1.1+git${SRCPV}"
|
|||
|
SRCREV = "af5a49e489fdc04b9cf02547650d7aeaccd43793"
|
|||
|
|
|||
|
If your :term:`SRC_URI` statement includes URLs pointing to individual files
|
|||
|
fetched from a remote server other than a version control system,
|
|||
|
BitBake attempts to verify the files against checksums defined in your
|
|||
|
recipe to ensure they have not been tampered with or otherwise modified
|
|||
|
since the recipe was written. Two checksums are used:
|
|||
|
``SRC_URI[md5sum]`` and ``SRC_URI[sha256sum]``.
|
|||
|
|
|||
|
If your :term:`SRC_URI` variable points to more than a single URL (excluding
|
|||
|
SCM URLs), you need to provide the ``md5`` and ``sha256`` checksums for
|
|||
|
each URL. For these cases, you provide a name for each URL as part of
|
|||
|
the :term:`SRC_URI` and then reference that name in the subsequent checksum
|
|||
|
statements. Here is an example combining lines from the files
|
|||
|
``git.inc`` and ``git_2.24.1.bb``::
|
|||
|
|
|||
|
SRC_URI = "${KERNELORG_MIRROR}/software/scm/git/git-${PV}.tar.gz;name=tarball \
|
|||
|
${KERNELORG_MIRROR}/software/scm/git/git-manpages-${PV}.tar.gz;name=manpages"
|
|||
|
|
|||
|
SRC_URI[tarball.md5sum] = "166bde96adbbc11c8843d4f8f4f9811b"
|
|||
|
SRC_URI[tarball.sha256sum] = "ad5334956301c86841eb1e5b1bb20884a6bad89a10a6762c958220c7cf64da02"
|
|||
|
SRC_URI[manpages.md5sum] = "31c2272a8979022497ba3d4202df145d"
|
|||
|
SRC_URI[manpages.sha256sum] = "9a7ae3a093bea39770eb96ca3e5b40bff7af0b9f6123f089d7821d0e5b8e1230"
|
|||
|
|
|||
|
Proper values for ``md5`` and ``sha256`` checksums might be available
|
|||
|
with other signatures on the download page for the upstream source (e.g.
|
|||
|
``md5``, ``sha1``, ``sha256``, ``GPG``, and so forth). Because the
|
|||
|
OpenEmbedded build system only deals with ``sha256sum`` and ``md5sum``,
|
|||
|
you should verify all the signatures you find by hand.
|
|||
|
|
|||
|
If no :term:`SRC_URI` checksums are specified when you attempt to build the
|
|||
|
recipe, or you provide an incorrect checksum, the build will produce an
|
|||
|
error for each missing or incorrect checksum. As part of the error
|
|||
|
message, the build system provides the checksum string corresponding to
|
|||
|
the fetched file. Once you have the correct checksums, you can copy and
|
|||
|
paste them into your recipe and then run the build again to continue.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
As mentioned, if the upstream source provides signatures for
|
|||
|
verifying the downloaded source code, you should verify those
|
|||
|
manually before setting the checksum values in the recipe and
|
|||
|
continuing with the build.
|
|||
|
|
|||
|
This final example is a bit more complicated and is from the
|
|||
|
``meta/recipes-sato/rxvt-unicode/rxvt-unicode_9.20.bb`` recipe. The
|
|||
|
example's :term:`SRC_URI` statement identifies multiple files as the source
|
|||
|
files for the recipe: a tarball, a patch file, a desktop file, and an icon::
|
|||
|
|
|||
|
SRC_URI = "http://dist.schmorp.de/rxvt-unicode/Attic/rxvt-unicode-${PV}.tar.bz2 \
|
|||
|
file://xwc.patch \
|
|||
|
file://rxvt.desktop \
|
|||
|
file://rxvt.png"
|
|||
|
|
|||
|
When you specify local files using the ``file://`` URI protocol, the
|
|||
|
build system fetches files from the local machine. The path is relative
|
|||
|
to the :term:`FILESPATH` variable
|
|||
|
and searches specific directories in a certain order:
|
|||
|
``${``\ :term:`BP`\ ``}``,
|
|||
|
``${``\ :term:`BPN`\ ``}``, and
|
|||
|
``files``. The directories are assumed to be subdirectories of the
|
|||
|
directory in which the recipe or append file resides. For another
|
|||
|
example that specifies these types of files, see the
|
|||
|
"`building a single .c file package`_" section.
|
|||
|
|
|||
|
The previous example also specifies a patch file. Patch files are files
|
|||
|
whose names usually end in ``.patch`` or ``.diff`` but can end with
|
|||
|
compressed suffixes such as ``diff.gz`` and ``patch.bz2``, for example.
|
|||
|
The build system automatically applies patches as described in the
|
|||
|
":ref:`dev-manual/new-recipe:patching code`" section.
|
|||
|
|
|||
|
Fetching Code Through Firewalls
|
|||
|
-------------------------------
|
|||
|
|
|||
|
Some users are behind firewalls and need to fetch code through a proxy.
|
|||
|
See the ":doc:`/ref-manual/faq`" chapter for advice.
|
|||
|
|
|||
|
Limiting the Number of Parallel Connections
|
|||
|
-------------------------------------------
|
|||
|
|
|||
|
Some users are behind firewalls or use servers where the number of parallel
|
|||
|
connections is limited. In such cases, you can limit the number of fetch
|
|||
|
tasks being run in parallel by adding the following to your ``local.conf``
|
|||
|
file::
|
|||
|
|
|||
|
do_fetch[number_threads] = "4"
|
|||
|
|
|||
|
Unpacking Code
|
|||
|
==============
|
|||
|
|
|||
|
During the build, the
|
|||
|
:ref:`ref-tasks-unpack` task unpacks
|
|||
|
the source with ``${``\ :term:`S`\ ``}``
|
|||
|
pointing to where it is unpacked.
|
|||
|
|
|||
|
If you are fetching your source files from an upstream source archived
|
|||
|
tarball and the tarball's internal structure matches the common
|
|||
|
convention of a top-level subdirectory named
|
|||
|
``${``\ :term:`BPN`\ ``}-${``\ :term:`PV`\ ``}``,
|
|||
|
then you do not need to set :term:`S`. However, if :term:`SRC_URI` specifies to
|
|||
|
fetch source from an archive that does not use this convention, or from
|
|||
|
an SCM like Git or Subversion, your recipe needs to define :term:`S`.
|
|||
|
|
|||
|
If processing your recipe using BitBake successfully unpacks the source
|
|||
|
files, you need to be sure that the directory pointed to by ``${S}``
|
|||
|
matches the structure of the source.
|
|||
|
|
|||
|
Patching Code
|
|||
|
=============
|
|||
|
|
|||
|
Sometimes it is necessary to patch code after it has been fetched. Any
|
|||
|
files mentioned in :term:`SRC_URI` whose names end in ``.patch`` or
|
|||
|
``.diff`` or compressed versions of these suffixes (e.g. ``diff.gz`` are
|
|||
|
treated as patches. The
|
|||
|
:ref:`ref-tasks-patch` task
|
|||
|
automatically applies these patches.
|
|||
|
|
|||
|
The build system should be able to apply patches with the "-p1" option
|
|||
|
(i.e. one directory level in the path will be stripped off). If your
|
|||
|
patch needs to have more directory levels stripped off, specify the
|
|||
|
number of levels using the "striplevel" option in the :term:`SRC_URI` entry
|
|||
|
for the patch. Alternatively, if your patch needs to be applied in a
|
|||
|
specific subdirectory that is not specified in the patch file, use the
|
|||
|
"patchdir" option in the entry.
|
|||
|
|
|||
|
As with all local files referenced in
|
|||
|
:term:`SRC_URI` using ``file://``,
|
|||
|
you should place patch files in a directory next to the recipe either
|
|||
|
named the same as the base name of the recipe
|
|||
|
(:term:`BP` and
|
|||
|
:term:`BPN`) or "files".
|
|||
|
|
|||
|
Licensing
|
|||
|
=========
|
|||
|
|
|||
|
Your recipe needs to define variables related to the license
|
|||
|
under whith the software is distributed. See the
|
|||
|
:ref:`contributor-guide/recipe-style-guide:recipe license fields`
|
|||
|
section in the Contributor Guide for details.
|
|||
|
|
|||
|
Dependencies
|
|||
|
============
|
|||
|
|
|||
|
Most software packages have a short list of other packages that they
|
|||
|
require, which are called dependencies. These dependencies fall into two
|
|||
|
main categories: build-time dependencies, which are required when the
|
|||
|
software is built; and runtime dependencies, which are required to be
|
|||
|
installed on the target in order for the software to run.
|
|||
|
|
|||
|
Within a recipe, you specify build-time dependencies using the
|
|||
|
:term:`DEPENDS` variable. Although there are nuances,
|
|||
|
items specified in :term:`DEPENDS` should be names of other
|
|||
|
recipes. It is important that you specify all build-time dependencies
|
|||
|
explicitly.
|
|||
|
|
|||
|
Another consideration is that configure scripts might automatically
|
|||
|
check for optional dependencies and enable corresponding functionality
|
|||
|
if those dependencies are found. If you wish to make a recipe that is
|
|||
|
more generally useful (e.g. publish the recipe in a layer for others to
|
|||
|
use), instead of hard-disabling the functionality, you can use the
|
|||
|
:term:`PACKAGECONFIG` variable to allow functionality and the
|
|||
|
corresponding dependencies to be enabled and disabled easily by other
|
|||
|
users of the recipe.
|
|||
|
|
|||
|
Similar to build-time dependencies, you specify runtime dependencies
|
|||
|
through a variable -
|
|||
|
:term:`RDEPENDS`, which is
|
|||
|
package-specific. All variables that are package-specific need to have
|
|||
|
the name of the package added to the end as an override. Since the main
|
|||
|
package for a recipe has the same name as the recipe, and the recipe's
|
|||
|
name can be found through the
|
|||
|
``${``\ :term:`PN`\ ``}`` variable, then
|
|||
|
you specify the dependencies for the main package by setting
|
|||
|
``RDEPENDS:${PN}``. If the package were named ``${PN}-tools``, then you
|
|||
|
would set ``RDEPENDS:${PN}-tools``, and so forth.
|
|||
|
|
|||
|
Some runtime dependencies will be set automatically at packaging time.
|
|||
|
These dependencies include any shared library dependencies (i.e. if a
|
|||
|
package "example" contains "libexample" and another package "mypackage"
|
|||
|
contains a binary that links to "libexample" then the OpenEmbedded build
|
|||
|
system will automatically add a runtime dependency to "mypackage" on
|
|||
|
"example"). See the
|
|||
|
":ref:`overview-manual/concepts:automatically added runtime dependencies`"
|
|||
|
section in the Yocto Project Overview and Concepts Manual for further
|
|||
|
details.
|
|||
|
|
|||
|
Configuring the Recipe
|
|||
|
======================
|
|||
|
|
|||
|
Most software provides some means of setting build-time configuration
|
|||
|
options before compilation. Typically, setting these options is
|
|||
|
accomplished by running a configure script with options, or by modifying
|
|||
|
a build configuration file.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
As of Yocto Project Release 1.7, some of the core recipes that
|
|||
|
package binary configuration scripts now disable the scripts due to
|
|||
|
the scripts previously requiring error-prone path substitution. The
|
|||
|
OpenEmbedded build system uses ``pkg-config`` now, which is much more
|
|||
|
robust. You can find a list of the ``*-config`` scripts that are disabled
|
|||
|
in the ":ref:`migration-1.7-binary-configuration-scripts-disabled`" section
|
|||
|
in the Yocto Project Reference Manual.
|
|||
|
|
|||
|
A major part of build-time configuration is about checking for
|
|||
|
build-time dependencies and possibly enabling optional functionality as
|
|||
|
a result. You need to specify any build-time dependencies for the
|
|||
|
software you are building in your recipe's
|
|||
|
:term:`DEPENDS` value, in terms of
|
|||
|
other recipes that satisfy those dependencies. You can often find
|
|||
|
build-time or runtime dependencies described in the software's
|
|||
|
documentation.
|
|||
|
|
|||
|
The following list provides configuration items of note based on how
|
|||
|
your software is built:
|
|||
|
|
|||
|
- *Autotools:* If your source files have a ``configure.ac`` file, then
|
|||
|
your software is built using Autotools. If this is the case, you just
|
|||
|
need to modify the configuration.
|
|||
|
|
|||
|
When using Autotools, your recipe needs to inherit the
|
|||
|
:ref:`ref-classes-autotools` class and it does not have to
|
|||
|
contain a :ref:`ref-tasks-configure` task. However, you might still want to
|
|||
|
make some adjustments. For example, you can set :term:`EXTRA_OECONF` or
|
|||
|
:term:`PACKAGECONFIG_CONFARGS` to pass any needed configure options that
|
|||
|
are specific to the recipe.
|
|||
|
|
|||
|
- *CMake:* If your source files have a ``CMakeLists.txt`` file, then
|
|||
|
your software is built using CMake. If this is the case, you just
|
|||
|
need to modify the configuration.
|
|||
|
|
|||
|
When you use CMake, your recipe needs to inherit the
|
|||
|
:ref:`ref-classes-cmake` class and it does not have to contain a
|
|||
|
:ref:`ref-tasks-configure` task. You can make some adjustments by setting
|
|||
|
:term:`EXTRA_OECMAKE` to pass any needed configure options that are
|
|||
|
specific to the recipe.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
If you need to install one or more custom CMake toolchain files
|
|||
|
that are supplied by the application you are building, install the
|
|||
|
files to ``${D}${datadir}/cmake/Modules`` during :ref:`ref-tasks-install`.
|
|||
|
|
|||
|
- *Other:* If your source files do not have a ``configure.ac`` or
|
|||
|
``CMakeLists.txt`` file, then your software is built using some
|
|||
|
method other than Autotools or CMake. If this is the case, you
|
|||
|
normally need to provide a
|
|||
|
:ref:`ref-tasks-configure` task
|
|||
|
in your recipe unless, of course, there is nothing to configure.
|
|||
|
|
|||
|
Even if your software is not being built by Autotools or CMake, you
|
|||
|
still might not need to deal with any configuration issues. You need
|
|||
|
to determine if configuration is even a required step. You might need
|
|||
|
to modify a Makefile or some configuration file used for the build to
|
|||
|
specify necessary build options. Or, perhaps you might need to run a
|
|||
|
provided, custom configure script with the appropriate options.
|
|||
|
|
|||
|
For the case involving a custom configure script, you would run
|
|||
|
``./configure --help`` and look for the options you need to set.
|
|||
|
|
|||
|
Once configuration succeeds, it is always good practice to look at the
|
|||
|
``log.do_configure`` file to ensure that the appropriate options have
|
|||
|
been enabled and no additional build-time dependencies need to be added
|
|||
|
to :term:`DEPENDS`. For example, if the configure script reports that it
|
|||
|
found something not mentioned in :term:`DEPENDS`, or that it did not find
|
|||
|
something that it needed for some desired optional functionality, then
|
|||
|
you would need to add those to :term:`DEPENDS`. Looking at the log might
|
|||
|
also reveal items being checked for, enabled, or both that you do not
|
|||
|
want, or items not being found that are in :term:`DEPENDS`, in which case
|
|||
|
you would need to look at passing extra options to the configure script
|
|||
|
as needed. For reference information on configure options specific to
|
|||
|
the software you are building, you can consult the output of the
|
|||
|
``./configure --help`` command within ``${S}`` or consult the software's
|
|||
|
upstream documentation.
|
|||
|
|
|||
|
Using Headers to Interface with Devices
|
|||
|
=======================================
|
|||
|
|
|||
|
If your recipe builds an application that needs to communicate with some
|
|||
|
device or needs an API into a custom kernel, you will need to provide
|
|||
|
appropriate header files. Under no circumstances should you ever modify
|
|||
|
the existing
|
|||
|
``meta/recipes-kernel/linux-libc-headers/linux-libc-headers.inc`` file.
|
|||
|
These headers are used to build ``libc`` and must not be compromised
|
|||
|
with custom or machine-specific header information. If you customize
|
|||
|
``libc`` through modified headers all other applications that use
|
|||
|
``libc`` thus become affected.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Never copy and customize the ``libc`` header file (i.e.
|
|||
|
``meta/recipes-kernel/linux-libc-headers/linux-libc-headers.inc``).
|
|||
|
|
|||
|
The correct way to interface to a device or custom kernel is to use a
|
|||
|
separate package that provides the additional headers for the driver or
|
|||
|
other unique interfaces. When doing so, your application also becomes
|
|||
|
responsible for creating a dependency on that specific provider.
|
|||
|
|
|||
|
Consider the following:
|
|||
|
|
|||
|
- Never modify ``linux-libc-headers.inc``. Consider that file to be
|
|||
|
part of the ``libc`` system, and not something you use to access the
|
|||
|
kernel directly. You should access ``libc`` through specific ``libc``
|
|||
|
calls.
|
|||
|
|
|||
|
- Applications that must talk directly to devices should either provide
|
|||
|
necessary headers themselves, or establish a dependency on a special
|
|||
|
headers package that is specific to that driver.
|
|||
|
|
|||
|
For example, suppose you want to modify an existing header that adds I/O
|
|||
|
control or network support. If the modifications are used by a small
|
|||
|
number programs, providing a unique version of a header is easy and has
|
|||
|
little impact. When doing so, bear in mind the guidelines in the
|
|||
|
previous list.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
If for some reason your changes need to modify the behavior of the ``libc``,
|
|||
|
and subsequently all other applications on the system, use a ``.bbappend``
|
|||
|
to modify the ``linux-kernel-headers.inc`` file. However, take care to not
|
|||
|
make the changes machine specific.
|
|||
|
|
|||
|
Consider a case where your kernel is older and you need an older
|
|||
|
``libc`` ABI. The headers installed by your recipe should still be a
|
|||
|
standard mainline kernel, not your own custom one.
|
|||
|
|
|||
|
When you use custom kernel headers you need to get them from
|
|||
|
:term:`STAGING_KERNEL_DIR`,
|
|||
|
which is the directory with kernel headers that are required to build
|
|||
|
out-of-tree modules. Your recipe will also need the following::
|
|||
|
|
|||
|
do_configure[depends] += "virtual/kernel:do_shared_workdir"
|
|||
|
|
|||
|
Compilation
|
|||
|
===========
|
|||
|
|
|||
|
During a build, the :ref:`ref-tasks-compile` task happens after source is fetched,
|
|||
|
unpacked, and configured. If the recipe passes through :ref:`ref-tasks-compile`
|
|||
|
successfully, nothing needs to be done.
|
|||
|
|
|||
|
However, if the compile step fails, you need to diagnose the failure.
|
|||
|
Here are some common issues that cause failures.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
For cases where improper paths are detected for configuration files
|
|||
|
or for when libraries/headers cannot be found, be sure you are using
|
|||
|
the more robust ``pkg-config``. See the note in section
|
|||
|
":ref:`dev-manual/new-recipe:Configuring the Recipe`" for additional information.
|
|||
|
|
|||
|
- *Parallel build failures:* These failures manifest themselves as
|
|||
|
intermittent errors, or errors reporting that a file or directory
|
|||
|
that should be created by some other part of the build process could
|
|||
|
not be found. This type of failure can occur even if, upon
|
|||
|
inspection, the file or directory does exist after the build has
|
|||
|
failed, because that part of the build process happened in the wrong
|
|||
|
order.
|
|||
|
|
|||
|
To fix the problem, you need to either satisfy the missing dependency
|
|||
|
in the Makefile or whatever script produced the Makefile, or (as a
|
|||
|
workaround) set :term:`PARALLEL_MAKE` to an empty string::
|
|||
|
|
|||
|
PARALLEL_MAKE = ""
|
|||
|
|
|||
|
For information on parallel Makefile issues, see the
|
|||
|
":ref:`dev-manual/debugging:debugging parallel make races`" section.
|
|||
|
|
|||
|
- *Improper host path usage:* This failure applies to recipes building
|
|||
|
for the target or ":ref:`ref-classes-nativesdk`" only. The
|
|||
|
failure occurs when the compilation process uses improper headers,
|
|||
|
libraries, or other files from the host system when cross-compiling for
|
|||
|
the target.
|
|||
|
|
|||
|
To fix the problem, examine the ``log.do_compile`` file to identify
|
|||
|
the host paths being used (e.g. ``/usr/include``, ``/usr/lib``, and
|
|||
|
so forth) and then either add configure options, apply a patch, or do
|
|||
|
both.
|
|||
|
|
|||
|
- *Failure to find required libraries/headers:* If a build-time
|
|||
|
dependency is missing because it has not been declared in
|
|||
|
:term:`DEPENDS`, or because the
|
|||
|
dependency exists but the path used by the build process to find the
|
|||
|
file is incorrect and the configure step did not detect it, the
|
|||
|
compilation process could fail. For either of these failures, the
|
|||
|
compilation process notes that files could not be found. In these
|
|||
|
cases, you need to go back and add additional options to the
|
|||
|
configure script as well as possibly add additional build-time
|
|||
|
dependencies to :term:`DEPENDS`.
|
|||
|
|
|||
|
Occasionally, it is necessary to apply a patch to the source to
|
|||
|
ensure the correct paths are used. If you need to specify paths to
|
|||
|
find files staged into the sysroot from other recipes, use the
|
|||
|
variables that the OpenEmbedded build system provides (e.g.
|
|||
|
:term:`STAGING_BINDIR`, :term:`STAGING_INCDIR`, :term:`STAGING_DATADIR`, and so
|
|||
|
forth).
|
|||
|
|
|||
|
Installing
|
|||
|
==========
|
|||
|
|
|||
|
During :ref:`ref-tasks-install`, the task copies the built files along with their
|
|||
|
hierarchy to locations that would mirror their locations on the target
|
|||
|
device. The installation process copies files from the
|
|||
|
``${``\ :term:`S`\ ``}``,
|
|||
|
``${``\ :term:`B`\ ``}``, and
|
|||
|
``${``\ :term:`WORKDIR`\ ``}``
|
|||
|
directories to the ``${``\ :term:`D`\ ``}``
|
|||
|
directory to create the structure as it should appear on the target
|
|||
|
system.
|
|||
|
|
|||
|
How your software is built affects what you must do to be sure your
|
|||
|
software is installed correctly. The following list describes what you
|
|||
|
must do for installation depending on the type of build system used by
|
|||
|
the software being built:
|
|||
|
|
|||
|
- *Autotools and CMake:* If the software your recipe is building uses
|
|||
|
Autotools or CMake, the OpenEmbedded build system understands how to
|
|||
|
install the software. Consequently, you do not have to have a
|
|||
|
:ref:`ref-tasks-install` task as part of your recipe. You just need to make
|
|||
|
sure the install portion of the build completes with no issues.
|
|||
|
However, if you wish to install additional files not already being
|
|||
|
installed by ``make install``, you should do this using a
|
|||
|
``do_install:append`` function using the install command as described
|
|||
|
in the "Manual" bulleted item later in this list.
|
|||
|
|
|||
|
- *Other (using* ``make install``\ *)*: You need to define a :ref:`ref-tasks-install`
|
|||
|
function in your recipe. The function should call
|
|||
|
``oe_runmake install`` and will likely need to pass in the
|
|||
|
destination directory as well. How you pass that path is dependent on
|
|||
|
how the ``Makefile`` being run is written (e.g. ``DESTDIR=${D}``,
|
|||
|
``PREFIX=${D}``, ``INSTALLROOT=${D}``, and so forth).
|
|||
|
|
|||
|
For an example recipe using ``make install``, see the
|
|||
|
":ref:`dev-manual/new-recipe:building a makefile-based package`" section.
|
|||
|
|
|||
|
- *Manual:* You need to define a :ref:`ref-tasks-install` function in your
|
|||
|
recipe. The function must first use ``install -d`` to create the
|
|||
|
directories under
|
|||
|
``${``\ :term:`D`\ ``}``. Once the
|
|||
|
directories exist, your function can use ``install`` to manually
|
|||
|
install the built software into the directories.
|
|||
|
|
|||
|
You can find more information on ``install`` at
|
|||
|
https://www.gnu.org/software/coreutils/manual/html_node/install-invocation.html.
|
|||
|
|
|||
|
For the scenarios that do not use Autotools or CMake, you need to track
|
|||
|
the installation and diagnose and fix any issues until everything
|
|||
|
installs correctly. You need to look in the default location of
|
|||
|
``${D}``, which is ``${WORKDIR}/image``, to be sure your files have been
|
|||
|
installed correctly.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
- During the installation process, you might need to modify some of
|
|||
|
the installed files to suit the target layout. For example, you
|
|||
|
might need to replace hard-coded paths in an initscript with
|
|||
|
values of variables provided by the build system, such as
|
|||
|
replacing ``/usr/bin/`` with ``${bindir}``. If you do perform such
|
|||
|
modifications during :ref:`ref-tasks-install`, be sure to modify the
|
|||
|
destination file after copying rather than before copying.
|
|||
|
Modifying after copying ensures that the build system can
|
|||
|
re-execute :ref:`ref-tasks-install` if needed.
|
|||
|
|
|||
|
- ``oe_runmake install``, which can be run directly or can be run
|
|||
|
indirectly by the :ref:`ref-classes-autotools` and
|
|||
|
:ref:`ref-classes-cmake` classes, runs ``make install`` in parallel.
|
|||
|
Sometimes, a Makefile can have missing dependencies between targets that
|
|||
|
can result in race conditions. If you experience intermittent failures
|
|||
|
during :ref:`ref-tasks-install`, you might be able to work around them by
|
|||
|
disabling parallel Makefile installs by adding the following to the
|
|||
|
recipe::
|
|||
|
|
|||
|
PARALLEL_MAKEINST = ""
|
|||
|
|
|||
|
See :term:`PARALLEL_MAKEINST` for additional information.
|
|||
|
|
|||
|
- If you need to install one or more custom CMake toolchain files
|
|||
|
that are supplied by the application you are building, install the
|
|||
|
files to ``${D}${datadir}/cmake/Modules`` during
|
|||
|
:ref:`ref-tasks-install`.
|
|||
|
|
|||
|
Enabling System Services
|
|||
|
========================
|
|||
|
|
|||
|
If you want to install a service, which is a process that usually starts
|
|||
|
on boot and runs in the background, then you must include some
|
|||
|
additional definitions in your recipe.
|
|||
|
|
|||
|
If you are adding services and the service initialization script or the
|
|||
|
service file itself is not installed, you must provide for that
|
|||
|
installation in your recipe using a ``do_install:append`` function. If
|
|||
|
your recipe already has a :ref:`ref-tasks-install` function, update the function
|
|||
|
near its end rather than adding an additional ``do_install:append``
|
|||
|
function.
|
|||
|
|
|||
|
When you create the installation for your services, you need to
|
|||
|
accomplish what is normally done by ``make install``. In other words,
|
|||
|
make sure your installation arranges the output similar to how it is
|
|||
|
arranged on the target system.
|
|||
|
|
|||
|
The OpenEmbedded build system provides support for starting services two
|
|||
|
different ways:
|
|||
|
|
|||
|
- *SysVinit:* SysVinit is a system and service manager that manages the
|
|||
|
init system used to control the very basic functions of your system.
|
|||
|
The init program is the first program started by the Linux kernel
|
|||
|
when the system boots. Init then controls the startup, running and
|
|||
|
shutdown of all other programs.
|
|||
|
|
|||
|
To enable a service using SysVinit, your recipe needs to inherit the
|
|||
|
:ref:`ref-classes-update-rc.d` class. The class helps
|
|||
|
facilitate safely installing the package on the target.
|
|||
|
|
|||
|
You will need to set the
|
|||
|
:term:`INITSCRIPT_PACKAGES`,
|
|||
|
:term:`INITSCRIPT_NAME`,
|
|||
|
and
|
|||
|
:term:`INITSCRIPT_PARAMS`
|
|||
|
variables within your recipe.
|
|||
|
|
|||
|
- *systemd:* System Management Daemon (systemd) was designed to replace
|
|||
|
SysVinit and to provide enhanced management of services. For more
|
|||
|
information on systemd, see the systemd homepage at
|
|||
|
https://freedesktop.org/wiki/Software/systemd/.
|
|||
|
|
|||
|
To enable a service using systemd, your recipe needs to inherit the
|
|||
|
:ref:`ref-classes-systemd` class. See the ``systemd.bbclass`` file
|
|||
|
located in your :term:`Source Directory` section for more information.
|
|||
|
|
|||
|
Packaging
|
|||
|
=========
|
|||
|
|
|||
|
Successful packaging is a combination of automated processes performed
|
|||
|
by the OpenEmbedded build system and some specific steps you need to
|
|||
|
take. The following list describes the process:
|
|||
|
|
|||
|
- *Splitting Files*: The :ref:`ref-tasks-package` task splits the files produced
|
|||
|
by the recipe into logical components. Even software that produces a
|
|||
|
single binary might still have debug symbols, documentation, and
|
|||
|
other logical components that should be split out. The :ref:`ref-tasks-package`
|
|||
|
task ensures that files are split up and packaged correctly.
|
|||
|
|
|||
|
- *Running QA Checks*: The :ref:`ref-classes-insane` class adds a
|
|||
|
step to the package generation process so that output quality
|
|||
|
assurance checks are generated by the OpenEmbedded build system. This
|
|||
|
step performs a range of checks to be sure the build's output is free
|
|||
|
of common problems that show up during runtime. For information on
|
|||
|
these checks, see the :ref:`ref-classes-insane` class and
|
|||
|
the ":ref:`ref-manual/qa-checks:qa error and warning messages`"
|
|||
|
chapter in the Yocto Project Reference Manual.
|
|||
|
|
|||
|
- *Hand-Checking Your Packages*: After you build your software, you
|
|||
|
need to be sure your packages are correct. Examine the
|
|||
|
``${``\ :term:`WORKDIR`\ ``}/packages-split``
|
|||
|
directory and make sure files are where you expect them to be. If you
|
|||
|
discover problems, you can set
|
|||
|
:term:`PACKAGES`,
|
|||
|
:term:`FILES`,
|
|||
|
``do_install(:append)``, and so forth as needed.
|
|||
|
|
|||
|
- *Splitting an Application into Multiple Packages*: If you need to
|
|||
|
split an application into several packages, see the
|
|||
|
":ref:`dev-manual/new-recipe:splitting an application into multiple packages`"
|
|||
|
section for an example.
|
|||
|
|
|||
|
- *Installing a Post-Installation Script*: For an example showing how
|
|||
|
to install a post-installation script, see the
|
|||
|
":ref:`dev-manual/new-recipe:post-installation scripts`" section.
|
|||
|
|
|||
|
- *Marking Package Architecture*: Depending on what your recipe is
|
|||
|
building and how it is configured, it might be important to mark the
|
|||
|
packages produced as being specific to a particular machine, or to
|
|||
|
mark them as not being specific to a particular machine or
|
|||
|
architecture at all.
|
|||
|
|
|||
|
By default, packages apply to any machine with the same architecture
|
|||
|
as the target machine. When a recipe produces packages that are
|
|||
|
machine-specific (e.g. the
|
|||
|
:term:`MACHINE` value is passed
|
|||
|
into the configure script or a patch is applied only for a particular
|
|||
|
machine), you should mark them as such by adding the following to the
|
|||
|
recipe::
|
|||
|
|
|||
|
PACKAGE_ARCH = "${MACHINE_ARCH}"
|
|||
|
|
|||
|
On the other hand, if the recipe produces packages that do not
|
|||
|
contain anything specific to the target machine or architecture at
|
|||
|
all (e.g. recipes that simply package script files or configuration
|
|||
|
files), you should use the :ref:`ref-classes-allarch` class to
|
|||
|
do this for you by adding this to your recipe::
|
|||
|
|
|||
|
inherit allarch
|
|||
|
|
|||
|
Ensuring that the package architecture is correct is not critical
|
|||
|
while you are doing the first few builds of your recipe. However, it
|
|||
|
is important in order to ensure that your recipe rebuilds (or does
|
|||
|
not rebuild) appropriately in response to changes in configuration,
|
|||
|
and to ensure that you get the appropriate packages installed on the
|
|||
|
target machine, particularly if you run separate builds for more than
|
|||
|
one target machine.
|
|||
|
|
|||
|
Sharing Files Between Recipes
|
|||
|
=============================
|
|||
|
|
|||
|
Recipes often need to use files provided by other recipes on the build
|
|||
|
host. For example, an application linking to a common library needs
|
|||
|
access to the library itself and its associated headers. The way this
|
|||
|
access is accomplished is by populating a sysroot with files. Each
|
|||
|
recipe has two sysroots in its work directory, one for target files
|
|||
|
(``recipe-sysroot``) and one for files that are native to the build host
|
|||
|
(``recipe-sysroot-native``).
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
You could find the term "staging" used within the Yocto project
|
|||
|
regarding files populating sysroots (e.g. the :term:`STAGING_DIR`
|
|||
|
variable).
|
|||
|
|
|||
|
Recipes should never populate the sysroot directly (i.e. write files
|
|||
|
into sysroot). Instead, files should be installed into standard
|
|||
|
locations during the
|
|||
|
:ref:`ref-tasks-install` task within
|
|||
|
the ``${``\ :term:`D`\ ``}`` directory. The
|
|||
|
reason for this limitation is that almost all files that populate the
|
|||
|
sysroot are cataloged in manifests in order to ensure the files can be
|
|||
|
removed later when a recipe is either modified or removed. Thus, the
|
|||
|
sysroot is able to remain free from stale files.
|
|||
|
|
|||
|
A subset of the files installed by the :ref:`ref-tasks-install` task are
|
|||
|
used by the :ref:`ref-tasks-populate_sysroot` task as defined by the
|
|||
|
:term:`SYSROOT_DIRS` variable to automatically populate the sysroot. It
|
|||
|
is possible to modify the list of directories that populate the sysroot.
|
|||
|
The following example shows how you could add the ``/opt`` directory to
|
|||
|
the list of directories within a recipe::
|
|||
|
|
|||
|
SYSROOT_DIRS += "/opt"
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
The `/sysroot-only` is to be used by recipes that generate artifacts
|
|||
|
that are not included in the target filesystem, allowing them to share
|
|||
|
these artifacts without needing to use the :term:`DEPLOY_DIR`.
|
|||
|
|
|||
|
For a more complete description of the :ref:`ref-tasks-populate_sysroot`
|
|||
|
task and its associated functions, see the
|
|||
|
:ref:`staging <ref-classes-staging>` class.
|
|||
|
|
|||
|
Using Virtual Providers
|
|||
|
=======================
|
|||
|
|
|||
|
Prior to a build, if you know that several different recipes provide the
|
|||
|
same functionality, you can use a virtual provider (i.e. ``virtual/*``)
|
|||
|
as a placeholder for the actual provider. The actual provider is
|
|||
|
determined at build-time.
|
|||
|
|
|||
|
A common scenario where a virtual provider is used would be for the kernel
|
|||
|
recipe. Suppose you have three kernel recipes whose :term:`PN` values map to
|
|||
|
``kernel-big``, ``kernel-mid``, and ``kernel-small``. Furthermore, each of
|
|||
|
these recipes in some way uses a :term:`PROVIDES` statement that essentially
|
|||
|
identifies itself as being able to provide ``virtual/kernel``. Here is one way
|
|||
|
through the :ref:`ref-classes-kernel` class::
|
|||
|
|
|||
|
PROVIDES += "virtual/kernel"
|
|||
|
|
|||
|
Any recipe that inherits the :ref:`ref-classes-kernel` class is
|
|||
|
going to utilize a :term:`PROVIDES` statement that identifies that recipe as
|
|||
|
being able to provide the ``virtual/kernel`` item.
|
|||
|
|
|||
|
Now comes the time to actually build an image and you need a kernel
|
|||
|
recipe, but which one? You can configure your build to call out the
|
|||
|
kernel recipe you want by using the :term:`PREFERRED_PROVIDER` variable. As
|
|||
|
an example, consider the :yocto_git:`x86-base.inc
|
|||
|
</poky/tree/meta/conf/machine/include/x86/x86-base.inc>` include file, which is a
|
|||
|
machine (i.e. :term:`MACHINE`) configuration file. This include file is the
|
|||
|
reason all x86-based machines use the ``linux-yocto`` kernel. Here are the
|
|||
|
relevant lines from the include file::
|
|||
|
|
|||
|
PREFERRED_PROVIDER_virtual/kernel ??= "linux-yocto"
|
|||
|
PREFERRED_VERSION_linux-yocto ??= "4.15%"
|
|||
|
|
|||
|
When you use a virtual provider, you do not have to "hard code" a recipe
|
|||
|
name as a build dependency. You can use the
|
|||
|
:term:`DEPENDS` variable to state the
|
|||
|
build is dependent on ``virtual/kernel`` for example::
|
|||
|
|
|||
|
DEPENDS = "virtual/kernel"
|
|||
|
|
|||
|
During the build, the OpenEmbedded build system picks
|
|||
|
the correct recipe needed for the ``virtual/kernel`` dependency based on
|
|||
|
the :term:`PREFERRED_PROVIDER` variable. If you want to use the small kernel
|
|||
|
mentioned at the beginning of this section, configure your build as
|
|||
|
follows::
|
|||
|
|
|||
|
PREFERRED_PROVIDER_virtual/kernel ??= "kernel-small"
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Any recipe that :term:`PROVIDES` a ``virtual/*`` item that is ultimately not
|
|||
|
selected through :term:`PREFERRED_PROVIDER` does not get built. Preventing these
|
|||
|
recipes from building is usually the desired behavior since this mechanism's
|
|||
|
purpose is to select between mutually exclusive alternative providers.
|
|||
|
|
|||
|
The following lists specific examples of virtual providers:
|
|||
|
|
|||
|
- ``virtual/kernel``: Provides the name of the kernel recipe to use
|
|||
|
when building a kernel image.
|
|||
|
|
|||
|
- ``virtual/bootloader``: Provides the name of the bootloader to use
|
|||
|
when building an image.
|
|||
|
|
|||
|
- ``virtual/libgbm``: Provides ``gbm.pc``.
|
|||
|
|
|||
|
- ``virtual/egl``: Provides ``egl.pc`` and possibly ``wayland-egl.pc``.
|
|||
|
|
|||
|
- ``virtual/libgl``: Provides ``gl.pc`` (i.e. libGL).
|
|||
|
|
|||
|
- ``virtual/libgles1``: Provides ``glesv1_cm.pc`` (i.e. libGLESv1_CM).
|
|||
|
|
|||
|
- ``virtual/libgles2``: Provides ``glesv2.pc`` (i.e. libGLESv2).
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Virtual providers only apply to build time dependencies specified with
|
|||
|
:term:`PROVIDES` and :term:`DEPENDS`. They do not apply to runtime
|
|||
|
dependencies specified with :term:`RPROVIDES` and :term:`RDEPENDS`.
|
|||
|
|
|||
|
Properly Versioning Pre-Release Recipes
|
|||
|
=======================================
|
|||
|
|
|||
|
Sometimes the name of a recipe can lead to versioning problems when the
|
|||
|
recipe is upgraded to a final release. For example, consider the
|
|||
|
``irssi_0.8.16-rc1.bb`` recipe file in the list of example recipes in
|
|||
|
the ":ref:`dev-manual/new-recipe:storing and naming the recipe`" section.
|
|||
|
This recipe is at a release candidate stage (i.e. "rc1"). When the recipe is
|
|||
|
released, the recipe filename becomes ``irssi_0.8.16.bb``. The version
|
|||
|
change from ``0.8.16-rc1`` to ``0.8.16`` is seen as a decrease by the
|
|||
|
build system and package managers, so the resulting packages will not
|
|||
|
correctly trigger an upgrade.
|
|||
|
|
|||
|
In order to ensure the versions compare properly, the recommended
|
|||
|
convention is to use a tilde (``~``) character as follows::
|
|||
|
|
|||
|
PV = 0.8.16~rc1
|
|||
|
|
|||
|
This way ``0.8.16~rc1`` sorts before ``0.8.16``. See the
|
|||
|
":ref:`contributor-guide/recipe-style-guide:version policy`" section in the
|
|||
|
Yocto Project and OpenEmbedded Contributor Guide for more details about
|
|||
|
versioning code corresponding to a pre-release or to a specific Git commit.
|
|||
|
|
|||
|
Post-Installation Scripts
|
|||
|
=========================
|
|||
|
|
|||
|
Post-installation scripts run immediately after installing a package on
|
|||
|
the target or during image creation when a package is included in an
|
|||
|
image. To add a post-installation script to a package, add a
|
|||
|
``pkg_postinst:``\ `PACKAGENAME`\ ``()`` function to the recipe file
|
|||
|
(``.bb``) and replace `PACKAGENAME` with the name of the package you want
|
|||
|
to attach to the ``postinst`` script. To apply the post-installation
|
|||
|
script to the main package for the recipe, which is usually what is
|
|||
|
required, specify
|
|||
|
``${``\ :term:`PN`\ ``}`` in place of
|
|||
|
PACKAGENAME.
|
|||
|
|
|||
|
A post-installation function has the following structure::
|
|||
|
|
|||
|
pkg_postinst:PACKAGENAME() {
|
|||
|
# Commands to carry out
|
|||
|
}
|
|||
|
|
|||
|
The script defined in the post-installation function is called when the
|
|||
|
root filesystem is created. If the script succeeds, the package is
|
|||
|
marked as installed.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
Any RPM post-installation script that runs on the target should
|
|||
|
return a 0 exit code. RPM does not allow non-zero exit codes for
|
|||
|
these scripts, and the RPM package manager will cause the package to
|
|||
|
fail installation on the target.
|
|||
|
|
|||
|
Sometimes it is necessary for the execution of a post-installation
|
|||
|
script to be delayed until the first boot. For example, the script might
|
|||
|
need to be executed on the device itself. To delay script execution
|
|||
|
until boot time, you must explicitly mark post installs to defer to the
|
|||
|
target. You can use ``pkg_postinst_ontarget()`` or call
|
|||
|
``postinst_intercept delay_to_first_boot`` from ``pkg_postinst()``. Any
|
|||
|
failure of a ``pkg_postinst()`` script (including exit 1) triggers an
|
|||
|
error during the
|
|||
|
:ref:`ref-tasks-rootfs` task.
|
|||
|
|
|||
|
If you have recipes that use ``pkg_postinst`` function and they require
|
|||
|
the use of non-standard native tools that have dependencies during
|
|||
|
root filesystem construction, you need to use the
|
|||
|
:term:`PACKAGE_WRITE_DEPS`
|
|||
|
variable in your recipe to list these tools. If you do not use this
|
|||
|
variable, the tools might be missing and execution of the
|
|||
|
post-installation script is deferred until first boot. Deferring the
|
|||
|
script to the first boot is undesirable and impossible for read-only
|
|||
|
root filesystems.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
There is equivalent support for pre-install, pre-uninstall, and post-uninstall
|
|||
|
scripts by way of ``pkg_preinst``, ``pkg_prerm``, and ``pkg_postrm``,
|
|||
|
respectively. These scrips work in exactly the same way as does
|
|||
|
``pkg_postinst`` with the exception that they run at different times. Also,
|
|||
|
because of when they run, they are not applicable to being run at image
|
|||
|
creation time like ``pkg_postinst``.
|
|||
|
|
|||
|
Testing
|
|||
|
=======
|
|||
|
|
|||
|
The final step for completing your recipe is to be sure that the
|
|||
|
software you built runs correctly. To accomplish runtime testing, add
|
|||
|
the build's output packages to your image and test them on the target.
|
|||
|
|
|||
|
For information on how to customize your image by adding specific
|
|||
|
packages, see ":ref:`dev-manual/customizing-images:customizing images`" section.
|
|||
|
|
|||
|
Examples
|
|||
|
========
|
|||
|
|
|||
|
To help summarize how to write a recipe, this section provides some
|
|||
|
recipe examples given various scenarios:
|
|||
|
|
|||
|
- `Building a single .c file package`_
|
|||
|
|
|||
|
- `Building a Makefile-based package`_
|
|||
|
|
|||
|
- `Building an Autotooled package`_
|
|||
|
|
|||
|
- `Building a Meson package`_
|
|||
|
|
|||
|
- `Splitting an application into multiple packages`_
|
|||
|
|
|||
|
- `Packaging externally produced binaries`_
|
|||
|
|
|||
|
Building a Single .c File Package
|
|||
|
---------------------------------
|
|||
|
|
|||
|
Building an application from a single file that is stored locally (e.g. under
|
|||
|
``files``) requires a recipe that has the file listed in the :term:`SRC_URI`
|
|||
|
variable. Additionally, you need to manually write the :ref:`ref-tasks-compile`
|
|||
|
and :ref:`ref-tasks-install` tasks. The :term:`S` variable defines the
|
|||
|
directory containing the source code, which is set to :term:`WORKDIR` in this
|
|||
|
case --- the directory BitBake uses for the build::
|
|||
|
|
|||
|
SUMMARY = "Simple helloworld application"
|
|||
|
SECTION = "examples"
|
|||
|
LICENSE = "MIT"
|
|||
|
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
|
|||
|
|
|||
|
SRC_URI = "file://helloworld.c"
|
|||
|
|
|||
|
S = "${WORKDIR}"
|
|||
|
|
|||
|
do_compile() {
|
|||
|
${CC} ${LDFLAGS} helloworld.c -o helloworld
|
|||
|
}
|
|||
|
|
|||
|
do_install() {
|
|||
|
install -d ${D}${bindir}
|
|||
|
install -m 0755 helloworld ${D}${bindir}
|
|||
|
}
|
|||
|
|
|||
|
By default, the ``helloworld``, ``helloworld-dbg``, and ``helloworld-dev`` packages
|
|||
|
are built. For information on how to customize the packaging process, see the
|
|||
|
":ref:`dev-manual/new-recipe:splitting an application into multiple packages`"
|
|||
|
section.
|
|||
|
|
|||
|
Building a Makefile-Based Package
|
|||
|
---------------------------------
|
|||
|
|
|||
|
Applications built with GNU ``make`` require a recipe that has the source archive
|
|||
|
listed in :term:`SRC_URI`. You do not need to add a :ref:`ref-tasks-compile`
|
|||
|
step since by default BitBake starts the ``make`` command to compile the
|
|||
|
application. If you need additional ``make`` options, you should store them in
|
|||
|
the :term:`EXTRA_OEMAKE` or :term:`PACKAGECONFIG_CONFARGS` variables. BitBake
|
|||
|
passes these options into the GNU ``make`` invocation. Note that a
|
|||
|
:ref:`ref-tasks-install` task is still required. Otherwise, BitBake runs an
|
|||
|
empty :ref:`ref-tasks-install` task by default.
|
|||
|
|
|||
|
Some applications might require extra parameters to be passed to the
|
|||
|
compiler. For example, the application might need an additional header
|
|||
|
path. You can accomplish this by adding to the :term:`CFLAGS` variable. The
|
|||
|
following example shows this::
|
|||
|
|
|||
|
CFLAGS:prepend = "-I ${S}/include "
|
|||
|
|
|||
|
In the following example, ``lz4`` is a makefile-based package::
|
|||
|
|
|||
|
SUMMARY = "Extremely Fast Compression algorithm"
|
|||
|
DESCRIPTION = "LZ4 is a very fast lossless compression algorithm, providing compression speed at 400 MB/s per core, scalable with multi-cores CPU. It also features an extremely fast decoder, with speed in multiple GB/s per core, typically reaching RAM speed limits on multi-core systems."
|
|||
|
HOMEPAGE = "https://github.com/lz4/lz4"
|
|||
|
|
|||
|
LICENSE = "BSD-2-Clause | GPL-2.0-only"
|
|||
|
LIC_FILES_CHKSUM = "file://lib/LICENSE;md5=ebc2ea4814a64de7708f1571904b32cc \
|
|||
|
file://programs/COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263 \
|
|||
|
file://LICENSE;md5=d57c0d21cb917fb4e0af2454aa48b956 \
|
|||
|
"
|
|||
|
|
|||
|
PE = "1"
|
|||
|
|
|||
|
SRCREV = "d44371841a2f1728a3f36839fd4b7e872d0927d3"
|
|||
|
|
|||
|
SRC_URI = "git://github.com/lz4/lz4.git;branch=release;protocol=https \
|
|||
|
file://CVE-2021-3520.patch \
|
|||
|
"
|
|||
|
UPSTREAM_CHECK_GITTAGREGEX = "v(?P<pver>.*)"
|
|||
|
|
|||
|
S = "${WORKDIR}/git"
|
|||
|
|
|||
|
# Fixed in r118, which is larger than the current version.
|
|||
|
CVE_CHECK_IGNORE += "CVE-2014-4715"
|
|||
|
|
|||
|
EXTRA_OEMAKE = "PREFIX=${prefix} CC='${CC}' CFLAGS='${CFLAGS}' DESTDIR=${D} LIBDIR=${libdir} INCLUDEDIR=${includedir} BUILD_STATIC=no"
|
|||
|
|
|||
|
do_install() {
|
|||
|
oe_runmake install
|
|||
|
}
|
|||
|
|
|||
|
BBCLASSEXTEND = "native nativesdk"
|
|||
|
|
|||
|
Building an Autotooled Package
|
|||
|
------------------------------
|
|||
|
|
|||
|
Applications built with the Autotools such as ``autoconf`` and ``automake``
|
|||
|
require a recipe that has a source archive listed in :term:`SRC_URI` and also
|
|||
|
inherit the :ref:`ref-classes-autotools` class, which contains the definitions
|
|||
|
of all the steps needed to build an Autotool-based application. The result of
|
|||
|
the build is automatically packaged. And, if the application uses NLS for
|
|||
|
localization, packages with local information are generated (one package per
|
|||
|
language). Following is one example: (``hello_2.3.bb``)::
|
|||
|
|
|||
|
SUMMARY = "GNU Helloworld application"
|
|||
|
SECTION = "examples"
|
|||
|
LICENSE = "GPL-2.0-or-later"
|
|||
|
LIC_FILES_CHKSUM = "file://COPYING;md5=751419260aa954499f7abaabaa882bbe"
|
|||
|
|
|||
|
SRC_URI = "${GNU_MIRROR}/hello/hello-${PV}.tar.gz"
|
|||
|
|
|||
|
inherit autotools gettext
|
|||
|
|
|||
|
The variable :term:`LIC_FILES_CHKSUM` is used to track source license changes
|
|||
|
as described in the ":ref:`dev-manual/licenses:tracking license changes`"
|
|||
|
section in the Yocto Project Overview and Concepts Manual. You can quickly
|
|||
|
create Autotool-based recipes in a manner similar to the previous example.
|
|||
|
|
|||
|
.. _ref-building-meson-package:
|
|||
|
|
|||
|
Building a Meson Package
|
|||
|
------------------------
|
|||
|
|
|||
|
Applications built with the `Meson build system <https://mesonbuild.com/>`__
|
|||
|
just need a recipe that has sources described in :term:`SRC_URI` and inherits
|
|||
|
the :ref:`ref-classes-meson` class.
|
|||
|
|
|||
|
The :oe_git:`ipcalc recipe </meta-openembedded/tree/meta-networking/recipes-support/ipcalc>`
|
|||
|
is a simple example of an application without dependencies::
|
|||
|
|
|||
|
SUMMARY = "Tool to assist in network address calculations for IPv4 and IPv6."
|
|||
|
HOMEPAGE = "https://gitlab.com/ipcalc/ipcalc"
|
|||
|
|
|||
|
SECTION = "net"
|
|||
|
|
|||
|
LICENSE = "GPL-2.0-only"
|
|||
|
LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263"
|
|||
|
|
|||
|
SRC_URI = "git://gitlab.com/ipcalc/ipcalc.git;protocol=https;branch=master"
|
|||
|
SRCREV = "4c4261a47f355946ee74013d4f5d0494487cc2d6"
|
|||
|
|
|||
|
S = "${WORKDIR}/git"
|
|||
|
|
|||
|
inherit meson
|
|||
|
|
|||
|
Applications with dependencies are likely to inherit the
|
|||
|
:ref:`ref-classes-pkgconfig` class, as ``pkg-config`` is the default method
|
|||
|
used by Meson to find dependencies and compile applications against them.
|
|||
|
|
|||
|
Splitting an Application into Multiple Packages
|
|||
|
-----------------------------------------------
|
|||
|
|
|||
|
You can use the variables :term:`PACKAGES` and :term:`FILES` to split an
|
|||
|
application into multiple packages.
|
|||
|
|
|||
|
Following is an example that uses the ``libxpm`` recipe. By default,
|
|||
|
this recipe generates a single package that contains the library along
|
|||
|
with a few binaries. You can modify the recipe to split the binaries
|
|||
|
into separate packages::
|
|||
|
|
|||
|
require xorg-lib-common.inc
|
|||
|
|
|||
|
SUMMARY = "Xpm: X Pixmap extension library"
|
|||
|
LICENSE = "MIT"
|
|||
|
LIC_FILES_CHKSUM = "file://COPYING;md5=51f4270b012ecd4ab1a164f5f4ed6cf7"
|
|||
|
DEPENDS += "libxext libsm libxt"
|
|||
|
PE = "1"
|
|||
|
|
|||
|
XORG_PN = "libXpm"
|
|||
|
|
|||
|
PACKAGES =+ "sxpm cxpm"
|
|||
|
FILES:cxpm = "${bindir}/cxpm"
|
|||
|
FILES:sxpm = "${bindir}/sxpm"
|
|||
|
|
|||
|
In the previous example, we want to ship the ``sxpm`` and ``cxpm``
|
|||
|
binaries in separate packages. Since ``bindir`` would be packaged into
|
|||
|
the main :term:`PN` package by default, we prepend the :term:`PACKAGES` variable
|
|||
|
so additional package names are added to the start of list. This results
|
|||
|
in the extra ``FILES:*`` variables then containing information that
|
|||
|
define which files and directories go into which packages. Files
|
|||
|
included by earlier packages are skipped by latter packages. Thus, the
|
|||
|
main :term:`PN` package does not include the above listed files.
|
|||
|
|
|||
|
Packaging Externally Produced Binaries
|
|||
|
--------------------------------------
|
|||
|
|
|||
|
Sometimes, you need to add pre-compiled binaries to an image. For
|
|||
|
example, suppose that there are binaries for proprietary code,
|
|||
|
created by a particular division of a company. Your part of the company
|
|||
|
needs to use those binaries as part of an image that you are building
|
|||
|
using the OpenEmbedded build system. Since you only have the binaries
|
|||
|
and not the source code, you cannot use a typical recipe that expects to
|
|||
|
fetch the source specified in
|
|||
|
:term:`SRC_URI` and then compile it.
|
|||
|
|
|||
|
One method is to package the binaries and then install them as part of
|
|||
|
the image. Generally, it is not a good idea to package binaries since,
|
|||
|
among other things, it can hinder the ability to reproduce builds and
|
|||
|
could lead to compatibility problems with ABI in the future. However,
|
|||
|
sometimes you have no choice.
|
|||
|
|
|||
|
The easiest solution is to create a recipe that uses the
|
|||
|
:ref:`ref-classes-bin-package` class and to be sure that you are using default
|
|||
|
locations for build artifacts. In most cases, the
|
|||
|
:ref:`ref-classes-bin-package` class handles "skipping" the configure and
|
|||
|
compile steps as well as sets things up to grab packages from the appropriate
|
|||
|
area. In particular, this class sets ``noexec`` on both the
|
|||
|
:ref:`ref-tasks-configure` and :ref:`ref-tasks-compile` tasks, sets
|
|||
|
``FILES:${PN}`` to "/" so that it picks up all files, and sets up a
|
|||
|
:ref:`ref-tasks-install` task, which effectively copies all files from ``${S}``
|
|||
|
to ``${D}``. The :ref:`ref-classes-bin-package` class works well when the files
|
|||
|
extracted into ``${S}`` are already laid out in the way they should be laid out
|
|||
|
on the target. For more information on these variables, see the :term:`FILES`,
|
|||
|
:term:`PN`, :term:`S`, and :term:`D` variables in the Yocto Project Reference
|
|||
|
Manual's variable glossary.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
- Using :term:`DEPENDS` is a good
|
|||
|
idea even for components distributed in binary form, and is often
|
|||
|
necessary for shared libraries. For a shared library, listing the
|
|||
|
library dependencies in :term:`DEPENDS` makes sure that the libraries
|
|||
|
are available in the staging sysroot when other recipes link
|
|||
|
against the library, which might be necessary for successful
|
|||
|
linking.
|
|||
|
|
|||
|
- Using :term:`DEPENDS` also allows runtime dependencies between
|
|||
|
packages to be added automatically. See the
|
|||
|
":ref:`overview-manual/concepts:automatically added runtime dependencies`"
|
|||
|
section in the Yocto Project Overview and Concepts Manual for more
|
|||
|
information.
|
|||
|
|
|||
|
If you cannot use the :ref:`ref-classes-bin-package` class, you need to be sure you are
|
|||
|
doing the following:
|
|||
|
|
|||
|
- Create a recipe where the
|
|||
|
:ref:`ref-tasks-configure` and
|
|||
|
:ref:`ref-tasks-compile` tasks do
|
|||
|
nothing: It is usually sufficient to just not define these tasks in
|
|||
|
the recipe, because the default implementations do nothing unless a
|
|||
|
Makefile is found in
|
|||
|
``${``\ :term:`S`\ ``}``.
|
|||
|
|
|||
|
If ``${S}`` might contain a Makefile, or if you inherit some class
|
|||
|
that replaces :ref:`ref-tasks-configure` and :ref:`ref-tasks-compile` with custom
|
|||
|
versions, then you can use the
|
|||
|
``[``\ :ref:`noexec <bitbake-user-manual/bitbake-user-manual-metadata:variable flags>`\ ``]``
|
|||
|
flag to turn the tasks into no-ops, as follows::
|
|||
|
|
|||
|
do_configure[noexec] = "1"
|
|||
|
do_compile[noexec] = "1"
|
|||
|
|
|||
|
Unlike :ref:`bitbake-user-manual/bitbake-user-manual-metadata:deleting a task`,
|
|||
|
using the flag preserves the dependency chain from the :ref:`ref-tasks-fetch`,
|
|||
|
:ref:`ref-tasks-unpack`, and :ref:`ref-tasks-patch` tasks to the
|
|||
|
:ref:`ref-tasks-install` task.
|
|||
|
|
|||
|
- Make sure your :ref:`ref-tasks-install` task installs the binaries
|
|||
|
appropriately.
|
|||
|
|
|||
|
- Ensure that you set up :term:`FILES`
|
|||
|
(usually
|
|||
|
``FILES:${``\ :term:`PN`\ ``}``) to
|
|||
|
point to the files you have installed, which of course depends on
|
|||
|
where you have installed them and whether those files are in
|
|||
|
different locations than the defaults.
|
|||
|
|
|||
|
Following Recipe Style Guidelines
|
|||
|
=================================
|
|||
|
|
|||
|
When writing recipes, it is good to conform to existing style guidelines.
|
|||
|
See the ":doc:`../contributor-guide/recipe-style-guide`" in the Yocto Project
|
|||
|
and OpenEmbedded Contributor Guide for reference.
|
|||
|
|
|||
|
It is common for existing recipes to deviate a bit from this style.
|
|||
|
However, aiming for at least a consistent style is a good idea. Some
|
|||
|
practices, such as omitting spaces around ``=`` operators in assignments
|
|||
|
or ordering recipe components in an erratic way, are widely seen as poor
|
|||
|
style.
|
|||
|
|
|||
|
Recipe Syntax
|
|||
|
=============
|
|||
|
|
|||
|
Understanding recipe file syntax is important for writing recipes. The
|
|||
|
following list overviews the basic items that make up a BitBake recipe
|
|||
|
file. For more complete BitBake syntax descriptions, see the
|
|||
|
":doc:`bitbake:bitbake-user-manual/bitbake-user-manual-metadata`"
|
|||
|
chapter of the BitBake User Manual.
|
|||
|
|
|||
|
- *Variable Assignments and Manipulations:* Variable assignments allow
|
|||
|
a value to be assigned to a variable. The assignment can be static
|
|||
|
text or might include the contents of other variables. In addition to
|
|||
|
the assignment, appending and prepending operations are also
|
|||
|
supported.
|
|||
|
|
|||
|
The following example shows some of the ways you can use variables in
|
|||
|
recipes::
|
|||
|
|
|||
|
S = "${WORKDIR}/postfix-${PV}"
|
|||
|
CFLAGS += "-DNO_ASM"
|
|||
|
CFLAGS:append = " --enable-important-feature"
|
|||
|
|
|||
|
- *Functions:* Functions provide a series of actions to be performed.
|
|||
|
You usually use functions to override the default implementation of a
|
|||
|
task function or to complement a default function (i.e. append or
|
|||
|
prepend to an existing function). Standard functions use ``sh`` shell
|
|||
|
syntax, although access to OpenEmbedded variables and internal
|
|||
|
methods are also available.
|
|||
|
|
|||
|
Here is an example function from the ``sed`` recipe::
|
|||
|
|
|||
|
do_install () {
|
|||
|
autotools_do_install
|
|||
|
install -d ${D}${base_bindir}
|
|||
|
mv ${D}${bindir}/sed ${D}${base_bindir}/sed
|
|||
|
rmdir ${D}${bindir}/
|
|||
|
}
|
|||
|
|
|||
|
It is
|
|||
|
also possible to implement new functions that are called between
|
|||
|
existing tasks as long as the new functions are not replacing or
|
|||
|
complementing the default functions. You can implement functions in
|
|||
|
Python instead of shell. Both of these options are not seen in the
|
|||
|
majority of recipes.
|
|||
|
|
|||
|
- *Keywords:* BitBake recipes use only a few keywords. You use keywords
|
|||
|
to include common functions (``inherit``), load parts of a recipe
|
|||
|
from other files (``include`` and ``require``) and export variables
|
|||
|
to the environment (``export``).
|
|||
|
|
|||
|
The following example shows the use of some of these keywords::
|
|||
|
|
|||
|
export POSTCONF = "${STAGING_BINDIR}/postconf"
|
|||
|
inherit autoconf
|
|||
|
require otherfile.inc
|
|||
|
|
|||
|
- *Comments (#):* Any lines that begin with the hash character (``#``)
|
|||
|
are treated as comment lines and are ignored::
|
|||
|
|
|||
|
# This is a comment
|
|||
|
|
|||
|
This next list summarizes the most important and most commonly used
|
|||
|
parts of the recipe syntax. For more information on these parts of the
|
|||
|
syntax, you can reference the
|
|||
|
":doc:`bitbake:bitbake-user-manual/bitbake-user-manual-metadata`" chapter
|
|||
|
in the BitBake User Manual.
|
|||
|
|
|||
|
- *Line Continuation (\\):* Use the backward slash (``\``) character to
|
|||
|
split a statement over multiple lines. Place the slash character at
|
|||
|
the end of the line that is to be continued on the next line::
|
|||
|
|
|||
|
VAR = "A really long \
|
|||
|
line"
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
You cannot have any characters including spaces or tabs after the
|
|||
|
slash character.
|
|||
|
|
|||
|
- *Using Variables (${VARNAME}):* Use the ``${VARNAME}`` syntax to
|
|||
|
access the contents of a variable::
|
|||
|
|
|||
|
SRC_URI = "${SOURCEFORGE_MIRROR}/libpng/zlib-${PV}.tar.gz"
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
It is important to understand that the value of a variable
|
|||
|
expressed in this form does not get substituted automatically. The
|
|||
|
expansion of these expressions happens on-demand later (e.g.
|
|||
|
usually when a function that makes reference to the variable
|
|||
|
executes). This behavior ensures that the values are most
|
|||
|
appropriate for the context in which they are finally used. On the
|
|||
|
rare occasion that you do need the variable expression to be
|
|||
|
expanded immediately, you can use the
|
|||
|
:=
|
|||
|
operator instead of
|
|||
|
=
|
|||
|
when you make the assignment, but this is not generally needed.
|
|||
|
|
|||
|
- *Quote All Assignments ("value"):* Use double quotes around values in
|
|||
|
all variable assignments (e.g. ``"value"``). Following is an example::
|
|||
|
|
|||
|
VAR1 = "${OTHERVAR}"
|
|||
|
VAR2 = "The version is ${PV}"
|
|||
|
|
|||
|
- *Conditional Assignment (?=):* Conditional assignment is used to
|
|||
|
assign a value to a variable, but only when the variable is currently
|
|||
|
unset. Use the question mark followed by the equal sign (``?=``) to
|
|||
|
make a "soft" assignment used for conditional assignment. Typically,
|
|||
|
"soft" assignments are used in the ``local.conf`` file for variables
|
|||
|
that are allowed to come through from the external environment.
|
|||
|
|
|||
|
Here is an example where ``VAR1`` is set to "New value" if it is
|
|||
|
currently empty. However, if ``VAR1`` has already been set, it
|
|||
|
remains unchanged::
|
|||
|
|
|||
|
VAR1 ?= "New value"
|
|||
|
|
|||
|
In this next example, ``VAR1`` is left with the value "Original value"::
|
|||
|
|
|||
|
VAR1 = "Original value"
|
|||
|
VAR1 ?= "New value"
|
|||
|
|
|||
|
- *Appending (+=):* Use the plus character followed by the equals sign
|
|||
|
(``+=``) to append values to existing variables.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
This operator adds a space between the existing content of the
|
|||
|
variable and the new content.
|
|||
|
|
|||
|
Here is an example::
|
|||
|
|
|||
|
SRC_URI += "file://fix-makefile.patch"
|
|||
|
|
|||
|
- *Prepending (=+):* Use the equals sign followed by the plus character
|
|||
|
(``=+``) to prepend values to existing variables.
|
|||
|
|
|||
|
.. note::
|
|||
|
|
|||
|
This operator adds a space between the new content and the
|
|||
|
existing content of the variable.
|
|||
|
|
|||
|
Here is an example::
|
|||
|
|
|||
|
VAR =+ "Starts"
|
|||
|
|
|||
|
- *Appending (:append):* Use the ``:append`` operator to append values
|
|||
|
to existing variables. This operator does not add any additional
|
|||
|
space. Also, the operator is applied after all the ``+=``, and ``=+``
|
|||
|
operators have been applied and after all ``=`` assignments have
|
|||
|
occurred. This means that if ``:append`` is used in a recipe, it can
|
|||
|
only be overridden by another layer using the special ``:remove``
|
|||
|
operator, which in turn will prevent further layers from adding it back.
|
|||
|
|
|||
|
The following example shows the space being explicitly added to the
|
|||
|
start to ensure the appended value is not merged with the existing
|
|||
|
value::
|
|||
|
|
|||
|
CFLAGS:append = " --enable-important-feature"
|
|||
|
|
|||
|
You can also use
|
|||
|
the ``:append`` operator with overrides, which results in the actions
|
|||
|
only being performed for the specified target or machine::
|
|||
|
|
|||
|
CFLAGS:append:sh4 = " --enable-important-sh4-specific-feature"
|
|||
|
|
|||
|
- *Prepending (:prepend):* Use the ``:prepend`` operator to prepend
|
|||
|
values to existing variables. This operator does not add any
|
|||
|
additional space. Also, the operator is applied after all the ``+=``,
|
|||
|
and ``=+`` operators have been applied and after all ``=``
|
|||
|
assignments have occurred.
|
|||
|
|
|||
|
The following example shows the space being explicitly added to the
|
|||
|
end to ensure the prepended value is not merged with the existing
|
|||
|
value::
|
|||
|
|
|||
|
CFLAGS:prepend = "-I${S}/myincludes "
|
|||
|
|
|||
|
You can also use the
|
|||
|
``:prepend`` operator with overrides, which results in the actions
|
|||
|
only being performed for the specified target or machine::
|
|||
|
|
|||
|
CFLAGS:prepend:sh4 = "-I${S}/myincludes "
|
|||
|
|
|||
|
- *Overrides:* You can use overrides to set a value conditionally,
|
|||
|
typically based on how the recipe is being built. For example, to set
|
|||
|
the :term:`KBRANCH` variable's
|
|||
|
value to "standard/base" for any target
|
|||
|
:term:`MACHINE`, except for
|
|||
|
qemuarm where it should be set to "standard/arm-versatile-926ejs",
|
|||
|
you would do the following::
|
|||
|
|
|||
|
KBRANCH = "standard/base"
|
|||
|
KBRANCH:qemuarm = "standard/arm-versatile-926ejs"
|
|||
|
|
|||
|
Overrides are also used to separate
|
|||
|
alternate values of a variable in other situations. For example, when
|
|||
|
setting variables such as
|
|||
|
:term:`FILES` and
|
|||
|
:term:`RDEPENDS` that are
|
|||
|
specific to individual packages produced by a recipe, you should
|
|||
|
always use an override that specifies the name of the package.
|
|||
|
|
|||
|
- *Indentation:* Use spaces for indentation rather than tabs. For
|
|||
|
shell functions, both currently work. However, it is a policy
|
|||
|
decision of the Yocto Project to use tabs in shell functions. Realize
|
|||
|
that some layers have a policy to use spaces for all indentation.
|
|||
|
|
|||
|
- *Using Python for Complex Operations:* For more advanced processing,
|
|||
|
it is possible to use Python code during variable assignments (e.g.
|
|||
|
search and replacement on a variable).
|
|||
|
|
|||
|
You indicate Python code using the ``${@python_code}`` syntax for the
|
|||
|
variable assignment::
|
|||
|
|
|||
|
SRC_URI = "ftp://ftp.info-zip.org/pub/infozip/src/zip${@d.getVar('PV',1).replace('.', '')}.tgz
|
|||
|
|
|||
|
- *Shell Function Syntax:* Write shell functions as if you were writing
|
|||
|
a shell script when you describe a list of actions to take. You
|
|||
|
should ensure that your script works with a generic ``sh`` and that
|
|||
|
it does not require any ``bash`` or other shell-specific
|
|||
|
functionality. The same considerations apply to various system
|
|||
|
utilities (e.g. ``sed``, ``grep``, ``awk``, and so forth) that you
|
|||
|
might wish to use. If in doubt, you should check with multiple
|
|||
|
implementations --- including those from BusyBox.
|
|||
|
|