5. Optionality and directives
In this chapter we’re going to go over some of the more flexible constructs which BuildStream offers for optionality, and show how we can use directives in the BuildStream YAML format.
Note
This example is distributed with BuildStream in the doc/examples/directives subdirectory.
5.1. Overview
This chapter’s example will build another hello.c
program which much
resembles the program in the running commands example,
but here we’re going to make the greeting string configurable using the C
preprocessor.
We’ll be compiling the following C file:
5.1.1. files/src/hello.c
/*
* hello.c - Simple hello world program
*/
#include <stdio.h>
int main(int argc, char *argv[])
{
printf(GREETING_MESSAGE);
return 0;
}
And we’re going to build it using make
, using the following Makefile:
5.1.2. files/src/Makefile
# Sample makefile for hello.c
#
.PHONY: all install
all: hello
install:
install -d ${DESTDIR}${PREFIX}/bin
install -m 755 hello ${DESTDIR}${PREFIX}/bin
hello: hello.c
$(CC) -DGREETING_MESSAGE="\"${GREETING}\"" -Wall -o $@ $<
Notice the addition of -DGREETING_MESSAGE="\"${GREETING}\""
in the above
Makefile, this will allow us to configure the greeting message from the
hello.bst
element declaration.
We will need to add support to our project for optionality, and we’ll have to make conditional statements to resolve what kind of greeting we want from the hello world program.
5.2. Project structure
Since this project has much the same structure as the
running commands chapter did, we won’t go over all of
these elements in detail. Instead let’s focus on the addition of the new
project options in project.conf
, the added
file in the include/
project subdirectory, and how these come together
in the the hello.bst
element.
5.2.1. project.conf
# Unique project name
name: directives
# Minimum required BuildStream version
min-version: 2.0
# Subdirectory where elements are stored
element-path: elements
# Define an alias for our alpine tarball
aliases:
alpine: https://bst-integration-test-images.ams3.cdn.digitaloceanspaces.com/
# Define an option for this project
#
options:
flavor:
type: enum
description: Flavor of the greeting in the hello world program
values:
- normal
- somber
- excited
default: normal
Here, our project.conf
declares a project option called flavor
, and this
will inform what kind of greeting message we want to use when building the project.
5.2.2. elements/hello.bst
kind: manual
description: |
A hello world program with a custom greeting message
# Depend on the base system
depends:
- base.bst
# Stage the files/src directory for building
sources:
- kind: local
path: files/src
# This include file defines the %{greeting} variable used below
variables:
(@): include/greeting.bst
# Now configure the commands to run
config:
# This time we inform the Makefile of which greeting we want
build-commands:
- make PREFIX="%{prefix}" GREETING="%{greeting}"
install-commands:
- make -j1 PREFIX="%{prefix}" DESTDIR="%{install-root}" install
Notice the (@)
symbol we’ve added in the variables:
section, this
symbol is used to invoke the include directive,
which can be useful for code sharing between elements or simply to improve readability.
In this case, we are compositing the content of include/greeting.bst
into the
variables section of the element declaration, directives
can however be used virtually anywhere in the BuildStream YAML format.
5.2.3. include/greeting.bst
# We define the greeting message here conditionally
(?):
- flavor == "normal":
greeting: |
Hello world !
- flavor == "somber":
greeting: |
Hey world.
- flavor == "excited":
greeting: |
Howdy there, and what a world it is !
Here we can see the dictionary which will be composited into the variables:
section of the hello.bst
element described above.
Note the usage of the (?)
symbol at the toplevel of the YAML dictionary,
this is how we perform conditional statements
in the BuildStream YAML format.
This include file uses the flavor
project option we declared in project.conf
to
decide what value will end up being assigned to the %{greeting}
variable, which
will ultimately be used in the hello.bst
element.
5.3. Using the project
Now that we have a project which uses options and conditional statements, lets build the project with a few different options and observe the outputs.
5.3.1. Building hello.bst element with options
Since the flavor option we’ve declared above has a default, we can build it the first time using bst build without any special command line options:
user@host:~/directives$ bst build hello.bst
[--:--:--][ ][ main:core activity ] START Build
[--:--:--][ ][ main:core activity ] START Loading elements
[00:00:00][ ][ main:core activity ] SUCCESS Loading elements
[--:--:--][ ][ main:core activity ] START Resolving elements
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1728020715.409070 2023 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache
[00:00:00][ ][ main:core activity ] SUCCESS Resolving elements
[--:--:--][ ][ main:core activity ] START Initializing remote caches
[00:00:00][ ][ main:core activity ] SUCCESS Initializing remote caches
[--:--:--][ ][ main:core activity ] START Query cache
[00:00:00][ ][ main:core activity ] SUCCESS Query cache
BuildStream Version 2.3.0+13.g0edf2dc8a
Session Start: Friday, 04-10-2024 at 05:45:15
Project: directives (/home/user/buildstream/doc/examples/directives)
Targets: hello.bst
User Configuration
Configuration File: /home/user/buildstream/doc/run-bst-wywe3x_l/buildstream.conf
Cache Directory: /home/user/buildstream/doc/run-bst-wywe3x_l
Log Files: /home/user/buildstream/doc/run-bst-wywe3x_l/logs
Source Mirrors: /home/user/buildstream/doc/run-bst-wywe3x_l/sources
Build Area: /home/user/buildstream/doc/run-bst-wywe3x_l/build
Strict Build Plan: Yes
Maximum Fetch Tasks: 10
Maximum Build Tasks: 4
Maximum Push Tasks: 4
Maximum Network Retries: 2
Project: directives
Project Options
flavor: normal
Element Plugins
manual: core plugin
stack: core plugin
import: core plugin
Source Plugins
local: core plugin
tar: core plugin
Pipeline
fetch needed 4275015f95b90fd68b24421a9586814f97cc03630ce28d0b9fe35435bfe08ca5 base/alpine.bst
waiting 2284353672b080d3b1f19eacc625c0b6449109676abd0144328ca2521dabc977 base.bst
waiting 49a52215c02358a4bbbb632a74986fa23dc31a36ee8055feffbddc9e3c735d1a hello.bst
===============================================================================
[--:--:--][4275015f][ fetch:base/alpine.bst ] START directives/base-alpine/4275015f-fetch.20241004-054515.log
[--:--:--][22843536][ fetch:base.bst ] START directives/base/22843536-fetch.20241004-054515.log
[--:--:--][4275015f][ fetch:base/alpine.bst ] START Fetching https://bst-integration-test-images.ams3.cdn.digitaloceanspaces.com/integration-tests-base.v1.x86_64.tar.xz
[00:00:00][22843536][ fetch:base.bst ] SUCCESS directives/base/22843536-fetch.20241004-054515.log
[00:00:00][4275015f][ fetch:base/alpine.bst ] SUCCESS Fetching https://bst-integration-test-images.ams3.cdn.digitaloceanspaces.com/integration-tests-base.v1.x86_64.tar.xz
[00:00:06][4275015f][ fetch:base/alpine.bst ] SUCCESS directives/base-alpine/4275015f-fetch.20241004-054515.log
[--:--:--][4275015f][ build:base/alpine.bst ] START directives/base-alpine/4275015f-build.20241004-054522.log
[--:--:--][4275015f][ build:base/alpine.bst ] START Staging sources
[00:00:00][4275015f][ build:base/alpine.bst ] SUCCESS Staging sources
[--:--:--][4275015f][ build:base/alpine.bst ] START Caching artifact
[00:00:00][4275015f][ build:base/alpine.bst ] SUCCESS Caching artifact
[00:00:00][4275015f][ build:base/alpine.bst ] SUCCESS directives/base-alpine/4275015f-build.20241004-054522.log
[--:--:--][22843536][ build:base.bst ] START directives/base/22843536-build.20241004-054522.log
[--:--:--][22843536][ build:base.bst ] START Caching artifact
[00:00:00][22843536][ build:base.bst ] SUCCESS Caching artifact
[00:00:00][22843536][ build:base.bst ] SUCCESS directives/base/22843536-build.20241004-054522.log
[--:--:--][49a52215][ build:hello.bst ] START directives/hello/49a52215-build.20241004-054522.log
[--:--:--][49a52215][ build:hello.bst ] START Staging dependencies at: /
[00:00:00][49a52215][ build:hello.bst ] SUCCESS Staging dependencies at: /
[--:--:--][49a52215][ build:hello.bst ] START Integrating sandbox
[00:00:00][49a52215][ build:hello.bst ] SUCCESS Integrating sandbox
[--:--:--][49a52215][ build:hello.bst ] START Staging sources
[00:00:00][49a52215][ build:hello.bst ] SUCCESS Staging sources
[--:--:--][49a52215][ build:hello.bst ] START Running commands
make PREFIX="/usr" GREETING="Hello world !"
make -j1 PREFIX="/usr" DESTDIR="/buildstream-install" install
[00:00:00][49a52215][ build:hello.bst ] SUCCESS Running commands
[--:--:--][49a52215][ build:hello.bst ] START Caching artifact
[00:00:00][49a52215][ build:hello.bst ] SUCCESS Caching artifact
[00:00:00][49a52215][ build:hello.bst ] SUCCESS directives/hello/49a52215-build.20241004-054522.log
[00:00:06][ ][ main:core activity ] SUCCESS Build
Pipeline Summary
Total: 3
Session: 3
Fetch Queue: processed 2, skipped 1, failed 0
Build Queue: processed 3, skipped 0, failed 0
If we want to build the somber
flavor, we just need to specify the
additional --option
command line option to bst
in order to inform BuildStream of the options we want.
user@host:~/directives$ bst --option flavor somber build hello.bst
[--:--:--][ ][ main:core activity ] START Build
[--:--:--][ ][ main:core activity ] START Loading elements
[00:00:00][ ][ main:core activity ] SUCCESS Loading elements
[--:--:--][ ][ main:core activity ] START Resolving elements
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1728020722.761745 2084 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache
[00:00:00][ ][ main:core activity ] SUCCESS Resolving elements
[--:--:--][ ][ main:core activity ] START Initializing remote caches
[00:00:00][ ][ main:core activity ] SUCCESS Initializing remote caches
[--:--:--][ ][ main:core activity ] START Query cache
[00:00:00][ ][ main:core activity ] SUCCESS Query cache
BuildStream Version 2.3.0+13.g0edf2dc8a
Session Start: Friday, 04-10-2024 at 05:45:22
Project: directives (/home/user/buildstream/doc/examples/directives)
Targets: hello.bst
User Configuration
Configuration File: /home/user/buildstream/doc/run-bst-wywe3x_l/buildstream.conf
Cache Directory: /home/user/buildstream/doc/run-bst-wywe3x_l
Log Files: /home/user/buildstream/doc/run-bst-wywe3x_l/logs
Source Mirrors: /home/user/buildstream/doc/run-bst-wywe3x_l/sources
Build Area: /home/user/buildstream/doc/run-bst-wywe3x_l/build
Strict Build Plan: Yes
Maximum Fetch Tasks: 10
Maximum Build Tasks: 4
Maximum Push Tasks: 4
Maximum Network Retries: 2
Project: directives
Project Options
flavor: somber
Element Plugins
manual: core plugin
stack: core plugin
import: core plugin
Source Plugins
local: core plugin
tar: core plugin
Pipeline
cached 4275015f95b90fd68b24421a9586814f97cc03630ce28d0b9fe35435bfe08ca5 base/alpine.bst
cached 2284353672b080d3b1f19eacc625c0b6449109676abd0144328ca2521dabc977 base.bst
buildable 14183452db56642e12bc721cd3501237d397ac87b1f24988665d69177fe488cb hello.bst
===============================================================================
[--:--:--][14183452][ build:hello.bst ] START directives/hello/14183452-build.20241004-054522.log
[--:--:--][14183452][ build:hello.bst ] START Staging dependencies at: /
[00:00:00][14183452][ build:hello.bst ] SUCCESS Staging dependencies at: /
[--:--:--][14183452][ build:hello.bst ] START Integrating sandbox
[00:00:00][14183452][ build:hello.bst ] SUCCESS Integrating sandbox
[--:--:--][14183452][ build:hello.bst ] START Staging sources
[00:00:00][14183452][ build:hello.bst ] SUCCESS Staging sources
[--:--:--][14183452][ build:hello.bst ] START Running commands
make PREFIX="/usr" GREETING="Hey world."
make -j1 PREFIX="/usr" DESTDIR="/buildstream-install" install
[00:00:00][14183452][ build:hello.bst ] SUCCESS Running commands
[--:--:--][14183452][ build:hello.bst ] START Caching artifact
[00:00:00][14183452][ build:hello.bst ] SUCCESS Caching artifact
[00:00:00][14183452][ build:hello.bst ] SUCCESS directives/hello/14183452-build.20241004-054522.log
[00:00:00][ ][ main:core activity ] SUCCESS Build
Pipeline Summary
Total: 3
Session: 3
Fetch Queue: processed 0, skipped 3, failed 0
Build Queue: processed 1, skipped 2, failed 0
Note that the --option
option can be specified many times on the
bst
command line, so as to support projects which have multiple
options.
Finally lets get the excited
flavor built as well:
user@host:~/directives$ bst --option flavor excited build hello.bst
[--:--:--][ ][ main:core activity ] START Build
[--:--:--][ ][ main:core activity ] START Loading elements
[00:00:00][ ][ main:core activity ] SUCCESS Loading elements
[--:--:--][ ][ main:core activity ] START Resolving elements
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1728020723.375994 2141 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache
[00:00:00][ ][ main:core activity ] SUCCESS Resolving elements
[--:--:--][ ][ main:core activity ] START Initializing remote caches
[00:00:00][ ][ main:core activity ] SUCCESS Initializing remote caches
[--:--:--][ ][ main:core activity ] START Query cache
[00:00:00][ ][ main:core activity ] SUCCESS Query cache
BuildStream Version 2.3.0+13.g0edf2dc8a
Session Start: Friday, 04-10-2024 at 05:45:23
Project: directives (/home/user/buildstream/doc/examples/directives)
Targets: hello.bst
User Configuration
Configuration File: /home/user/buildstream/doc/run-bst-wywe3x_l/buildstream.conf
Cache Directory: /home/user/buildstream/doc/run-bst-wywe3x_l
Log Files: /home/user/buildstream/doc/run-bst-wywe3x_l/logs
Source Mirrors: /home/user/buildstream/doc/run-bst-wywe3x_l/sources
Build Area: /home/user/buildstream/doc/run-bst-wywe3x_l/build
Strict Build Plan: Yes
Maximum Fetch Tasks: 10
Maximum Build Tasks: 4
Maximum Push Tasks: 4
Maximum Network Retries: 2
Project: directives
Project Options
flavor: excited
Element Plugins
manual: core plugin
stack: core plugin
import: core plugin
Source Plugins
local: core plugin
tar: core plugin
Pipeline
cached 4275015f95b90fd68b24421a9586814f97cc03630ce28d0b9fe35435bfe08ca5 base/alpine.bst
cached 2284353672b080d3b1f19eacc625c0b6449109676abd0144328ca2521dabc977 base.bst
buildable 72169f19db218d37d9f9b2a8603c0b75dcd391d3a07e5ef900f95e6fdaaca1ba hello.bst
===============================================================================
[--:--:--][72169f19][ build:hello.bst ] START directives/hello/72169f19-build.20241004-054523.log
[--:--:--][72169f19][ build:hello.bst ] START Staging dependencies at: /
[00:00:00][72169f19][ build:hello.bst ] SUCCESS Staging dependencies at: /
[--:--:--][72169f19][ build:hello.bst ] START Integrating sandbox
[00:00:00][72169f19][ build:hello.bst ] SUCCESS Integrating sandbox
[--:--:--][72169f19][ build:hello.bst ] START Staging sources
[00:00:00][72169f19][ build:hello.bst ] SUCCESS Staging sources
[--:--:--][72169f19][ build:hello.bst ] START Running commands
make PREFIX="/usr" GREETING="Howdy there, and what a world it is !"
make -j1 PREFIX="/usr" DESTDIR="/buildstream-install" install
[00:00:00][72169f19][ build:hello.bst ] SUCCESS Running commands
[--:--:--][72169f19][ build:hello.bst ] START Caching artifact
[00:00:00][72169f19][ build:hello.bst ] SUCCESS Caching artifact
[00:00:00][72169f19][ build:hello.bst ] SUCCESS directives/hello/72169f19-build.20241004-054523.log
[00:00:00][ ][ main:core activity ] SUCCESS Build
Pipeline Summary
Total: 3
Session: 3
Fetch Queue: processed 0, skipped 3, failed 0
Build Queue: processed 1, skipped 2, failed 0
If you observe the cache keys above, you will notice that while
we have only three elements in the pipeline, counting base/alpine.bst
,
base.bst
and hello.bst
, we have actually built five artifacts,
because the hello.bst
is built differently each time, it has a
different cache key and is stored separately in the artifact cache.
5.3.2. Run the hello world program with options
Since the --option
command line option to bst
is a main option, it can be used in any command.
Let’s run the hello
program using bst shell
three times in a row, each time using a different option so we can
observe the results.
user@host:~/directives$ bst shell hello.bst -- hello
[--:--:--][ ][ main:core activity ] START Loading elements
[00:00:00][ ][ main:core activity ] SUCCESS Loading elements
[--:--:--][ ][ main:core activity ] START Resolving elements
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1728020723.992685 2197 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache
[00:00:00][ ][ main:core activity ] SUCCESS Resolving elements
[--:--:--][ ][ main:core activity ] START Initializing remote caches
[00:00:00][ ][ main:core activity ] SUCCESS Initializing remote caches
[--:--:--][ ][ main:core activity ] START Query cache
[00:00:00][ ][ main:core activity ] SUCCESS Query cache
[--:--:--][49a52215][ main:hello.bst ] START Staging dependencies
[00:00:00][49a52215][ main:hello.bst ] SUCCESS Staging dependencies
[--:--:--][49a52215][ main:hello.bst ] START Integrating sandbox
[00:00:00][49a52215][ main:hello.bst ] SUCCESS Integrating sandbox
[--:--:--][49a52215][ main:hello.bst ] STATUS Running command
hello
Hello world !
user@host:~/directives$ bst --option flavor somber shell hello.bst -- hello
[--:--:--][ ][ main:core activity ] START Loading elements
[00:00:00][ ][ main:core activity ] SUCCESS Loading elements
[--:--:--][ ][ main:core activity ] START Resolving elements
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1728020724.509841 2241 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache
[00:00:00][ ][ main:core activity ] SUCCESS Resolving elements
[--:--:--][ ][ main:core activity ] START Initializing remote caches
[00:00:00][ ][ main:core activity ] SUCCESS Initializing remote caches
[--:--:--][ ][ main:core activity ] START Query cache
[00:00:00][ ][ main:core activity ] SUCCESS Query cache
[--:--:--][14183452][ main:hello.bst ] START Staging dependencies
[00:00:00][14183452][ main:hello.bst ] SUCCESS Staging dependencies
[--:--:--][14183452][ main:hello.bst ] START Integrating sandbox
[00:00:00][14183452][ main:hello.bst ] SUCCESS Integrating sandbox
[--:--:--][14183452][ main:hello.bst ] STATUS Running command
hello
Hey world.
user@host:~/directives$ bst --option flavor excited shell hello.bst -- hello
[--:--:--][ ][ main:core activity ] START Loading elements
[00:00:00][ ][ main:core activity ] SUCCESS Loading elements
[--:--:--][ ][ main:core activity ] START Resolving elements
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1728020725.019382 2285 config.cc:230] gRPC experiments enabled: call_status_override_on_cancellation, event_engine_dns, event_engine_listener, http2_stats_fix, monitoring_experiment, pick_first_new, trace_record_callops, work_serializer_clears_time_cache
[00:00:00][ ][ main:core activity ] SUCCESS Resolving elements
[--:--:--][ ][ main:core activity ] START Initializing remote caches
[00:00:00][ ][ main:core activity ] SUCCESS Initializing remote caches
[--:--:--][ ][ main:core activity ] START Query cache
[00:00:00][ ][ main:core activity ] SUCCESS Query cache
[--:--:--][72169f19][ main:hello.bst ] START Staging dependencies
[00:00:00][72169f19][ main:hello.bst ] SUCCESS Staging dependencies
[--:--:--][72169f19][ main:hello.bst ] START Integrating sandbox
[00:00:00][72169f19][ main:hello.bst ] SUCCESS Integrating sandbox
[--:--:--][72169f19][ main:hello.bst ] STATUS Running command
hello
Howdy there, and what a world it is !
5.4. Summary
In this chapter we’ve demonstrated how to declare project options, how to use conditional directives, and also how to use include directives.
To get more familliar with these concepts, you may want to explore the remaining directives in the BuildStream YAML format, and also take a look at the various types of project options that are also supported.