Contribution guide
==================
The Bob Build Tool and the Basement project are open-source, community-based
projects. Contributions are very welcome. The following sections should give
some guidance how to create new recipes or improve existing ones.
Before you start
----------------
Please read the following chapters about the recipe style. Adhering to the
guidelines helps to make the process as frictionless as possible.
The YAML files are checked automatically on Github for some common style
errors. This is done with the help of `pre-commit `_.
You can either install pre-commit for the repository by running ``pre-commit
install`` or run it manually before committing via ``pre-commit run`` on all
modified files.
Anatomy of a recipe
-------------------
The general structure of a recipe building some C/C++ code looks like the
following::
inherit: [autotools]
depends:
- libs::pcre-lib-1-dev
- use: []
depends:
- libs::pcre-lib-1-tgt
metaEnvironment:
PKG_VERSION: "3.11"
PKG_LICENSE: "GPL-3.0-or-later"
checkoutSCM:
scm: url
url: ${GNU_MIRROR}/grep/grep-${PKG_VERSION}.tar.xz
digestSHA1: "955146a0a4887eca33606e391481bbef37055b86"
stripComponents: 1
buildScript: |
autotoolsBuild $1 \
--without-included-regex
packageScript: |
autotoolsPackageTgt
provideDeps: [ "*-tgt" ]
1. Any classes that are inherited are named at the top of the recipe. Only
include classes that are actually needed.
2. Usually, recipes depend on other recipes because the package needs other
libraries to work. They are named in the
:external:ref:`configuration-recipes-depends` section. Notice that each
dependency is usually listed twice: the build time library dependency
(``-dev``) that has the headers and the static or dynamic libraries. The
same dependencies are again listed as runtime dependency. These packages end
with the ``-tgt`` suffix by convention.
3. The :external:ref:`configuration-recipes-metaenv` variables describe the
package. See :ref:`contrib-meta-vars` for more details.
4. The :external:ref:`configuration-recipes-scm` part fetches the source code.
Always make sure that the checkout is determinisitc. This can be a hash sum
for tarballs like the example above or a git commit id. If tarballs or other
archives are available, they are very much preferred. Only use git clones or
other "real" SCMs if release tarballs are not available.
5. The build script does the actual job of building the package. In case of
standard build systems, this should only be a couple of lines, passing
necessary configuration options to the standard build system wrappers.
6. In the ``packageScript`` the desired output is fetched from the build tree
of the package.
7. As a last step, all runtime dependencies are passed downstream by the
:external:ref:`configuration-recipes-providedeps` property.
This pattern is the basis for almost all recipes. Some sections might not be
necessary while others need additional things. See the following sections for
more information about the various package types.
C / C++ libraries
~~~~~~~~~~~~~~~~~
.. TODO: Multiple packages with different licenses - USe PKG_LICENSE inside of
multiPackage
Libraries with applications
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Recipe style guide
------------------
There are a couple of general coding style rules:
* Indent by 4 spaces
* Lines should break after 80 characters. The hard line length limit is 120
characters.
* ...
.. _contrib-meta-vars:
Standard meta variables
~~~~~~~~~~~~~~~~~~~~~~~
Meta variables, like the name suggests, hold meta information like the version
or license about the recipe. So far, the following standard variables have been
defined:
``PKG_VERSION``
The version of the package that is built. Must be present when the recipe
downloads a source code package. The version number should be exactly like
the upstream package declared it. For packages that do not have an exact
version number, like untagged git commits, a sensible version string should
still be used e.g., ``v0.25.0-4-gee29e75c``.
``PKG_LICENSE``
The license of the package as `SPDX License Identifier
`_. Must be present when the recipe downloads a
source code package. In the best case, a single identifier applies.
Sometimes, a more complicated license expression (e.g. ``GPL-2.0-only OR
BSD-3-Clause``) is required. See the SPDX specification for details how
licenses are expressed.
Declaring configuration variables
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Configuration variables of a recipe are used to parametrize the build of the
package. They are used for example to enable or disable certain features.
Such variables should be named like the base name of the recipe. For example,
the ``recipes/devel/gcc.yaml`` recipe declares multiple packages but all
configuration variables have a common ``GCC_`` prefix. Rationale: there are
usually no two recipes with the same name in different categories and we want
to keep variable names short. This naming scheme only applies to "public"
variables, though. Variables declared in ``privateEnvironment`` can be named as
needed without any restrictions.
Avoid any other prefixes like ``CONFIG_`` or ``FEATURE_``. They usually don't
add and information about the variable but make it longer.
To make configuration variables discoverable, a dedicated *config* plugin is
used by the basement project that adds an optional ``Config`` recipe key. It be
used to describe configuration variables in a machine-readable format.
Examples::
Config:
FOO_VERSION:
help: overrides the default package version
FOO_DEBUG:
type: bool
help: Enable debugging. Disabled by default.
default: False
FOO_COLOR:
type: choice
required: True
choice:
red:
help: It's red
green:
blue:
FOO_REQUIRED_VAR:
type: str # this is the default type anyway
required: True # But variable must be present
FOO_USERS:
type: int # A C/C++ integer literal
range: [1, 10]
default: 5
FOO_BASE_ADDRESS:
type: hex
prefix: True # Require "0x" prefix
range: [0x00, 0xffffffff] # The range is optional
FOO_NUM:
type: decimal
FOO_MODE:
type: octal
prefix: False # Prevent leading "0"
range: [0, 07777]
Variables declared in this way do not need to be present. You can set the
``required`` key to ``True`` to enforce the presence of the variable. Even
though variables in Bob are always string, the format can be constrained by the
``Config`` definition. The following types (``type: ...``) are available:
``str``
An arbitrary string. This is the default and does not need to be named.
``bool``
A boolean string that is either ``0`` or ``1``.
``choice``
An enumeration of allowed values. Each value can optionally have a help
string.
``int``
A C/C++ integer literal.
``hex``
A hexadecimal number. By default, a ``0x`` prefix is accepted but not
required. Set ``prefix`` to ``True`` when requiring a ``0x`` prefix.
Setting ``prefix`` to ``False`` rejects a ``0x`` prefix.
``decimal``
A decimal number. Unlike the ``int`` type, leading zeros are accepted and
do not change the interpretation.
``octal``
An octal number. By default, leading zeroes are accepted and do not change
the interpretation. Set ``prefix`` to ``True`` when requiring a leading
zero. Setting ``prefix`` to ``False`` rejects a leading zero.
All number types (``int``, ``hex``, ``decimal``, ``octal``) can optionally have
a ``range`` property::
type: int
range: [0, 100]
Optionally, a ``default`` property might set a default value if the variable is
not present.
Enforced checks:
* A ``required`` variable must be present.
* The ``bool`` type checks that the variable is either ``0`` or ``1``.
* The ``choice`` type checks that only one of the declared choices is used.
* Number types are checked that they can be parsed. The ``hex`` and ``octal``
types may have prefixes. Their presence or absence is checked depending on
the ``prefix`` setting.
* All number types can have an optional range that is checked.
Class style guide
-----------------
Regarding the functions in classes, the function name should start with the
class name. The rest of the name is using camel case. For example, for class
``foo`` might define functions ``fooBuild`` and ``fooBarBaz``.
Classes should typically have no side effect. They should just declare
functions and variables in :external:ref:`checkout/build/packageSetup
`.
Recipe naming
-------------
When creating new recipes, the respective layer must be chosen first. Almost
always, the ``basement-gnu-linux`` layer is the right one. The only reason to
put something new into the ``basement`` layer is when it is required to support
a (new) build system or standard toolchain.
New recipes should be placed next to similar other recipes. Recipes are placed
into different categories. The following list should provide some guideline to
choose the right category. It is not uncommon that multiple categories apply.
In this case, the first matching category of the following list should be used.
If in doubt, create a discussion on Github or ask on the mailing list.
``libs``
C and C++ libraries to make other programs work. Libraries are packages that
provide header files and static and/or dynamic libraries that are used by
other packages. Even if the package additionally provides some application
based on the library, the ``libs`` category should be used.
Other languages (e.g. Python) have their own category and libraries of these
languages should be placed there. On the other hand, there are sometimes
large collections of libraries that are related to each other. Such
libraries are further put into sub-categories:
``gnome``
Libraries that are coming from the Gnome project.
``xorg``
Libraries that are related to the X.Org project.
Some interpreted languages have their own category. This includes the
interpreter itself, libraries and applications written in this language.
``perl``
Everything about Perl.
``python``
Everything about Python 3. Support for Python 2 has been removed.
The other categories do not really have a preference between each other.
``bsp``
Anything with links to specific hardware or hardware configuration
information. These are for example firmware like the Arm Trusted Firmware or
boot loaders like Grub and U-Boot. On the other hand, this should not include
packages of other categories just because they have been modified for a
particular SOC. They should stay in their respective category and either
get a dedicated sub-category or a vendor suffix.
If BSP components have been modified by a SOC vendor, they should go into a
corresponding sub-category. Examples:
``imx``
NXP i.MX series BSP components.
``rpi``
RaspberryPi specific components.
``core``
Basic files and daemons that are essential to boot the system. This includes
utilities to administer system resources, manage user accounts, etc.
``db``
Database Servers and Clients.
``devel``
Development utilities, compilers, development environments, libraries, etc.
Basically anything that is required to build other software.
``editors``
Software to edit files. Programming environments.
``graphics``
Applications, utilities and files that are graphics related.
``fonts``
Fonts.
``gnome``
Applications of the GNOME desktop environment.
``wayland``
Wayland specific applications and utilities.
``xorg``
X11 specific applications and utilities.
``kernel``
Operating System Kernels and related modules.
``multimedia``
Codecs and support utilities for audio, images and video.
``net``
Daemons and clients to connect the system to the world.
``text``
Text processing applications and utilities. This includes dictionaries and
converters.
``utils``
Shells, utilities for file/disk manipulation, backup and archive tools,
system monitoring, input systems, etc. Basically any tool that does not fit
in any of the other categories.
``virtual``
Virtual packages. Inside the virtual category the sub-categories form the
same hierarchy like it would for non-virtual packages. That is, any of the
main categories can be present.