Skip to content
Snippets Groups Projects
Commit daef78f5 authored by Todd Gamblin's avatar Todd Gamblin
Browse files

Update packaging documentataion.

parent 5699cbb5
No related branches found
No related tags found
No related merge requests found
...@@ -16,16 +16,17 @@ There are two key parts of Spack: ...@@ -16,16 +16,17 @@ There are two key parts of Spack:
software according to a spec. software according to a spec.
Specs allow a user to describe a *particular* build in a way that a Specs allow a user to describe a *particular* build in a way that a
package author can understand. Packages allow a developer to package author can understand. Packages allow a the packager to
encapsulate the logic build logic for different versions, compilers, encapsulate the build logic for different versions, compilers,
options, platforms, and dependency combinations in one place. options, platforms, and dependency combinations in one place.
Essentially, a package translates a spec into build logic.
Packages in Spack are written in pure Python, so you can do anything Packages in Spack are written in pure Python, so you can do anything
in Spack that you can do in Python. Python was chosen as the in Spack that you can do in Python. Python was chosen as the
implementation language for two reasons. First, Python is becoming implementation language for two reasons. First, Python is becoming
ubiquitous in the HPC community due to its use in numerical codes. ubiquitous in the scientific software community. Second, it's a modern
Second, it's a modern language and has many powerful features to help language and has many powerful features to help make package writing
make package writing easy. easy.
Creating & Editing Packages Creating & Editing Packages
---------------------------------- ----------------------------------
...@@ -35,24 +36,23 @@ Creating & Editing Packages ...@@ -35,24 +36,23 @@ Creating & Editing Packages
``spack create`` ``spack create``
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
The ``spack create`` command generates boilerplate package template The ``spack create`` command generates a boilerplate package template
from a URL pointing to a tarball or other software archive. In most from a URL. The URL should point to a tarball or other software
cases, you'll only need to run this once, then slightly modify the archive. In most cases, ``spack create`` plus a few modifications is
boilerplate to get your package working. all you need to get a package working.
All you need is the URL to a tarball (other archive formats are ok Here's an example:
too) you want to package:
.. code-block:: sh .. code-block:: sh
$ spack create http://www.cmake.org/files/v2.8/cmake-2.8.12.1.tar.gz $ spack create http://www.cmake.org/files/v2.8/cmake-2.8.12.1.tar.gz
When you run this, Spack looks at the tarball URL and tries to figure Spack examines the tarball URL and tries to figure out the name of the
out the name of the package to be created. It also tries to determine package to be created. It also tries to determine what version strings
out what version strings look like for this package. Using this look like for this package. Using this information, it will try to
information, it tries to find *additional* versions by spidering the find *additional* versions by spidering the package's webpage. If it
package's webpage. If it finds multiple versions, Spack prompts you finds multiple versions, Spack prompts you to tell it how many
to tell it how many versions you want to download and checksum. versions you want to download and checksum:
.. code-block:: sh .. code-block:: sh
...@@ -63,12 +63,6 @@ to tell it how many versions you want to download and checksum. ...@@ -63,12 +63,6 @@ to tell it how many versions you want to download and checksum.
2.8.12.1 http://www.cmake.org/files/v2.8/cmake-2.8.12.1.tar.gz 2.8.12.1 http://www.cmake.org/files/v2.8/cmake-2.8.12.1.tar.gz
2.8.12 http://www.cmake.org/files/v2.8/cmake-2.8.12.tar.gz 2.8.12 http://www.cmake.org/files/v2.8/cmake-2.8.12.tar.gz
2.8.11.2 http://www.cmake.org/files/v2.8/cmake-2.8.11.2.tar.gz 2.8.11.2 http://www.cmake.org/files/v2.8/cmake-2.8.11.2.tar.gz
2.8.11.1 http://www.cmake.org/files/v2.8/cmake-2.8.11.1.tar.gz
2.8.11 http://www.cmake.org/files/v2.8/cmake-2.8.11.tar.gz
2.8.10.2 http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
2.8.10.1 http://www.cmake.org/files/v2.8/cmake-2.8.10.1.tar.gz
2.8.10 http://www.cmake.org/files/v2.8/cmake-2.8.10.tar.gz
2.8.9 http://www.cmake.org/files/v2.8/cmake-2.8.9.tar.gz
... ...
2.8.0 http://www.cmake.org/files/v2.8/cmake-2.8.0.tar.gz 2.8.0 http://www.cmake.org/files/v2.8/cmake-2.8.0.tar.gz
...@@ -77,10 +71,30 @@ to tell it how many versions you want to download and checksum. ...@@ -77,10 +71,30 @@ to tell it how many versions you want to download and checksum.
Spack will automatically download the number of tarballs you specify Spack will automatically download the number of tarballs you specify
(starting with the most recent) and checksum each of them. (starting with the most recent) and checksum each of them.
Note that you don't need to do everything up front. If your package You do not *have* to download all of the versions up front. You can
is large, you can always choose to download just one tarball for now, always choose to download just one tarball initially, and run
then run :ref:`spack checksum <spack-checksum>` later if you end up :ref:`spack checksum <spack-checksum>` later if you need more.
wanting more. Let's say you choose to download 3 tarballs:
.. note::
If ``spack create`` fails to detect the package name correctly,
you can try supplying it yourself, e.g.::
$ spack create --name cmake http://www.cmake.org/files/v2.8/cmake-2.8.12.1.tar.gz
If it fails entirely, you can get minimal boilerplate by using
:ref:`spack-edit-f`, or you can manually create a directory and
``package.py`` file for the package in ``var/spack/packages``.
.. note::
Spack can fetch packages from source code repositories, but,
``spack create`` will *not* currently create a boilerplate package
from a repository URL. You will need to use :ref:`spack-edit-f`
and manually edit the ``version()`` directives to fetch from a
repo. See :ref:`vcs-fetch` for details.
Let's say you download 3 tarballs:
.. code-block:: sh .. code-block:: sh
...@@ -93,8 +107,8 @@ wanting more. Let's say you choose to download 3 tarballs: ...@@ -93,8 +107,8 @@ wanting more. Let's say you choose to download 3 tarballs:
==> Fetching http://www.cmake.org/files/v2.8/cmake-2.8.11.2.tar.gz ==> Fetching http://www.cmake.org/files/v2.8/cmake-2.8.11.2.tar.gz
#################################################################### 95.2% #################################################################### 95.2%
Now Spack generates boilerplate code and opens the new Now Spack generates boilerplate code and opens a new ``package.py``
``package.py`` file in your favorite ``$EDITOR``: file in your favorite ``$EDITOR``:
.. code-block:: python .. code-block:: python
:linenos: :linenos:
...@@ -141,12 +155,6 @@ Now Spack generates boilerplate code and opens the new ...@@ -141,12 +155,6 @@ Now Spack generates boilerplate code and opens the new
The tedious stuff (creating the class, checksumming archives) has been The tedious stuff (creating the class, checksumming archives) has been
done for you. done for you.
.. note::
If ``spack create`` fails to download or to detect the package
version, you can use ``spack edit -f`` to generate simpler
boilerplate. See the next section for more on this.
In the generated package, the download ``url`` attribute is already In the generated package, the download ``url`` attribute is already
set. All the things you still need to change are marked with set. All the things you still need to change are marked with
``FIXME`` labels. The first ``FIXME`` refers to the commented ``FIXME`` labels. The first ``FIXME`` refers to the commented
...@@ -199,27 +207,30 @@ The ``cmake`` package actually lives in ...@@ -199,27 +207,30 @@ The ``cmake`` package actually lives in
a much simpler shortcut and saves you the trouble of typing the full a much simpler shortcut and saves you the trouble of typing the full
path. path.
``spack edit -f``
~~~~~~~~~~~~~~~~~~~~
If you try to edit a package that doesn't exist, Spack will recommend If you try to edit a package that doesn't exist, Spack will recommend
using ``spack create``: using ``spack create`` or ``spack edit -f``:
.. code-block:: sh .. code-block:: sh
$ spack edit foo $ spack edit foo
==> Error: No package 'foo'. Use spack create, or supply -f/--force to edit a new file. ==> Error: No package 'foo'. Use spack create, or supply -f/--force to edit a new file.
As the output advises, You can use ``spack edit -f/--force`` to force .. _spack-edit-f:
the creation of a new, *very* simple boilerplate package:
``spack edit -f``
~~~~~~~~~~~~~~~~~~~~
``spack edit -f`` can be used to create a new, minimal boilerplate
package:
.. code-block:: sh .. code-block:: sh
$ spack edit -f foo $ spack edit -f foo
Unlike ``spack create``, which tries to infer names and versions, and Unlike ``spack create``, which infers names and versions, and which
which actually downloads the tarball and checksums it for you, ``spack actually downloads the tarball and checksums it for you, ``spack edit
edit -f`` will substitute dummy values for you to fill in yourself: -f`` has no such fanciness. It will substitute dummy values for you
to fill in yourself:
.. code-block:: python .. code-block:: python
:linenos: :linenos:
...@@ -246,6 +257,13 @@ version of your package from the archive URL. ...@@ -246,6 +257,13 @@ version of your package from the archive URL.
Naming & Directory Structure Naming & Directory Structure
-------------------------------------- --------------------------------------
.. note::
Spack's default naming and directory structure will change in
version 0.9. Specifically, 0.9 will stop using directory names
with special characters like ``@``, to avoid interfering with
certain packages that do not handle this well.
This section describes how packages need to be named, and where they This section describes how packages need to be named, and where they
live in Spack's directory structure. In general, `spack-create`_ and live in Spack's directory structure. In general, `spack-create`_ and
`spack-edit`_ handle creating package files for you, so you can skip `spack-edit`_ handle creating package files for you, so you can skip
...@@ -264,6 +282,7 @@ package: ...@@ -264,6 +282,7 @@ package:
.. command-output:: cd $SPACK_ROOT/var/spack/packages; ls -CF .. command-output:: cd $SPACK_ROOT/var/spack/packages; ls -CF
:shell: :shell:
:ellipsis: 10
Each directory contains a file called ``package.py``, which is where Each directory contains a file called ``package.py``, which is where
all the python code for the package goes. For example, the ``libelf`` all the python code for the package goes. For example, the ``libelf``
...@@ -280,11 +299,9 @@ Package Names ...@@ -280,11 +299,9 @@ Package Names
Packages are named after the directory containing ``package.py``. So, Packages are named after the directory containing ``package.py``. So,
``libelf``'s ``package.py`` lives in a directory called ``libelf``. ``libelf``'s ``package.py`` lives in a directory called ``libelf``.
The ``package.py`` file contains a class called ``Libelf``, which The ``package.py`` file defines a class called ``Libelf``, which
extends Spack's ``Package`` class. This is what makes it a Spack extends Spack's ``Package`` class. for example, here is
package: ``$SPACK_ROOT/var/spack/packages/libelf/package.py``:
``var/spack/packages/libelf/package.py``
.. code-block:: python .. code-block:: python
:linenos: :linenos:
...@@ -301,8 +318,9 @@ package: ...@@ -301,8 +318,9 @@ package:
def install(): def install():
... ...
The **directory name** (``libelf``) is what users need to provide on The **directory name** (``libelf``) determines the package name that
the command line. e.g., if you type any of these: users should provide on the command line. e.g., if you type any of
these:
.. code-block:: sh .. code-block:: sh
...@@ -311,8 +329,8 @@ the command line. e.g., if you type any of these: ...@@ -311,8 +329,8 @@ the command line. e.g., if you type any of these:
Spack sees the package name in the spec and looks for Spack sees the package name in the spec and looks for
``libelf/package.py`` in ``var/spack/packages``. Likewise, if you say ``libelf/package.py`` in ``var/spack/packages``. Likewise, if you say
``spack install docbook-xml``, then Spack looks for ``spack install py-numpy``, then Spack looks for
``docbook-xml/package.py``. ``py-numpy/package.py``.
Spack uses the directory name as the package name in order to give Spack uses the directory name as the package name in order to give
packagers more freedom in naming their packages. Package names can packagers more freedom in naming their packages. Package names can
...@@ -342,8 +360,7 @@ some examples: ...@@ -342,8 +360,7 @@ some examples:
================= ================= ================= =================
In general, you won't have to remember this naming convention because In general, you won't have to remember this naming convention because
`spack-create`_ and `spack-edit`_ will generate boilerplate for you, `spack-create`_ and `spack-edit`_ handle the details for you.
and you can just fill in the blanks.
Adding new versions Adding new versions
...@@ -381,9 +398,8 @@ For the URL above, you might have to add an explicit URL because the ...@@ -381,9 +398,8 @@ For the URL above, you might have to add an explicit URL because the
version can't simply be substituted in the original ``url`` to version can't simply be substituted in the original ``url`` to
construct the new one for ``8.2.1``. construct the new one for ``8.2.1``.
Wehn you supply a custom URL for a version, Spack uses that URL When you supply a custom URL for a version, Spack uses that URL
*verbatim* when fetching the version, and will *not* perform *verbatim* and does not perform extrapolation.
extrapolation.
Checksums Checksums
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
...@@ -392,10 +408,11 @@ Spack uses a checksum to ensure that the downloaded package version is ...@@ -392,10 +408,11 @@ Spack uses a checksum to ensure that the downloaded package version is
not corrupted or compromised. This is especially important when not corrupted or compromised. This is especially important when
fetching from insecure sources, like unencrypted http. By default, a fetching from insecure sources, like unencrypted http. By default, a
package will *not* be installed if it doesn't pass a checksum test package will *not* be installed if it doesn't pass a checksum test
(though users can overried this with ``spack install --no-checksum``). (though you can override this with ``spack install --no-checksum``).
Spack can currently support checksums using the MD5, SHA-1, SHA-224, Spack can currently support checksums using the MD5, SHA-1, SHA-224,
SHA-256, SHA-384, and SHA-512 algorithms. SHA-256, SHA-384, and SHA-512 algorithms. It determines the algorithm
to use based on the hash length.
``spack md5`` ``spack md5``
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
...@@ -459,16 +476,18 @@ By default, Spack will search for new tarball downloads by scraping ...@@ -459,16 +476,18 @@ By default, Spack will search for new tarball downloads by scraping
the parent directory of the tarball you gave it. So, if your tarball the parent directory of the tarball you gave it. So, if your tarball
is at ``http://example.com/downloads/foo-1.0.tar.gz``, Spack will look is at ``http://example.com/downloads/foo-1.0.tar.gz``, Spack will look
in ``http://example.com/downloads/`` for links to additional versions. in ``http://example.com/downloads/`` for links to additional versions.
If you need to search another path for download links, see the If you need to search another path for download links, you can supply
reference documentation on `attribute_list_url`_ and some extra attributes that control how your package finds new
versions. See the documentation on `attribute_list_url`_ and
`attributee_list_depth`_. `attributee_list_depth`_.
.. note:: .. note::
* This command assumes that Spack can extrapolate new URLs from an * This command assumes that Spack can extrapolate new URLs from an
existing URL in the package, and that Spack can find similar URLs existing URL in the package, and that Spack can find similar URLs
on a webpage. If that's not possible, you'll need to manually add on a webpage. If that's not possible, e.g. if the package's
``version`` calls yourself. developers don't name their tarballs consistently, you'll need to
manually add ``version`` calls yourself.
* For ``spack checksum`` to work, Spack needs to be able to * For ``spack checksum`` to work, Spack needs to be able to
``import`` your pacakge in Python. That means it can't have any ``import`` your pacakge in Python. That means it can't have any
...@@ -481,32 +500,33 @@ reference documentation on `attribute_list_url`_ and ...@@ -481,32 +500,33 @@ reference documentation on `attribute_list_url`_ and
Fetching from VCS Repositories Fetching from VCS Repositories
-------------------------------------- --------------------------------------
For some packages, source code is hosted in a Version Control System For some packages, source code is provided in a Version Control System
(VCS) repository rather than as a tarball. Packages can be set up to (VCS) repository rather than in a tarball. Spack can fetch packages
fetch from a repository instead of a tarball. Currently, Spack from VCS repositories. Currently, Spack supports fetching with `Git
supports fetching with `Git <git-fetch_>`_, `Mercurial (hg) <git-fetch_>`_, `Mercurial (hg) <hg-fetch_>`_, and `Subversion (SVN)
<hg-fetch_>`_, and `Subversion (SVN) <svn-fetch_>`_. <svn-fetch_>`_.
To fetch a package from a source repository, you add a ``version()`` To fetch a package from a source repository, you add a ``version()``
call to your package with parameters indicating the repository URL and call to your package with parameters indicating the repository URL and
any branch, tag, or revision to fetch. See below for the paramters any branch, tag, or revision to fetch. See below for the parameters
you'll need for each VCS system. you'll need for each VCS system.
Repositories and versions Repositories and versions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The package author is responsible for coming up with a sensible name The package author is responsible for coming up with a sensible name
for each version. For example, if you're fetching from a tag like for each version to be fetched from a repository. For example, if
``v1.0``, you might call that ``1.0``. If you're fetching a nameless you're fetching from a tag like ``v1.0``, you might call that ``1.0``.
git commit or an older subversion revision, you might give the commit If you're fetching a nameless git commit or an older subversion
an intuitive name, like ``dev`` for a development version, or revision, you might give the commit an intuitive name, like ``dev``
``some-fancy-new-feature`` if you want to be more specific. for a development version, or ``some-fancy-new-feature`` if you want
to be more specific.
In general, it's recommended to fetch tags or particular In general, it's recommended to fetch tags or particular
commits/revisions, NOT branches or the repository mainline, as commits/revisions, NOT branches or the repository mainline, as
branches move forward over time and you aren't guaranteed to get the branches move forward over time and you aren't guaranteed to get the
same thing every time you fetch a particular version. Life isn't same thing every time you fetch a particular version. Life isn't
simple, though, so this is not strictly enforced. always simple, though, so this is not strictly enforced.
In some future release, Spack may support extrapolating repository In some future release, Spack may support extrapolating repository
versions as it does for tarball URLs, but currently this is not versions as it does for tarball URLs, but currently this is not
...@@ -633,7 +653,7 @@ Subversion ...@@ -633,7 +653,7 @@ Subversion
To fetch with subversion, use the ``svn`` and ``revision`` parameters: To fetch with subversion, use the ``svn`` and ``revision`` parameters:
Head Fetching the head
Simply add an ``svn`` parameter to ``version``: Simply add an ``svn`` parameter to ``version``:
.. code-block:: python .. code-block:: python
...@@ -642,7 +662,7 @@ Head ...@@ -642,7 +662,7 @@ Head
This is not recommended, as the head will move forward over time. This is not recommended, as the head will move forward over time.
Revisions Fetching a revision
To fetch a particular revision, add a ``revision`` to the To fetch a particular revision, add a ``revision`` to the
version call: version call:
...@@ -746,6 +766,53 @@ from the URL and then applied to your source code. ...@@ -746,6 +766,53 @@ from the URL and then applied to your source code.
applies cleanly with ``-p1``, but if you're using a patch you didn't applies cleanly with ``-p1``, but if you're using a patch you didn't
create yourself, ``level`` can be handy. create yourself, ``level`` can be handy.
``patch()`` functions
~~~~~~~~~~~~~~~~~~~~~~~~
In addition to supplying patch files, you can write a custom function
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``:
.. code-block:: python
:linenos:
class PyPyside(Package):
...
def patch(self):
"""Undo PySide RPATH handling and add Spack RPATH."""
# Figure out the special RPATH
pypkg = self.spec['python'].package
rpath = self.rpath
rpath.append(os.path.join(self.prefix, pypkg.site_packages_dir, 'PySide'))
# Add Spack's standard CMake args to the sub-builds.
# They're called BY setup.py so we have to patch it.
filter_file(
r'OPTION_CMAKE,',
r'OPTION_CMAKE, ' + (
'"-DCMAKE_INSTALL_RPATH_USE_LINK_PATH=FALSE", '
'"-DCMAKE_INSTALL_RPATH=%s",' % ':'.join(rpath)),
'setup.py')
# PySide tries to patch ELF files to remove RPATHs
# Disable this and go with the one we set.
filter_file(
r'^\s*rpath_cmd\(pyside_path, srcpath\)',
r'#rpath_cmd(pyside_path, srcpath)',
'pyside_postinstall.py')
A ``patch`` function, if present, will be run after patch files are
applied and before ``install()`` is run.
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 ..
Finding Package Downloads Finding Package Downloads
---------------------------- ----------------------------
...@@ -1932,6 +1999,8 @@ A typical package workflow might look like this: ...@@ -1932,6 +1999,8 @@ A typical package workflow might look like this:
Below are some commands that will allow you some finer-grained Below are some commands that will allow you some finer-grained
controll over the install process. controll over the install process.
.. _spack-fetch:
``spack fetch`` ``spack fetch``
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
...@@ -1944,6 +2013,8 @@ directory will be located under ``$SPACK_HOME/var/spack``. ...@@ -1944,6 +2013,8 @@ directory will be located under ``$SPACK_HOME/var/spack``.
When run after the archive has already been downloaded, ``spack When run after the archive has already been downloaded, ``spack
fetch`` is idempotent and will not download the archive again. fetch`` is idempotent and will not download the archive again.
.. _spack-stage:
``spack stage`` ``spack stage``
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
...@@ -1952,6 +2023,8 @@ the downloaded archive in its temporary directory, where it will be ...@@ -1952,6 +2023,8 @@ the downloaded archive in its temporary directory, where it will be
built by ``spack install``. Similar to ``fetch``, if the archive has built by ``spack install``. Similar to ``fetch``, if the archive has
already been expanded, ``stage`` is idempotent. already been expanded, ``stage`` is idempotent.
.. _spack-patch:
``spack patch`` ``spack patch``
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
...@@ -1963,7 +2036,6 @@ this step if they have been. If Spack discovers that patches didn't ...@@ -1963,7 +2036,6 @@ 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 apply cleanly on some previous run, then it will restage the entire
package before patching. package before patching.
``spack clean`` ``spack clean``
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
...@@ -2035,6 +2107,11 @@ to get rid of the install prefix before you build again: ...@@ -2035,6 +2107,11 @@ to get rid of the install prefix before you build again:
Graphing Dependencies Graphing Dependencies
-------------------------- --------------------------
.. _spack-graph:
``spack graph``
~~~~~~~~~~~~~~~~~~~
Spack provides the ``spack graph`` command for graphing dependencies. Spack provides the ``spack graph`` command for graphing dependencies.
The command by default generates an ASCII rendering of a spec's The command by default generates an ASCII rendering of a spec's
dependency graph. For example:: dependency graph. For example::
......
...@@ -43,5 +43,3 @@ def install(self, spec, prefix): ...@@ -43,5 +43,3 @@ def install(self, spec, prefix):
python('setup.py', 'install', python('setup.py', 'install',
'--prefix=%s' % prefix, '--prefix=%s' % prefix,
'--jobs=%s' % make_jobs) '--jobs=%s' % make_jobs)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment