blob: e516a66926eaf74571f889fb2438369810ff409b [file] [log] [blame]
.. _developing_strict_mode:
Strict mode
===========
In this section, we will cover the usage of :ref:`strict vs non-strict <user_config_strict_mode>`
build plans in conjunction with :ref:`workspaces <developing_workspaces>`, and how this
can help to improve your edit/compile/test cycles.
.. note::
This example is distributed with BuildStream
in the `doc/examples/strict-mode
<https://github.com/apache/buildstream/tree/master/doc/examples/strict-mode>`_
subdirectory.
Overview
--------
When working with BuildStream to create integrations, it is typical that you have a
lot of components to build, and you frequently need to modify a component
at various levels of the stack. When developing one or more applications, you might
want to open a workspace and fix a bug in an application, or you might need to
open a workspace on a low level shared library to fix the behavior of one or
more misbehaving applications.
By default, BuildStream will always choose to be deterministic in order to
produce the most correct build results as possible. As such, modifying a low
level library will result in rebuilding all of it's reverse dependencies, but
this can be very time consuming and inconvenient for your edit/compile/test
cycles.
This is when enabling :ref:`non-strict build plans <user_config_strict_mode>`
can be helpful.
To illustrate the facets of how this works, this example will present a project
consisting of an application which is linked both statically and dynamically
linked to a common library.
Project structure
-----------------
This project is mostly based on the :ref:`integration commands <tutorial_integration_commands>`
example, as such we will ignore large parts of this project and only focus
on the elements which are of specific interest.
To illustrate the relationship of these two applications and the library,
let's briefly take a look at the underlying Makefiles which are used in this
project, starting with the library and followed by both Makefiles used to
build the application.
``files/libhello/Makefile``
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: ../../examples/strict-mode/files/libhello/Makefile
:language: Makefile
``files/hello/Makefile.dynamic``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: ../../examples/strict-mode/files/hello/Makefile.dynamic
:language: Makefile
``files/hello/Makefile.static``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: ../../examples/strict-mode/files/hello/Makefile.static
:language: Makefile
As we can see, we have a library that is distributed both as the dynamic
library ``libhello.so`` and also as the static archive ``libhello.a``.
Now let's take a look at the two separate elements which build the
application, first the dynamically linked version and then the static one.
``elements/hello-dynamic.bst``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: ../../examples/strict-mode/elements/hello-dynamic.bst
:language: yaml
Nothing very special to observe about this hello program, just a
:mod:`manual <elements.manual>` element quite similar to the one we've
already seen in the :ref:`running commands <tutorial_running_commands>`
example.
``elements/hello-static.bst``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. literalinclude:: ../../examples/strict-mode/elements/hello-static.bst
:language: yaml
Almost the same as the dynamic element, except here we have declared the
dependency to the ``libhello.bst`` element differently: this time we have enabled
the ``strict`` option in the :ref:`dependency declaration <format_dependencies>`.
The side effect of setting this option is that ``hello-static.bst`` will be
rebuilt any time that ``libhello.bst`` has changed, even when
:ref:`non-strict build plans <user_config_strict_mode>` have been enabled.
.. tip::
Some element plugins are designed to consume the content of their
dependencies entirely, and output an artifact without any transient
runtime dependencies, an example of this is the :mod:`compose <elements.compose>`
element.
In cases such as :mod:`compose <elements.compose>`, it is not necessary to
explicitly annotate their dependencies as ``strict``.
It is only helpful to set the ``strict`` attribute on a
:ref:`dependency declaration <format_dependencies>` in the case that the
specific dependency relationship causes data to be consumed verbatim,
as is the case with static linking.
Using the project
-----------------
For the sake of brevity, let's assume that you've already built all of the
elements of this project, and that you want to make some changes to the
``libhello.bst`` element, and test how it might effect the hello program.
Everything is already built
~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. raw:: html
:file: ../sessions/strict-mode-show-initial.html
Open a workspace and modify libhello.c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now let's open up a workspace on the hello library
.. raw:: html
:file: ../sessions/strict-mode-workspace-open.html
And go ahead and make a modification like this:
.. literalinclude:: ../../examples/strict-mode/update.patch
:language: diff
Observing ``hello-dynamic.bst``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Let's take a look at the :ref:`bst show <invoking_show>` output for
the dynamically linked ``hello-dynamic.bst`` element.
.. raw:: html
:file: ../sessions/strict-mode-show-dynamic-strict.html
As one might expect, the ``libhello.bst`` element is ready to be built
after having been modified, and the ``hello-dynamic.bst`` element is
waiting for ``libhello.bst`` to be built before it can build.
Now let's take a look at the same elements if we pass the ``--no-strict``
option to ``bst``:
.. raw:: html
:file: ../sessions/strict-mode-show-dynamic-no-strict.html
Note that this time, the ``libhello.bst`` still needs to be built,
but the ``hello-dymamic.bst`` element is showing up as ``cached``.
.. tip::
The :ref:`bst show <invoking_show>` output will show some cache
keys dimmed out in the case that they are not entirely deterministic.
Here we can see that ``hello-dynamic.bst`` is dimmed out because
it will not be rebuilt against the changed ``libhello.bst`` element,
and it also has a different cache key because of this.
Observing ``hello-static.bst``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now let's observe the ``hello-static.bst`` element with strict mode
disabled:
.. raw:: html
:file: ../sessions/strict-mode-show-static-no-strict.html
Note that in this case the ``hello-strict.bst`` is going to be
rebuilt even in strict mode. This is because we annotated the
declaration of the ``libhello.bst`` dependency with the ``strict``
attribute.
We did this because ``hello-strict.bst`` consumes the input of
``libhello.bst`` verbatim, by way of statically linking to it, instead
of merely being affected by the content of ``libhello.bst`` at runtime,
as would be the case of static linking.
Building and running ``hello-dynamic.bst``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Now let's build ``hello-dynamic.bst`` with strict mode disabled.
.. raw:: html
:file: ../sessions/strict-mode-build-dynamic-no-strict.html
Note that the :ref:`bst build <invoking_build>` command completed without
having to build ``hello-dynamic.bst`` at all.
And now we can also run ``hello-dynamic.bst``
.. raw:: html
:file: ../sessions/strict-mode-run-dynamic-no-strict.html
When running ``hello-dynamic.bst`` with no-strict mode, we are
actually reusing the old build of ``hello-dynamic.bst`` staged against
the new build of the modified ``libhello.bst`` element.
Building and running ``hello-static.bst``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Finally, if we build ``hello-static.bst`` with strict mode disabled,
we can see that it will be rebuilt regardless of strict mode being
enabled.
.. raw:: html
:file: ../sessions/strict-mode-build-static-no-strict.html
This is of course because we declared its dependency on ``libhello.bst``
as a ``strict`` dependency.
And by the same virtue, we can see that when we run the example
it has properly relinked against the changed static archive, and
has the updated text in the greeting:
.. raw:: html
:file: ../sessions/strict-mode-run-static-no-strict.html
Summary
-------
In this chapter we've explored how to use :ref:`non-strict build plans <user_config_strict_mode>`
in order to avoid rebuilding reverse dependencies of a lower level
element you might be working with in a :ref:`workspace <invoking_workspace_open>`,
consequently improving your edit/compile/test experience.
We've also explained how to ensure your project still works properly
with non-strict build plans when some elements perform static linking
(or other operations which consume data from their dependencies
verbatim), by annotating :ref:`dependency declarations <format_dependencies>`
as ``strict``.