summaryrefslogtreecommitdiff
path: root/doc/source/tutorial/running-commands.rst
blob: 78c6df6484a7f8ac9f9ee341c5243d6889ca953a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205


Running commands
================
In :ref:`the first chapter <tutorial_first_project>` we only imported
a file to create an artifact, this time lets run some commands inside
the :ref:`isolated build sandbox <sandboxing>`.

.. note::

   This example is distributed with BuildStream
   in the `doc/examples/running-commands
   <https://gitlab.com/BuildStream/buildstream/tree/master/doc/examples/running-commands>`_
   subdirectory.


Overview
--------
In this chapter, we'll be running commands inside the sandboxed
execution environment and producing build output.

We'll be compiling the following simple C file:


``files/src/hello.c``
~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: ../../examples/running-commands/files/src/hello.c
   :language: c


And we're going to build it using ``make``, using the following Makefile:


``files/src/Makefile``
~~~~~~~~~~~~~~~~~~~~~~

.. literalinclude:: ../../examples/running-commands/files/src/Makefile
   :language: Makefile


We'll be using the most fundamental :ref:`build element <plugins_build_elements>`,
the :mod:`manual <elements.manual>` build element.

The :mod:`manual <elements.manual>` element is the backbone on which all the other
build elements are built, so understanding how it works at this level is helpful.


Project structure
-----------------
In this project we have a ``project.conf``, a directory with some source
code, and 3 element declarations.

Let's first take a peek at what we need to build using :ref:`bst show <invoking_show>`:

.. raw:: html
   :file: ../sessions/running-commands-show-before.html

This time we have loaded a pipeline with 3 elements, let's go over what they do
in detail.


``project.conf``
~~~~~~~~~~~~~~~~

.. literalinclude:: ../../examples/running-commands/project.conf
   :language: yaml

Our ``project.conf`` is very much like the last one, except that we
have defined a :ref:`source alias <project_source_aliases>` for ``alpine``.

.. tip::

   Using :ref:`source aliases <project_source_aliases>` for groups of sources
   which are generally hosted together is encouraged. This allows one to globally
   change the access scheme or URL for a group of repositories which belong together.


``elements/base/alpine.bst``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. literalinclude:: ../../examples/running-commands/elements/base/alpine.bst
   :language: yaml

This :mod:`import <elements.import>` element uses a :mod:`tar <sources.tar>`
source to download our Alpine Linux tarball to create our base runtime.

This tarball is a sysroot which provides the C runtime libraries
and some programs - this is what will be providing the programs we're
going to run in this example.


``elements/base.bst``
~~~~~~~~~~~~~~~~~~~~~

.. literalinclude:: ../../examples/running-commands/elements/base.bst
   :language: yaml

This is just a symbolic :mod:`stack <elements.stack>` element which declares that
anything which depends on it, will implicitly depend on ``base/alpine.bst``.

It is typical to use stack elements in places where the implementing logical
software stack could change, but you rather not have your higher level components
carry knowledge about those changing components.

Any element which :ref:`runtime depends <format_dependencies_types>` on
the ``base.bst`` will now be able to execute programs provided by the imported
``base/alpine.bst`` runtime.


``elements/hello.bst``
~~~~~~~~~~~~~~~~~~~~~~

.. literalinclude:: ../../examples/running-commands/elements/hello.bst
   :language: yaml

Finally we have the element which executes commands. Looking at the
:mod:`manual <elements.manual>` element's documentation, we can see that
the element configuration exposes four command lists:

* ``configure-commands``

  Commands which are run in preparation of a build. This is where you
  would normally call any configure stage build tools to configure
  the build how you like and generate some files needed for the build.

* ``build-commands``

  Commands to run the build, usually a build system will
  invoke the compiler for you here.

* ``install-commands``

  Commands to install the build results.

  Commands to install the build results into the target system,
  these should install files somewhere under ``%{install-root}``.

* ``strip-commands``

  Commands to doctor the build results after the install.

  Typically this involves stripping binaries of debugging
  symbols or stripping timestamps from build results to ensure
  reproducibility.

.. tip::

   All other :ref:`build elements <plugins_build_elements>`
   implement exactly the same command lists too, except that they provide
   default commands specific to invoke the build systems they support.

The :mod:`manual <elements.manual>` element however is the most basic
and does not provide any default commands, so we have instructed it
to use ``make`` to build and install our program.

     
Using the project
-----------------


Build the hello.bst element
~~~~~~~~~~~~~~~~~~~~~~~~~~~
To build the project, run :ref:`bst build <invoking_build>` in the
following way:

.. raw:: html
   :file: ../sessions/running-commands-build.html

Now we've built our hello world program, using ``make``
and the C compiler provided by the Alpine Linux image.

In the :ref:`first chapter <tutorial_first_project>` we observed that the inputs
and output of an element are *directory trees*. In this example, the directory tree
generated by ``base/alpine.bst`` is consumed by ``hello.bst`` due to the
:ref:`implicit runtime dependency <format_dependencies_types>` introduced by ``base.bst``.

.. tip::

   All of the :ref:`dependencies <format_dependencies>` which are required to run for
   the sake of a build, are staged at the root of the build sandbox. These comprise the
   runtime environment in which the depending element will run commands.

   The result is that the ``make`` program and C compiler provided by ``base/alpine.bst``
   were already in ``$PATH`` and ready to run when the commands were needed by ``hello.bst``.

Now observe that all of the elements in the loaded pipeline are ``cached``,
the element is *built*:

.. raw:: html
   :file: ../sessions/running-commands-show-after.html


Run the hello world program
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now that we've built everything, we can indulge ourselves in running
the hello world program using :ref:`bst shell <invoking_build>`:

.. raw:: html
   :file: ../sessions/running-commands-shell.html

Here, :ref:`bst shell <invoking_build>` created a runtime environment for running
the ``hello.bst`` element. This was done by staging all of the dependencies of
``hello.bst`` including the ``hello.bst`` output itself into a directory. Once a directory
with all of the dependencies was staged and ready, we ran the ``hello`` command from
within the build sandbox environment.