BuildElement - Abstract class for build elements
The BuildElement class is a convenience element one can derive from for implementing the most common case of element.
Built-in functionality
The BuildElement base class provides built in functionality that could be overridden by the individual plugins.
This section will give a brief summary of how some of the common features work, some of them or the variables they use will be further detailed in the following sections.
The strip-binaries variable
The strip-binaries variable is by default empty. You need to use the appropiate commands depending of the system you are building. If you are targetting Linux, ones known to work are the ones used by the freedesktop-sdk, you can take a look to them in their project.conf
Location for staging dependencies
The BuildElement supports the “location” dependency configuration, which means you can use this configuration for any BuildElement class.
The “location” configuration defines where the dependency will be staged in the build sandbox.
Example:
Here is an example of how one might stage some dependencies into an alternative location while staging some elements in the sandbox root.
# Stage these build dependencies in /opt
#
build-depends:
- baseproject.bst:opt-dependencies.bst
config:
location: /opt
# Stage these tools in "/" and require them as
# runtime dependencies.
depends:
- baseproject.bst:base-tools.bst
Note
The order of dependencies specified is not significant.
The staging locations will be sorted so that elements are staged in parent directories before subdirectories.
Location for running commands
The command-subdir
variable sets where commands will be executed,
and the directory will be created automatically if it does not exist.
The command-subdir
is a relative path from %{build-root}
, and
cannot be a parent or adjacent directory, it must expand to a subdirectory
of ${build-root}
.
Location for configuring the project
The conf-root
is the location that specific build elements can use to look for build configuration files.
This is used by elements such as autotools,
cmake,
meson,
setuptools and
pip.
The default value of conf-root
is defined by default as .
. This means that if
the conf-root
is not explicitly set to another directory, the configuration
files are expected to be found in command-subdir
.
Separating source and build directories
A typical example of using conf-root
is when performing
autotools builds
where your source directory is separate from your build directory.
This can be achieved in build elements which use conf-root
as follows:
variables:
# Specify that build configuration scripts are found in %{build-root}
conf-root: "%{build-root}"
# The build will run in the `_build` subdirectory
command-subdir: _build
Install Location
Build elements must install the build output to the directory defined by install-root
.
You need not set or change the install-root
variable as it will be defined
automatically on your behalf, and it is used to collect build output when creating
the resulting artifacts.
It is important to know about install-root
in order to write your own
custom install instructions, for example the
cmake
element will use it to specify the DESTDIR
.
Abstract method implementations
Element.configure_sandbox()
In Element.configure_sandbox()
,
the BuildElement will ensure that the sandbox locations described by the %{build-root}
and %{install-root}
variables are marked and will be mounted read-write for the
assemble phase
.
The working directory for the sandbox will be configured to be the %{build-root}
,
unless the %{command-subdir}
variable is specified for the element in question,
in which case the working directory will be configured as %{build-root}/%{command-subdir}
.
Element.stage()
In Element.stage()
, the BuildElement
will do the following operations:
Stage all of the build dependencies into the sandbox root.
Run the integration commands for all staged dependencies using
Element.integrate()
Stage any Source on the given element to the
%{build-root}
location inside the sandbox, usingElement.stage_sources()
Element.assemble()
In Element.assemble()
, the
BuildElement will proceed to run sandboxed commands which are expected to be
found in the element configuration.
Commands are run in the following order:
configure-commands
: Commands to configure the build scriptsbuild-commands
: Commands to build the elementinstall-commands
: Commands to install the results into%{install-root}
strip-commands
: Commands to strip debugging symbols installed binaries
The result of the build is expected to end up in %{install-root}
, and
as such; Element.assemble() method will return the %{install-root}
for
artifact collection purposes.
Note
In the case that the element is currently workspaced, the configure-commands
will only be run in subsequent builds until they succeed at least once, unless
bst workspace reset –soft is called on the
workspace to explicitly avoid an incremental build.
- class BuildElement(context: Context, project: Project, load_element: LoadElement, plugin_conf: str | None, *, artifact_key: str | None = None)
Bases:
Element
- configure(node)
Configure the Plugin from loaded configuration data
- Parameters:
node – The loaded configuration dictionary
- Raises:
Plugin implementors should implement this method to read configuration data and store it.
The
MappingNode.validate_keys()
method should be used to ensure that the user has not specified keys in node which are unsupported by the plugin.
- configure_dependencies(dependencies)
Configure the Element with regards to it’s build dependencies
Elements can use this method to parse custom configuration which define their relationship to their build dependencies.
If this method is implemented, then it will be called with all direct build dependencies specified in their element declaration in a list.
If the dependency was declared with custom configuration, it will be provided along with the dependency element, otherwise None will be passed with dependencies which do not have any additional configuration.
If the user has specified the same build dependency multiple times with differing configurations, then those build dependencies will be provided multiple times in the
dependencies
list.- Parameters:
dependencies (list) – A list of
DependencyConfiguration
objects- Raises:
.ElementError – When the element raises an error
The format of the
MappingNode
provided asDependencyConfiguration.config
method should be called by the implementing plugin in order to validate it.Note
It is unnecessary to implement this method if the plugin does not support any custom dependency configuration.
- preflight()
Preflight Check
- Raises:
This method is run after
Plugin.configure()
and after the pipeline is fully constructed.Implementors should simply raise
SourceError
orElementError
with an informative message in the case that the host environment is unsuitable for operation.Plugins which require host tools (only sources usually) should obtain them with
utils.get_host_tool()
which will raise an error automatically informing the user that a host tool is needed.
- get_unique_key()
Return something which uniquely identifies the plugin input
- Returns:
A string, list or dictionary which uniquely identifies the input
This is used to construct unique cache keys for elements and sources, sources should return something which uniquely identifies the payload, such as an sha256 sum of a tarball content.
Elements and Sources should implement this by collecting any configurations which could possibly affect the output and return a dictionary of these settings.
For Sources, this is guaranteed to only be called if
Source.is_resolved()
has returnedTrue
which is to say that theSource
is expected to have an exact source ref indicating exactly what source is going to be staged.Note
If your plugin is concerned with API stability, then future extensions of your plugin YAML configuration which affect the unique key returned here should be added to this key with care.
A good rule of thumb is to only compute the new value in the returned key if the value of the newly added YAML key is not equal to it’s default value.
- configure_sandbox(sandbox)
Configures the the sandbox for execution
- Parameters:
sandbox – The build sandbox
:raises (
ElementError
): When the element raises an errorElements must implement this method to configure the sandbox object for execution.
- stage(sandbox)
Stage inputs into the sandbox directories
- Parameters:
sandbox – The build sandbox
:raises (
ElementError
): When the element raises an errorElements must implement this method to populate the sandbox directory with data. This is done either by staging
Source
objects, by staging the artifacts of the elements this element depends on, or both.
- assemble(sandbox)
Assemble the output artifact
- Parameters:
sandbox – The build sandbox
- Returns:
An absolute path within the sandbox to collect the artifact from
:raises (
ElementError
): When the element raises an errorElements must implement this method to create an output artifact from its sources and dependencies.
- generate_script()
Generate a build (sh) script to build this element
- Returns:
A string containing the shell commands required to build the element
BuildStream guarantees the following environment when the generated script is run:
All element variables have been exported.
The cwd is self.get_variable(‘build-root’)/self.normal_name.
$PREFIX is set to self.get_variable(‘install-root’).
The directory indicated by $PREFIX is an empty directory.
Files are expected to be installed to $PREFIX.
If the script fails, it is expected to return with an exit code != 0.