.. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. _developing_strict_mode: Strict mode =========== In this section, we will cover the usage of :ref:`strict vs non-strict ` build plans in conjunction with :ref:`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 `_ 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 ` 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 ` 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 ` element quite similar to the one we've already seen in the :ref:`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 `. 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 ` 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 ` element. In cases such as :mod:`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 ` 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 ` 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 ` 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 ` 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 ` in order to avoid rebuilding reverse dependencies of a lower level element you might be working with in a :ref:`workspace `, 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 ` as ``strict``.