summaryrefslogtreecommitdiff
path: root/lib/spack/docs/build_systems/sconspackage.rst
blob: a17e1271b86d3b7d03e7dc16a2fc0665d43b6a8e (plain) (blame)
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
.. Copyright 2013-2023 Lawrence Livermore National Security, LLC and other
   Spack Project Developers. See the top-level COPYRIGHT file for details.

   SPDX-License-Identifier: (Apache-2.0 OR MIT)

.. _sconspackage:

-----
SCons
-----

SCons is a general-purpose build system that does not rely on
Makefiles to build software. SCons is written in Python, and handles
all building and linking itself.

As far as build systems go, SCons is very non-uniform. It provides a
common framework for developers to write build scripts, but the build
scripts themselves can vary drastically. Some developers add subcommands
like:

.. code-block:: console

   $ scons clean
   $ scons build
   $ scons test
   $ scons install


Others don't add any subcommands. Some have configuration options that
can be specified through variables on the command line. Others don't.

^^^^^^
Phases
^^^^^^

As previously mentioned, SCons allows developers to add subcommands like
``build`` and ``install``, but by default, installation usually looks like:

.. code-block:: console

   $ scons
   $ scons install


To facilitate this, the ``SConsBuilder`` and ``SconsPackage`` base classes provide the
following phases:

#. ``build`` - build the package
#. ``install`` - install the package

Package developers often add unit tests that can be invoked with
``scons test`` or ``scons check``. Spack provides a ``test`` method
to handle this. Since we don't know which one the package developer
chose, the ``test`` method does nothing by default, but can be easily
overridden like so:

.. code-block:: python

   def test(self):
       scons("check")


^^^^^^^^^^^^^^^
Important files
^^^^^^^^^^^^^^^

SCons packages can be identified by their ``SConstruct`` files. These
files handle everything from setting up subcommands and command-line
options to linking and compiling.

One thing to look for is the ``EnsureSConsVersion`` function:

.. code-block:: none

   EnsureSConsVersion(2, 3, 0)


This means that SCons 2.3.0 is the earliest release that will work.
You should specify this in a ``depends_on`` statement.

^^^^^^^^^^^^^^^^^^^^^^^^^
Build system dependencies
^^^^^^^^^^^^^^^^^^^^^^^^^

At the bare minimum, packages that use the SCons build system need a
``scons`` dependency. Since this is always the case, the ``SConsPackage``
base class already contains:

.. code-block:: python

   depends_on("scons", type="build")


If you want to specify a particular version requirement, you can override
this in your package:

.. code-block:: python

   depends_on("scons@2.3.0:", type="build")


^^^^^^^^^^^^^^^^^^^^^^^^^
Finding available options
^^^^^^^^^^^^^^^^^^^^^^^^^

The first place to start when looking for a list of valid options to
build a package is ``scons --help``. Some packages like
`kahip <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/kahip/package.py>`_
don't bother overwriting the default SCons help message, so this isn't
very useful, but other packages like
`serf <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/serf/package.py>`_
print a list of valid command-line variables:

.. code-block:: console

   $ scons --help
   scons: Reading SConscript files ...
   Checking for GNU-compatible C compiler...yes
   scons: done reading SConscript files.

   PREFIX: Directory to install under ( /path/to/PREFIX )
       default: /usr/local
       actual: /usr/local

   LIBDIR: Directory to install architecture dependent libraries under ( /path/to/LIBDIR )
       default: $PREFIX/lib
       actual: /usr/local/lib

   APR: Path to apr-1-config, or to APR's install area ( /path/to/APR )
       default: /usr
       actual: /usr

   APU: Path to apu-1-config, or to APR's install area ( /path/to/APU )
       default: /usr
       actual: /usr

   OPENSSL: Path to OpenSSL's install area ( /path/to/OPENSSL )
       default: /usr
       actual: /usr

   ZLIB: Path to zlib's install area ( /path/to/ZLIB )
       default: /usr
       actual: /usr

   GSSAPI: Path to GSSAPI's install area ( /path/to/GSSAPI )
       default: None
       actual: None

   DEBUG: Enable debugging info and strict compile warnings (yes|no)
       default: False
       actual: False

   APR_STATIC: Enable using a static compiled APR (yes|no)
       default: False
       actual: False

   CC: Command name or path of the C compiler
       default: None
       actual: gcc

   CFLAGS: Extra flags for the C compiler (space-separated)
       default: None
       actual:

   LIBS: Extra libraries passed to the linker, e.g. "-l<library1> -l<library2>" (space separated)
       default: None
       actual: None

   LINKFLAGS: Extra flags for the linker (space-separated)
       default: None
       actual:

   CPPFLAGS: Extra flags for the C preprocessor (space separated)
       default: None
       actual: None

   Use scons -H for help about command-line options.


