123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- .. SPDX-License-Identifier: CC-BY-SA-2.0-UK
- Working With Licenses
- *********************
- As mentioned in the ":ref:`overview-manual/development-environment:licensing`"
- section in the Yocto Project Overview and Concepts Manual, open source
- projects are open to the public and they consequently have different
- licensing structures in place. This section describes the mechanism by
- which the :term:`OpenEmbedded Build System`
- tracks changes to
- licensing text and covers how to maintain open source license compliance
- during your project's lifecycle. The section also describes how to
- enable commercially licensed recipes, which by default are disabled.
- Tracking License Changes
- ========================
- The license of an upstream project might change in the future. In order
- to prevent these changes going unnoticed, the
- :term:`LIC_FILES_CHKSUM`
- variable tracks changes to the license text. The checksums are validated
- at the end of the configure step, and if the checksums do not match, the
- build will fail.
- Specifying the ``LIC_FILES_CHKSUM`` Variable
- --------------------------------------------
- The :term:`LIC_FILES_CHKSUM` variable contains checksums of the license text
- in the source code for the recipe. Here is an example of how to
- specify :term:`LIC_FILES_CHKSUM`::
- LIC_FILES_CHKSUM = "file://COPYING;md5=xxxx \
- file://licfile1.txt;beginline=5;endline=29;md5=yyyy \
- file://licfile2.txt;endline=50;md5=zzzz \
- ..."
- .. note::
- - When using "beginline" and "endline", realize that line numbering
- begins with one and not zero. Also, the included lines are
- inclusive (i.e. lines five through and including 29 in the
- previous example for ``licfile1.txt``).
- - When a license check fails, the selected license text is included
- as part of the QA message. Using this output, you can determine
- the exact start and finish for the needed license text.
- The build system uses the :term:`S`
- variable as the default directory when searching files listed in
- :term:`LIC_FILES_CHKSUM`. The previous example employs the default
- directory.
- Consider this next example::
- LIC_FILES_CHKSUM = "file://src/ls.c;beginline=5;endline=16;\
- md5=bb14ed3c4cda583abc85401304b5cd4e"
- LIC_FILES_CHKSUM = "file://${WORKDIR}/license.html;md5=5c94767cedb5d6987c902ac850ded2c6"
- The first line locates a file in ``${S}/src/ls.c`` and isolates lines
- five through 16 as license text. The second line refers to a file in
- :term:`WORKDIR`.
- Note that :term:`LIC_FILES_CHKSUM` variable is mandatory for all recipes,
- unless the :term:`LICENSE` variable is set to "CLOSED".
- Explanation of Syntax
- ---------------------
- As mentioned in the previous section, the :term:`LIC_FILES_CHKSUM` variable
- lists all the important files that contain the license text for the
- source code. It is possible to specify a checksum for an entire file, or
- a specific section of a file (specified by beginning and ending line
- numbers with the "beginline" and "endline" parameters, respectively).
- The latter is useful for source files with a license notice header,
- README documents, and so forth. If you do not use the "beginline"
- parameter, then it is assumed that the text begins on the first line of
- the file. Similarly, if you do not use the "endline" parameter, it is
- assumed that the license text ends with the last line of the file.
- The "md5" parameter stores the md5 checksum of the license text. If the
- license text changes in any way as compared to this parameter then a
- mismatch occurs. This mismatch triggers a build failure and notifies the
- developer. Notification allows the developer to review and address the
- license text changes. Also note that if a mismatch occurs during the
- build, the correct md5 checksum is placed in the build log and can be
- easily copied to the recipe.
- There is no limit to how many files you can specify using the
- :term:`LIC_FILES_CHKSUM` variable. Generally, however, every project
- requires a few specifications for license tracking. Many projects have a
- "COPYING" file that stores the license information for all the source
- code files. This practice allows you to just track the "COPYING" file as
- long as it is kept up to date.
- .. note::
- - If you specify an empty or invalid "md5" parameter,
- :term:`BitBake` returns an md5
- mis-match error and displays the correct "md5" parameter value
- during the build. The correct parameter is also captured in the
- build log.
- - If the whole file contains only license text, you do not need to
- use the "beginline" and "endline" parameters.
- Enabling Commercially Licensed Recipes
- ======================================
- By default, the OpenEmbedded build system disables components that have
- commercial or other special licensing requirements. Such requirements
- are defined on a recipe-by-recipe basis through the
- :term:`LICENSE_FLAGS` variable
- definition in the affected recipe. For instance, the
- ``poky/meta/recipes-multimedia/gstreamer/gst-plugins-ugly`` recipe
- contains the following statement::
- LICENSE_FLAGS = "commercial"
- Here is a
- slightly more complicated example that contains both an explicit recipe
- name and version (after variable expansion)::
- LICENSE_FLAGS = "license_${PN}_${PV}"
- It is possible to give more details about a specific license
- using flags on the :term:`LICENSE_FLAGS_DETAILS` variable::
- LICENSE_FLAGS_DETAILS[my-eula-license] = "For further details, see https://example.com/eula."
- If set, this will be displayed to the user if the license hasn't been accepted.
- In order for a component restricted by a
- :term:`LICENSE_FLAGS` definition to be enabled and included in an image, it
- needs to have a matching entry in the global
- :term:`LICENSE_FLAGS_ACCEPTED`
- variable, which is a variable typically defined in your ``local.conf``
- file. For example, to enable the
- ``poky/meta/recipes-multimedia/gstreamer/gst-plugins-ugly`` package, you
- could add either the string "commercial_gst-plugins-ugly" or the more
- general string "commercial" to :term:`LICENSE_FLAGS_ACCEPTED`. See the
- ":ref:`dev-manual/licenses:license flag matching`" section for a full
- explanation of how :term:`LICENSE_FLAGS` matching works. Here is the
- example::
- LICENSE_FLAGS_ACCEPTED = "commercial_gst-plugins-ugly"
- Likewise, to additionally enable the package built from the recipe
- containing ``LICENSE_FLAGS = "license_${PN}_${PV}"``, and assuming that
- the actual recipe name was ``emgd_1.10.bb``, the following string would
- enable that package as well as the original ``gst-plugins-ugly``
- package::
- LICENSE_FLAGS_ACCEPTED = "commercial_gst-plugins-ugly license_emgd_1.10"
- As a convenience, you do not need to specify the
- complete license string for every package. You can use
- an abbreviated form, which consists of just the first portion or
- portions of the license string before the initial underscore character
- or characters. A partial string will match any license that contains the
- given string as the first portion of its license. For example, the
- following value will also match both of the packages
- previously mentioned as well as any other packages that have licenses
- starting with "commercial" or "license"::
- LICENSE_FLAGS_ACCEPTED = "commercial license"
- License Flag Matching
- ---------------------
- License flag matching allows you to control what recipes the
- OpenEmbedded build system includes in the build. Fundamentally, the
- build system attempts to match :term:`LICENSE_FLAGS` strings found in
- recipes against strings found in :term:`LICENSE_FLAGS_ACCEPTED`.
- A match causes the build system to include a recipe in the
- build, while failure to find a match causes the build system to exclude
- a recipe.
- In general, license flag matching is simple. However, understanding some
- concepts will help you correctly and effectively use matching.
- Before a flag defined by a particular recipe is tested against the
- entries of :term:`LICENSE_FLAGS_ACCEPTED`, the expanded
- string ``_${PN}`` is appended to the flag. This expansion makes each
- :term:`LICENSE_FLAGS` value recipe-specific. After expansion, the
- string is then matched against the entries. Thus, specifying
- ``LICENSE_FLAGS = "commercial"`` in recipe "foo", for example, results
- in the string ``"commercial_foo"``. And, to create a match, that string
- must appear among the entries of :term:`LICENSE_FLAGS_ACCEPTED`.
- Judicious use of the :term:`LICENSE_FLAGS` strings and the contents of the
- :term:`LICENSE_FLAGS_ACCEPTED` variable allows you a lot of flexibility for
- including or excluding recipes based on licensing. For example, you can
- broaden the matching capabilities by using license flags string subsets
- in :term:`LICENSE_FLAGS_ACCEPTED`.
- .. note::
- When using a string subset, be sure to use the part of the expanded
- string that precedes the appended underscore character (e.g.
- ``usethispart_1.3``, ``usethispart_1.4``, and so forth).
- For example, simply specifying the string "commercial" in the
- :term:`LICENSE_FLAGS_ACCEPTED` variable matches any expanded
- :term:`LICENSE_FLAGS` definition that starts with the string
- "commercial" such as "commercial_foo" and "commercial_bar", which
- are the strings the build system automatically generates for
- hypothetical recipes named "foo" and "bar" assuming those recipes simply
- specify the following::
- LICENSE_FLAGS = "commercial"
- Thus, you can choose to exhaustively enumerate each license flag in the
- list and allow only specific recipes into the image, or you can use a
- string subset that causes a broader range of matches to allow a range of
- recipes into the image.
- This scheme works even if the :term:`LICENSE_FLAGS` string already has
- ``_${PN}`` appended. For example, the build system turns the license
- flag "commercial_1.2_foo" into "commercial_1.2_foo_foo" and would match
- both the general "commercial" and the specific "commercial_1.2_foo"
- strings found in the :term:`LICENSE_FLAGS_ACCEPTED` variable, as expected.
- Here are some other scenarios:
- - You can specify a versioned string in the recipe such as
- "commercial_foo_1.2" in a "foo" recipe. The build system expands this
- string to "commercial_foo_1.2_foo". Combine this license flag with a
- :term:`LICENSE_FLAGS_ACCEPTED` variable that has the string
- "commercial" and you match the flag along with any other flag that
- starts with the string "commercial".
- - Under the same circumstances, you can add "commercial_foo" in the
- :term:`LICENSE_FLAGS_ACCEPTED` variable and the build system not only
- matches "commercial_foo_1.2" but also matches any license flag with
- the string "commercial_foo", regardless of the version.
- - You can be very specific and use both the package and version parts
- in the :term:`LICENSE_FLAGS_ACCEPTED` list (e.g.
- "commercial_foo_1.2") to specifically match a versioned recipe.
- Other Variables Related to Commercial Licenses
- ----------------------------------------------
- There are other helpful variables related to commercial license handling,
- defined in the
- ``poky/meta/conf/distro/include/default-distrovars.inc`` file::
- COMMERCIAL_AUDIO_PLUGINS ?= ""
- COMMERCIAL_VIDEO_PLUGINS ?= ""
- If you want to enable these components, you can do so by making sure you have
- statements similar to the following in your ``local.conf`` configuration file::
- COMMERCIAL_AUDIO_PLUGINS = "gst-plugins-ugly-mad \
- gst-plugins-ugly-mpegaudioparse"
- COMMERCIAL_VIDEO_PLUGINS = "gst-plugins-ugly-mpeg2dec \
- gst-plugins-ugly-mpegstream gst-plugins-bad-mpegvideoparse"
- LICENSE_FLAGS_ACCEPTED = "commercial_gst-plugins-ugly commercial_gst-plugins-bad commercial_qmmp"
- Of course, you could also create a matching list for those components using the
- more general "commercial" string in the :term:`LICENSE_FLAGS_ACCEPTED` variable,
- but that would also enable all the other packages with :term:`LICENSE_FLAGS`
- containing "commercial", which you may or may not want::
- LICENSE_FLAGS_ACCEPTED = "commercial"
- Specifying audio and video plugins as part of the
- :term:`COMMERCIAL_AUDIO_PLUGINS` and :term:`COMMERCIAL_VIDEO_PLUGINS` statements
- (along with :term:`LICENSE_FLAGS_ACCEPTED`) includes the plugins or
- components into built images, thus adding support for media formats or
- components.
- .. note::
- GStreamer "ugly" and "bad" plugins are actually available through
- open source licenses. However, the "ugly" ones can be subject to software
- patents in some countries, making it necessary to pay licensing fees
- to distribute them. The "bad" ones are just deemed unreliable by the
- GStreamer community and should therefore be used with care.
- Maintaining Open Source License Compliance During Your Product's Lifecycle
- ==========================================================================
- One of the concerns for a development organization using open source
- software is how to maintain compliance with various open source
- licensing during the lifecycle of the product. While this section does
- not provide legal advice or comprehensively cover all scenarios, it does
- present methods that you can use to assist you in meeting the compliance
- requirements during a software release.
- With hundreds of different open source licenses that the Yocto Project
- tracks, it is difficult to know the requirements of each and every
- license. However, the requirements of the major FLOSS licenses can begin
- to be covered by assuming that there are three main areas of concern:
- - Source code must be provided.
- - License text for the software must be provided.
- - Compilation scripts and modifications to the source code must be
- provided.
- There are other requirements beyond the scope of these three and the
- methods described in this section (e.g. the mechanism through which
- source code is distributed).
- As different organizations have different ways of releasing software,
- there can be multiple ways of meeting license obligations. At
- least, we describe here two methods for achieving compliance:
- - The first method is to use OpenEmbedded's ability to provide
- the source code, provide a list of licenses, as well as
- compilation scripts and source code modifications.
- The remainder of this section describes supported methods to meet
- the previously mentioned three requirements.
- - The second method is to generate a *Software Bill of Materials*
- (:term:`SBoM`), as described in the ":doc:`/dev-manual/sbom`" section.
- Not only do you generate :term:`SPDX` output which can be used meet
- license compliance requirements (except for sharing the build system
- and layers sources for the time being), but this output also includes
- component version and patch information which can be used
- for vulnerability assessment.
- Whatever method you choose, prior to releasing images, sources,
- and the build system, you should audit all artifacts to ensure
- completeness.
- .. note::
- The Yocto Project generates a license manifest during image creation
- that is located in
- ``${DEPLOY_DIR}/licenses/${SSTATE_PKGARCH}/<image-name>-<machine>.rootfs-<datestamp>/``
- to assist with any audits.
- Providing the Source Code
- -------------------------
- Compliance activities should begin before you generate the final image.
- The first thing you should look at is the requirement that tops the list
- for most compliance groups --- providing the source. The Yocto Project has
- a few ways of meeting this requirement.
- One of the easiest ways to meet this requirement is to provide the
- entire :term:`DL_DIR` used by the
- build. This method, however, has a few issues. The most obvious is the
- size of the directory since it includes all sources used in the build
- and not just the source used in the released image. It will include
- toolchain source, and other artifacts, which you would not generally
- release. However, the more serious issue for most companies is
- accidental release of proprietary software. The Yocto Project provides
- an :ref:`ref-classes-archiver` class to help avoid some of these concerns.
- Before you employ :term:`DL_DIR` or the :ref:`ref-classes-archiver` class, you
- need to decide how you choose to provide source. The source
- :ref:`ref-classes-archiver` class can generate tarballs and SRPMs and can
- create them with various levels of compliance in mind.
- One way of doing this (but certainly not the only way) is to release
- just the source as a tarball. You can do this by adding the following to
- the ``local.conf`` file found in the :term:`Build Directory`::
- INHERIT += "archiver"
- ARCHIVER_MODE[src] = "original"
- During the creation of your
- image, the source from all recipes that deploy packages to the image is
- placed within subdirectories of ``DEPLOY_DIR/sources`` based on the
- :term:`LICENSE` for each recipe.
- Releasing the entire directory enables you to comply with requirements
- concerning providing the unmodified source. It is important to note that
- the size of the directory can get large.
- A way to help mitigate the size issue is to only release tarballs for
- licenses that require the release of source. Let us assume you are only
- concerned with GPL code as identified by running the following script:
- .. code-block:: shell
- # Script to archive a subset of packages matching specific license(s)
- # Source and license files are copied into sub folders of package folder
- # Must be run from build folder
- #!/bin/bash
- src_release_dir="source-release"
- mkdir -p $src_release_dir
- for a in tmp/deploy/sources/*; do
- for d in $a/*; do
- # Get package name from path
- p=`basename $d`
- p=${p%-*}
- p=${p%-*}
- # Only archive GPL packages (update *GPL* regex for your license check)
- numfiles=`ls tmp/deploy/licenses/$p/*GPL* 2> /dev/null | wc -l`
- if [ $numfiles -ge 1 ]; then
- echo Archiving $p
- mkdir -p $src_release_dir/$p/source
- cp $d/* $src_release_dir/$p/source 2> /dev/null
- mkdir -p $src_release_dir/$p/license
- cp tmp/deploy/licenses/$p/* $src_release_dir/$p/license 2> /dev/null
- fi
- done
- done
- At this point, you
- could create a tarball from the ``gpl_source_release`` directory and
- provide that to the end user. This method would be a step toward
- achieving compliance with section 3a of GPLv2 and with section 6 of
- GPLv3.
- Providing License Text
- ----------------------
- One requirement that is often overlooked is inclusion of license text.
- This requirement also needs to be dealt with prior to generating the
- final image. Some licenses require the license text to accompany the
- binary. You can achieve this by adding the following to your
- ``local.conf`` file::
- COPY_LIC_MANIFEST = "1"
- COPY_LIC_DIRS = "1"
- LICENSE_CREATE_PACKAGE = "1"
- Adding these statements to the
- configuration file ensures that the licenses collected during package
- generation are included on your image.
- .. note::
- Setting all three variables to "1" results in the image having two
- copies of the same license file. One copy resides in
- ``/usr/share/common-licenses`` and the other resides in
- ``/usr/share/license``.
- The reason for this behavior is because
- :term:`COPY_LIC_DIRS` and
- :term:`COPY_LIC_MANIFEST`
- add a copy of the license when the image is built but do not offer a
- path for adding licenses for newly installed packages to an image.
- :term:`LICENSE_CREATE_PACKAGE`
- adds a separate package and an upgrade path for adding licenses to an
- image.
- As the source :ref:`ref-classes-archiver` class has already archived the
- original unmodified source that contains the license files, you would have
- already met the requirements for inclusion of the license information
- with source as defined by the GPL and other open source licenses.
- Providing Compilation Scripts and Source Code Modifications
- -----------------------------------------------------------
- At this point, we have addressed all we need prior to generating the
- image. The next two requirements are addressed during the final
- packaging of the release.
- By releasing the version of the OpenEmbedded build system and the layers
- used during the build, you will be providing both compilation scripts
- and the source code modifications in one step.
- If the deployment team has a :ref:`overview-manual/concepts:bsp layer`
- and a distro layer, and those
- those layers are used to patch, compile, package, or modify (in any way)
- any open source software included in your released images, you might be
- required to release those layers under section 3 of GPLv2 or section 1
- of GPLv3. One way of doing that is with a clean checkout of the version
- of the Yocto Project and layers used during your build. Here is an
- example:
- .. code-block:: shell
- # We built using the dunfell branch of the poky repo
- $ git clone -b dunfell git://git.yoctoproject.org/poky
- $ cd poky
- # We built using the release_branch for our layers
- $ git clone -b release_branch git://git.mycompany.com/meta-my-bsp-layer
- $ git clone -b release_branch git://git.mycompany.com/meta-my-software-layer
- # clean up the .git repos
- $ find . -name ".git" -type d -exec rm -rf {} \;
- One thing a development organization might want to consider for end-user
- convenience is to modify
- ``meta-poky/conf/templates/default/bblayers.conf.sample`` to ensure that when
- the end user utilizes the released build system to build an image, the
- development organization's layers are included in the ``bblayers.conf`` file
- automatically::
- # POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
- # changes incompatibly
- POKY_BBLAYERS_CONF_VERSION = "2"
- BBPATH = "${TOPDIR}"
- BBFILES ?= ""
- BBLAYERS ?= " \
- ##OEROOT##/meta \
- ##OEROOT##/meta-poky \
- ##OEROOT##/meta-yocto-bsp \
- ##OEROOT##/meta-mylayer \
- "
- Creating and
- providing an archive of the :term:`Metadata`
- layers (recipes, configuration files, and so forth) enables you to meet
- your requirements to include the scripts to control compilation as well
- as any modifications to the original source.
- Compliance Limitations with Executables Built from Static Libraries
- -------------------------------------------------------------------
- When package A is added to an image via the :term:`RDEPENDS` or :term:`RRECOMMENDS`
- mechanisms as well as explicitly included in the image recipe with
- :term:`IMAGE_INSTALL`, and depends on a static linked library recipe B
- (``DEPENDS += "B"``), package B will neither appear in the generated license
- manifest nor in the generated source tarballs. This occurs as the
- :ref:`ref-classes-license` and :ref:`ref-classes-archiver` classes assume that
- only packages included via :term:`RDEPENDS` or :term:`RRECOMMENDS`
- end up in the image.
- As a result, potential obligations regarding license compliance for package B
- may not be met.
- The Yocto Project doesn't enable static libraries by default, in part because
- of this issue. Before a solution to this limitation is found, you need to
- keep in mind that if your root filesystem is built from static libraries,
- you will need to manually ensure that your deliveries are compliant
- with the licenses of these libraries.
- Copying Non Standard Licenses
- =============================
- Some packages, such as the linux-firmware package, have many licenses
- that are not in any way common. You can avoid adding a lot of these
- types of common license files, which are only applicable to a specific
- package, by using the
- :term:`NO_GENERIC_LICENSE`
- variable. Using this variable also avoids QA errors when you use a
- non-common, non-CLOSED license in a recipe.
- Here is an example that uses the ``LICENSE.Abilis.txt`` file as
- the license from the fetched source::
- NO_GENERIC_LICENSE[Firmware-Abilis] = "LICENSE.Abilis.txt"
|