summaryrefslogtreecommitdiff
path: root/lib/spack/docs/packaging_guide.rst
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/docs/packaging_guide.rst')
-rw-r--r--lib/spack/docs/packaging_guide.rst312
1 files changed, 299 insertions, 13 deletions
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst
index bc3bacf8f2..8b4c0a4ce1 100644
--- a/lib/spack/docs/packaging_guide.rst
+++ b/lib/spack/docs/packaging_guide.rst
@@ -28,7 +28,7 @@ ubiquitous in the scientific software community. Second, it's a modern
language and has many powerful features to help make package writing
easy.
-Creating & Editing Packages
+Creating & editing packages
----------------------------------
.. _spack-create:
@@ -254,7 +254,7 @@ This is useful when ``spack create`` cannot figure out the name and
version of your package from the archive URL.
-Naming & Directory Structure
+Naming & directory structure
--------------------------------------
.. note::
@@ -497,7 +497,7 @@ versions. See the documentation on `attribute_list_url`_ and
.. _vcs-fetch:
-Fetching from VCS Repositories
+Fetching from VCS repositories
--------------------------------------
For some packages, source code is provided in a Version Control System
@@ -774,6 +774,8 @@ to patch a package's source. For example, the ``py-pyside`` package
contains some custom code for tweaking the way the PySide build
handles ``RPATH``:
+.. _pyside-patch:
+
.. code-block:: python
:linenos:
@@ -810,14 +812,59 @@ You could put this logic in ``install()``, but putting it in a patch
function gives you some benefits. First, spack ensures that the
``patch()`` function is run once per code checkout. That means that
if you run install, hit ctrl-C, and run install again, the code in the
-patch function is only run once. Also, you can tell Spack to run only the patching part of the build using the ..
+patch function is only run once. Also, you can tell Spack to run only
+the patching part of the build using the :ref:`spack-patch` command.
+
+Handling RPATHs
+----------------------------
+
+Spack installs each package in a way that ensures that all of its
+dependencies are found when it runs. It does this using `RPATHs
+<http://en.wikipedia.org/wiki/Rpath>`_. An RPATH is a search
+path, stored in a binary (an executable or library), that tells the
+dynamic loader where to find its dependencies at runtime. You may be
+familiar with ```LD_LIBRARY_PATH``
+<http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html>`_
+on Linux or ```DYLD_LIBRARY_PATH``
+<https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/dyld.1.html>`
+on Mac OS X. RPATH is similar to these paths, in that it tells
+the loader where to find libraries. Unlike them, it is embedded in
+the binary and not set in each user's environment.
+
+RPATHs in Spack are handled in one of three ways:
+
+ 1. For most packages, RPATHs are handled automatically using Spack's
+ :ref:`compiler wrappers <compiler-wrappers>`. These wrappers are
+ set in standard variables like ``CC``, ``CXX``, and ``FC``, so
+ most build systems (autotools and many gmake systems) pick them
+ up and use them.
+ 2. CMake also respects Spack's compiler wrappers, but many CMake
+ builds have logic to overwrite RPATHs when binaries are
+ installed. Spack provides the ``std_cmake_args`` variable, which
+ includes parameters necessary for CMake build use the right
+ installation RPATH. It can be used like this when ``cmake`` is
+ invoked:
+
+ .. code-block:: python
+
+ class MyPackage(Package):
+ ...
+ def install(self, spec, prefix):
+ cmake('..', *std_cmake_args)
+ make()
+ make('install')
+ 3. If you need to modify the build to add your own RPATHs, you can
+ use the ``self.rpath`` property of your package, which will
+ return a list of all the RPATHs that Spack will use when it
+ links. You can see this how this is used in the :ref:`PySide
+ example <pyside-patch>` above.
-Finding Package Downloads
+Finding new versions
----------------------------
-We've already seen the ``homepage`` and ``url`` package attributes:
+You've already seen the ``homepage`` and ``url`` package attributes:
.. code-block:: python
:linenos:
@@ -853,7 +900,7 @@ url is:
url = "http://www.mr511.de/software/libelf-0.8.13.tar.gz"
-Spack spiders ``http://www.mr511.de/software/`` to find similar
+Here, Spack spiders ``http://www.mr511.de/software/`` to find similar
tarball links and ultimately to make a list of available versions of
``libelf``.
@@ -907,7 +954,7 @@ when spidering the page.
.. _attribute_parallel:
-Parallel Builds
+Parallel builds
------------------
By default, Spack will invoke ``make()`` with a ``-j <njobs>``
@@ -1036,6 +1083,203 @@ command line to find installed packages or to install packages with
particular constraints, and package authors can use specs to describe
relationships between packages.
+.. _setup-dependent-environment:
+
+``setup_dependent_environment()``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Spack provides a mechanism for dependencies to provide variables that
+can be used in their dependents' build. Any package can declare a
+``setup_dependent_environment()`` function, and this function will be
+called before the ``install()`` method of any dependent packages.
+This allows dependencies to set up environment variables and other
+properties to be used by dependents.
+
+The funciton declaration should look like this:
+
+.. code-block:: python
+
+ class Qt(Package):
+ ...
+ def setup_dependent_environment(self, module, spec, dep_spec):
+ """Dependencies of Qt find it using the QTDIR environment variable."""
+ os.environ['QTDIR'] = self.prefix
+
+Here, the Qt package sets the ``QTDIR`` environment variable so that
+packages that depend on a particular Qt installation will find it.
+
+The arguments to this function are:
+
+ * **module**: the module of the dependent package, where global
+ properties can be assigned.
+ * **spec**: the spec of the *dependency package* (the one the function is called on).
+ * **dep_spec**: the spec of the dependent package (i.e. dep_spec depends on spec).
+
+A goo example of using these is in the Python packge:
+
+.. code-block:: python
+
+ def setup_dependent_environment(self, module, spec, dep_spec):
+ # Python extension builds can have a global python executable function
+ module.python = Executable(join_path(spec.prefix.bin, 'python'))
+
+ # Add variables for lib/pythonX.Y and lib/pythonX.Y/site-packages dirs.
+ module.python_lib_dir = os.path.join(dep_spec.prefix, self.python_lib_dir)
+ module.python_include_dir = os.path.join(dep_spec.prefix, self.python_include_dir)
+ module.site_packages_dir = os.path.join(dep_spec.prefix, self.site_packages_dir)
+
+ # Make the site packages directory if it does not exist already.
+ mkdirp(module.site_packages_dir)
+
+ # Set PYTHONPATH to include site-packages dir for the
+ # extension and any other python extensions it depends on.
+ python_paths = []
+ for d in dep_spec.traverse():
+ if d.package.extends(self.spec):
+ python_paths.append(os.path.join(d.prefix, self.site_packages_dir))
+ os.environ['PYTHONPATH'] = ':'.join(python_paths)
+
+The first thing that happens here is that the ``python`` command is
+inserted into module scope of the dependent. This allows most python
+packages to have a very simple install method, like this:
+
+.. code-block:: python
+
+ def install(self, spec, prefix):
+ python('setup.py', 'install', '--prefix=%s' % prefix)
+
+Python's ``setup_dependent_environment`` method also sets up smoe
+other variables, creates a directory, and sets up the ``PYTHONPATH``
+so that dependent packages can find their dependencies at build time.
+
+
+.. _packaging_extensions:
+
+Extensions
+-------------------------
+
+Spack's support for package extensions is documented extensively in
+:ref:`extensions`. This section documents how to make your own
+extendable packages and extensions.
+
+To support extensions, a package needs to set its ``extendable``
+property to ``True``, e.g.:
+
+.. code-block:: python
+
+ class Python(Package):
+ ...
+ extendable = True
+ ...
+
+To make a package into an extension, simply add simply add an
+``extends`` call in the package definition, and pass it the name of an
+extendable package:
+
+.. code-block:: python
+
+ class PyNumpy(Package):
+ ...
+ extends('python')
+ ...
+
+Now, the ``py-numpy`` package can be used as an argument to ``spack
+activate``. When it is activated, all the files in its prefix will be
+symbolically linked into the prefix of the python package.
+
+Sometimes, certain files in one package will conflict with those in
+another, which means they cannot both be activated (symlinked) at the
+same time. In this case, you can tell Spack to ignore those files
+when it does the activation:
+
+.. code-block:: python
+
+ class PyNose(Package):
+ ...
+ extends('python', ignore=r'bin/nosetests.*$')
+ ...
+
+The code above will prevent ``$prefix/bin/nosetests`` from being
+linked in at activation time.
+
+.. note::
+
+ You can call *either* ``depends_on`` or ``extends`` on any one
+ package, but not both. For example you cannot both
+ ``depends_on('python')`` and ``extends(python)`` in the same
+ package. ``extends`` implies ``depends_on``.
+
+
+
+Activation & deactivation
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Spack's ``Package`` class has default ``activate`` and ``deactivate``
+implementations that handle symbolically linking extensions' prefixes
+into the directory of the parent package. However, extendable
+packages can override these methdos to add custom activate/deactivate
+logic of their own. For example, the ``activate`` and ``deactivate``
+methods in the Python class use the symbolic linking, but they also
+handle details surrounding Python's ``.pth`` files, and other aspects
+of Python packaging.
+
+Spack's extensions mechanism is designed to be extensible, so that
+other packages (like Ruby, R, Perl, etc.) can provide their own
+custom extension management logic, as they may not handle modules the
+same way that Python does.
+
+Let's look at Python's activate function:
+
+.. code-block:: python
+
+ def activate(self, ext_pkg, **kwargs):
+ kwargs.update(ignore=self.python_ignore(ext_pkg, kwargs))
+ super(Python, self).activate(ext_pkg, **kwargs)
+
+ exts = spack.install_layout.extension_map(self.spec)
+ exts[ext_pkg.name] = ext_pkg.spec
+ self.write_easy_install_pth(exts)
+
+This function is called on the *extendee* (Python). It first calls
+``activate`` in the superclass, which handles symlinking the
+extension package's prefix into this package's prefix. It then does
+some special handling of the ``easy-install.pth`` file, part of
+Python's setuptools.
+
+Deactivate behaves similarly to activate, but it unlinks files:
+
+.. code-block:: python
+
+ def deactivate(self, ext_pkg, **kwargs):
+ kwargs.update(ignore=self.python_ignore(ext_pkg, kwargs))
+ super(Python, self).deactivate(ext_pkg, **kwargs)
+
+ exts = spack.install_layout.extension_map(self.spec)
+ if ext_pkg.name in exts: # Make deactivate idempotent.
+ del exts[ext_pkg.name]
+ self.write_easy_install_pth(exts)
+
+Both of these methods call some custom functions in the Python
+package. See the source for Spack's Python package for details.
+
+
+Activation arguments
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You may have noticed that the ``activate`` function defined above
+takes keyword arguments. These are the keyword arguments from
+``extends()``, and they are passed to both activate and deactivate.
+
+This capability allows an extension to customize its own activation by
+passing arguments to the extendee. Extendees can likewise implement
+custom ``activate()`` and ``deactivate()`` functions to suit their
+needs.
+
+The only keyword argument supported by default is the ``ignore``
+argument, which can take a regex, list of regexes, or a predicate to
+determine which files *not* to symlink during activation.
+
+
.. _virtual-dependencies:
Virtual dependencies
@@ -1257,6 +1501,7 @@ explicitly. Concretization policies are discussed in more detail in
:ref:`site-configuration`. Sites using Spack can customize them to
match the preferences of their own users.
+.. _spack-spec:
``spack spec``
~~~~~~~~~~~~~~~~~~~~
@@ -1354,7 +1599,7 @@ information.
.. _install-environment:
-The Install environment
+The install environment
--------------------------
In general, you should not have to do much differently in your install
@@ -1414,6 +1659,7 @@ easily:
``PATH`` Set to point to ``/bin`` directories of dpeendencies
``CMAKE_PREFIX_PATH`` Path to dependency prefixes for CMake
``PKG_CONFIG_PATH`` Path to any pkgconfig directories for dependencies
+ ``PYTHONPATH`` Path to site-packages dir of any python dependencies
======================= =============================
``PATH`` is set up to point to dependencies ``/bin`` directories so
@@ -1433,6 +1679,12 @@ dependencies using the GNU ``pkg-config`` tool. It is similar to
``CMAKE_PREFIX_PATH`` in that it allows a build to automatically
discover its dependencies.
+If you want to see the environment that a package will build with, or
+if you want to run commands in that environment to test them out, you
+can use the :ref:```spack env`` <spack-env>` command, documented
+below.
+
+.. _compiler-wrappers:
Compiler interceptors
~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1498,7 +1750,6 @@ process runs. Packages are free to change the environment or to
modify Spack internals, because each ``install()`` call has its own
dedicated process.
-
.. _prefix-objects:
Prefix objects
@@ -1970,7 +2221,7 @@ File functions
.. _pacakge-lifecycle:
-Package Workflow Commands
+Packaging workflow commands
---------------------------------
When you are building packages, you will likely not get things
@@ -2036,6 +2287,8 @@ this step if they have been. If Spack discovers that patches didn't
apply cleanly on some previous run, then it will restage the entire
package before patching.
+.. _spack-restage:
+
``spack restage``
~~~~~~~~~~~~~~~~~
Restores the source code to pristine state, as it was before building.
@@ -2048,6 +2301,7 @@ Does this in one of two ways:
2. If the source was checked out from a repository, this deletes the
build directory and checks it out again.
+.. _spack-clean:
``spack clean``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2057,6 +2311,8 @@ expanded/checked out source code *and* any downloaded archive. If
build process will start from scratch.
+.. _spack-purge:
+
``spack purge``
~~~~~~~~~~~~~~~~~
Cleans up all of Spack's temporary files. Use this to recover disk
@@ -2102,7 +2358,7 @@ to get rid of the install prefix before you build again:
spack uninstall -f <spec>
-Graphing Dependencies
+Graphing dependencies
--------------------------
.. _spack-graph:
@@ -2181,7 +2437,7 @@ example::
This graph can be provided as input to other graphing tools, such as
those in `Graphviz <http://www.graphviz.org>`_.
-Interactive Shell Support
+Interactive shell support
--------------------------
Spack provides some limited shell support to make life easier for
@@ -2197,6 +2453,7 @@ For ``csh`` and ``tcsh`` run:
``spack cd`` will then be available.
+.. _spack-cd:
``spack cd``
~~~~~~~~~~~~~~~~~
@@ -2227,6 +2484,35 @@ directory, install directory, package directory) and others change to
core spack locations. For example, ``spack cd -m`` will take you to
the main python source directory of your spack install.
+.. _spack-env:
+
+``spack env``
+~~~~~~~~~~~~~~~~~~~~~~
+
+``spack env`` functions much like the standard unix ``env`` command,
+but it takes a spec as an argument. You can use it to see the
+environment variables that will be set when a particular build runs,
+for example:
+
+.. code-block:: sh
+
+ $ spack env mpileaks@1.1%intel
+
+This will display the entire environment that will be set when the
+``mpileaks@1.1%intel`` build runs.
+
+To run commands in a package's build environment, you can simply provided them after the spec argument to ``spack env``:
+
+.. code-block:: sh
+
+ $ spack cd mpileaks@1.1%intel
+ $ spack env mpileaks@1.1%intel ./configure
+
+This will cd to the build directory and then run ``configure`` in the
+package's build environment.
+
+
+.. _spack-location:
``spack location``
~~~~~~~~~~~~~~~~~~~~~~