540 lines
23 KiB
ReStructuredText
540 lines
23 KiB
ReStructuredText
.. 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. Following 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}"
|
|
|
|
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.
|
|
|
|
- spdx files can 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/<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/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"
|
|
|