|
| 1 | +========================================================== |
| 2 | +Tutorial 5: Using Build Automation Tools As a Build System |
| 3 | +========================================================== |
| 4 | + |
| 5 | +In this tutorial we will present how to use `Easybuild <https://easybuild.io/>`__ and `Spack <https://spack.io/>`__ as a build system for a ReFrame test. |
| 6 | +The example uses the configuration file presented in :doc:`tutorial_basics`, which you can find in ``tutorials/config/settings.py``. |
| 7 | +We also assume that the reader is already familiar with the concepts presented in the basic tutorial and has a working knowledge of EasyBuild and Spack. |
| 8 | +Finally, to avoid specifying the tutorial configuration file each time you run the test, make sure to export it here: |
| 9 | + |
| 10 | +.. code:: bash |
| 11 | +
|
| 12 | + export RFM_CONFIG_FILE=$(pwd)/tutorials/config/mysettings.py |
| 13 | +
|
| 14 | +
|
| 15 | +
|
| 16 | +Using EasyBuild to Build the Test Code |
| 17 | +-------------------------------------- |
| 18 | + |
| 19 | +.. versionadded:: 3.5.0 |
| 20 | + |
| 21 | + |
| 22 | +Let's consider a simple ReFrame test that installs ``bzip2-1.0.6`` given the easyconfig `bzip2-1.0.6.eb <https://github.com/eth-cscs/production/blob/master/easybuild/easyconfigs/b/bzip2/bzip2-1.0.6.eb>`__ and checks that the installed version is correct. |
| 23 | +The following code block shows the check, highlighting the lines specific to this tutorial: |
| 24 | + |
| 25 | +.. literalinclude:: ../tutorials/build_systems/easybuild/eb_test.py |
| 26 | + :lines: 6- |
| 27 | + :emphasize-lines: 12,14-17,19-21 |
| 28 | + |
| 29 | +The test looks pretty standard except for the highlighted blocks. |
| 30 | +Let's have a look first to the block in the :class:`BZip2Check` class. |
| 31 | + |
| 32 | +The first thing is to specify that the EasyBuild build system will be used. |
| 33 | +This is done by setting :attr:`~reframe.core.pipeline.RegressionTest.build_system` to ``'EasyBuild'``. |
| 34 | +Then, the software to be installed is passed as a list to :attr:`~reframe.core.buildsystems.EasyBuild.easyconfigs`. |
| 35 | +Here only one easyconfig is given, but more than one can be passed. |
| 36 | +Finally, through :attr:`~reframe.core.buildsystems.EasyBuild.options`, command line options can be passed to the ``eb`` executable. |
| 37 | +In this test we pass ``-f`` to make sure that ``bzip2`` will be built even if the module already exists externally. |
| 38 | + |
| 39 | +For this test, ReFrame generates the following command to build and install the easyconfig: |
| 40 | + |
| 41 | +.. code-block:: console |
| 42 | +
|
| 43 | + export EASYBUILD_BUILDPATH={stagedir}/easybuild/build |
| 44 | + export EASYBUILD_INSTALLPATH={stagedir}/easybuild |
| 45 | + export EASYBUILD_PREFIX={stagedir}/easybuild |
| 46 | + export EASYBUILD_SOURCEPATH={stagedir}/easybuild |
| 47 | + eb bzip2-1.0.6.eb -f |
| 48 | +
|
| 49 | +ReFrame will keep all the files generated by EasyBuild (sources, temporary files, installed software and the corresponding modules) under the test's stage directory. |
| 50 | +For this reason it sets the relevant EasyBuild environment variables. |
| 51 | + |
| 52 | +.. tip:: |
| 53 | + |
| 54 | + Users may set the EasyBuild prefix to a different location by setting the :attr:`~reframe.core.buildsystems.EasyBuild.prefix` attribute of the build system. |
| 55 | + This allows you to have the built software installed upon successful completion of the build phase, but if the test fails in a later stage (sanity, performance), the installed software will not be cleaned up automatically. |
| 56 | + |
| 57 | +.. note:: |
| 58 | + |
| 59 | + ReFrame assumes that the ``eb`` executable is available on the system where the compilation is run (typically the local host where ReFrame is executed). |
| 60 | + |
| 61 | + |
| 62 | +Now that we know everything related to building and installing the code, we can move to the part dealing with running it. |
| 63 | +To run the code, the generated modules need to be loaded in order to make the software available. |
| 64 | +The modules can be accessed through :attr:`~reframe.core.buildsystems.Easybuild.generated_modules`, however, they are available only after EasyBuild completes the installation. |
| 65 | +This means that :attr:`~reframe.core.pipeline.RegressionTest.modules` can be set only after the build phase finishes. |
| 66 | +For that, we can set :attr:`~reframe.core.pipeline.RegressionTest.modules` in a class method wrapped by the :py:func:`~reframe.core.RegressionTest.run_before` built-in, specifying the ``run`` phase. |
| 67 | +This test will then run the following commands: |
| 68 | + |
| 69 | +.. code-block:: console |
| 70 | +
|
| 71 | + module load bzip/1.0.6 |
| 72 | + bzip2 --help |
| 73 | +
|
| 74 | +
|
| 75 | +-------------------------- |
| 76 | +Packaging the installation |
| 77 | +-------------------------- |
| 78 | + |
| 79 | +The EasyBuild build system offers a way of packaging the installation via EasyBuild's packaging support. |
| 80 | +To use this feature, `the FPM package manager <https://fpm.readthedocs.io/en/latest/intro.html>`__ must be available. |
| 81 | +By setting the dictionary :attr:`~reframe.core.buildsystems.Easybuild.package_opts` in the test, ReFrame will pass ``--package-{key}={val}`` to the EasyBuild invocation. |
| 82 | +For instance, the following can be set to package the installations as an rpm file: |
| 83 | + |
| 84 | +.. code-block:: python |
| 85 | +
|
| 86 | + self.keep_files = ['easybuild/packages'] |
| 87 | + self.build_system.package_opts = { |
| 88 | + 'type': 'rpm', |
| 89 | + } |
| 90 | +
|
| 91 | +The packages are generated by EasyBuild in the stage directory. |
| 92 | +To retain them after the test succeeds, :attr:`~reframe.core.pipeline.RegressionTest.keep_files` needs to be set. |
| 93 | + |
| 94 | + |
| 95 | + |
| 96 | +Using Spack to Build the Test Code |
| 97 | +---------------------------------- |
| 98 | + |
| 99 | + |
| 100 | +.. versionadded:: 3.6.1 |
| 101 | + |
| 102 | + |
| 103 | +This example is the equivalent to the previous one, except that it uses Spack to build ``bzip2``. |
| 104 | +Here is the test's code: |
| 105 | + |
| 106 | +.. literalinclude:: ../tutorials/build_systems/spack/spack_test.py |
| 107 | + :lines: 6- |
| 108 | + :emphasize-lines: 12,14-16 |
| 109 | + |
| 110 | + |
| 111 | +When :attr:`~reframe.core.pipeline.RegressionTest.build_system` is set to ``'Spack'``, ReFrame will leverage Spack environments in order to build the test code. |
| 112 | +For this reason, currently, users must specify an environment. |
| 113 | +ReFrame treats Spack environments as *test resources* so it expects to find them under the test's :attr:`~reframe.core.pipeline.RegressionTest.sourcesdir`, which defaults to ``'src'``. |
| 114 | +Here is the directory structure for the test in this particular example that we show here: |
| 115 | + |
| 116 | +.. code:: console |
| 117 | +
|
| 118 | + tutorials/build_systems/spack/ |
| 119 | + ├── spack_test.py |
| 120 | + └── src |
| 121 | + └── myenv |
| 122 | + └── spack.yaml |
| 123 | +
|
| 124 | +
|
| 125 | +We could have placed ``spack.yaml`` directly under the ``src/`` directory, in which case we would need to specify ``'.'`` as an environment. |
| 126 | +For reference, here are the contents of ``spack.yaml``: |
| 127 | + |
| 128 | +.. literalinclude:: ../tutorials/build_systems/spack/src/myenv/spack.yaml |
| 129 | + |
| 130 | + |
| 131 | +As with every other test, ReFrame will copy the test's resources to its stage directory before building it. |
| 132 | +ReFrame will then activate the environment and install the associated specs as in this case. |
| 133 | +Optionally, we can add more specs to the environment by setting the :attr:`~reframe.core.buildsystems.Spack.specs` attribute of the build system. |
| 134 | +Here is what ReFrame generates as a build script in this example: |
| 135 | + |
| 136 | +.. code:: bash |
| 137 | +
|
| 138 | + . $SPACK_ROOT/share/spack/setup-env.sh |
| 139 | + spack env activate -V -d myenv |
| 140 | + spack install |
| 141 | +
|
| 142 | +Any additional specs specified inside the ReFrame test will be added using the ``spack add`` command. |
| 143 | +As you might have noticed ReFrame expects that Spack is already installed on the system. |
| 144 | +The packages specified in the environment and the tests will be installed in the test's stage directory, where the environment is copied before building. |
| 145 | +Here is the stage directory structure: |
| 146 | + |
| 147 | +.. code:: console |
| 148 | +
|
| 149 | + stage/generic/default/builtin/BZip2SpackCheck/ |
| 150 | + ├── myenv |
| 151 | + │ ├── spack |
| 152 | + │ │ ├── opt |
| 153 | + │ │ │ └── spack |
| 154 | + │ │ │ ├── bin |
| 155 | + │ │ │ └── darwin-catalina-skylake |
| 156 | + │ │ └── share |
| 157 | + │ │ └── spack |
| 158 | + │ │ └── modules |
| 159 | + │ ├── spack.lock |
| 160 | + │ └── spack.yaml |
| 161 | + ├── rfm_BZip2SpackCheck_build.err |
| 162 | + ├── rfm_BZip2SpackCheck_build.out |
| 163 | + ├── rfm_BZip2SpackCheck_build.sh |
| 164 | + ├── rfm_BZip2SpackCheck_job.err |
| 165 | + ├── rfm_BZip2SpackCheck_job.out |
| 166 | + └── rfm_BZip2SpackCheck_job.sh |
| 167 | +
|
| 168 | +
|
| 169 | +Finally, here is the generated run script that ReFrame uses to run the test, once its build has succeeded: |
| 170 | + |
| 171 | +.. code-block:: bash |
| 172 | +
|
| 173 | + #!/bin/bash |
| 174 | + . $SPACK_ROOT/share/spack/setup-env.sh |
| 175 | + spack env activate -V -d myenv |
| 176 | + bzip2 --help |
| 177 | +
|
| 178 | +From this point on, sanity and performance checking are exactly identical to any other ReFrame test. |
| 179 | + |
| 180 | +.. tip:: |
| 181 | + |
| 182 | + While developing a test using Spack or EasyBuild as a build system, it can be useful to run ReFrame with the :option:`--keep-stage-files` and :option:`--dont-restage` options to prevent ReFrame from removing the test's stage directory upon successful completion of the test. |
| 183 | + For this particular type of test, these options will avoid having to rebuild the required package dependencies every time the test is retried. |
0 commit comments