More advanced packages like
`cantera <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/cantera/package.py>`_
use ``scons --help`` to print a list of subcommands:

.. code-block:: console

   $ scons --help
   scons: Reading SConscript files ...

   SCons build script for Cantera

   Basic usage:
       'scons help' - print a description of user-specifiable options.

       'scons build' - Compile Cantera and the language interfaces using
                       default options.

       'scons clean' - Delete files created while building Cantera.

       '[sudo] scons install' - Install Cantera.

       '[sudo] scons uninstall' - Uninstall Cantera.

       'scons test' - Run all tests which did not previously pass or for which the
                      results may have changed.

       'scons test-reset' - Reset the passing status of all tests.

       'scons test-clean' - Delete files created while running the tests.

       'scons test-help' - List available tests.

       'scons test-NAME' - Run the test named "NAME".

       'scons <command> dump' - Dump the state of the SCons environment to the
                                screen instead of doing <command>, e.g.
                                'scons build dump'. For debugging purposes.

       'scons samples' - Compile the C++ and Fortran samples.

       'scons msi' - Build a Windows installer (.msi) for Cantera.

       'scons sphinx' - Build the Sphinx documentation

       'scons doxygen' - Build the Doxygen documentation


You'll notice that cantera provides a ``scons help`` subcommand. Running
``scons help`` prints a list of valid command-line variables.

^^^^^^^^^^^^^^^^^^^^^^^^^^
Passing arguments to scons
^^^^^^^^^^^^^^^^^^^^^^^^^^

Now that you know what arguments the project accepts, you can add them to
the package build phase. This is done by overriding ``build_args`` like so:

.. code-block:: python

   def build_args(self, spec, prefix):
       args = [
         f"PREFIX={prefix}",
         f"ZLIB={spec['zlib'].prefix}",
       ]

       if spec.satisfies("+debug"):
           args.append("DEBUG=yes")
       else:
           args.append("DEBUG=no")

       return args


``SConsPackage`` also provides an ``install_args`` function that you can
override to pass additional arguments to ``scons install``.

^^^^^^^^^^^^^^^^^
Compiler wrappers
^^^^^^^^^^^^^^^^^

By default, SCons builds all packages in a separate execution environment,
and doesn't pass any environment variables from the user environment.
Even changes to ``PATH`` are not propagated unless the package developer
does so.

This is particularly troublesome for Spack's compiler wrappers, which depend
on environment variables to manage dependencies and linking flags. In many
cases, SCons packages are not compatible with Spack's compiler wrappers,
and linking must be done manually.

First of all, check the list of valid options for anything relating to
environment variables. For example, cantera has the following option:

.. code-block:: none

   * env_vars: [ string ]
       Environment variables to propagate through to SCons. Either the
       string "all" or a comma separated list of variable names, e.g.
       "LD_LIBRARY_PATH,HOME".
       - default: "LD_LIBRARY_PATH,PYTHONPATH"


In the case of cantera, using ``env_vars=all`` allows us to use
Spack's compiler wrappers. If you don't see an option related to
environment variables, try using Spack's compiler wrappers by passing
``spack_cc``, ``spack_cxx``, and ``spack_fc`` via the ``CC``, ``CXX``,
and ``FC`` arguments, respectively. If you pass them to the build and
you see an error message like:

.. code-block:: none

   Spack compiler must be run from Spack! Input 'SPACK_PREFIX' is missing.


you'll know that the package isn't compatible with Spack's compiler
wrappers. In this case, you'll have to use the path to the actual
compilers, which are stored in ``self.compiler.cc`` and friends.
Note that this may involve passing additional flags to the build to
locate dependencies, a task normally done by the compiler wrappers.
serf is an example of a package with this limitation.

^^^^^^^^^^^^^^^^^^^^^^
External documentation
^^^^^^^^^^^^^^^^^^^^^^

For more information on the SCons build system, see:
http://scons.org/documentation.html