docs: update old docs for spack.package.PackageBase
- There was a lot of documentation in `PackageBase` dating back to the very first versions of Spack. - It was repetitive and out of date, and the docs at spack.readthedocs.io are better. - Remove the outdated specifics, and leave the minimal useful set of developer docs in `package.py`.
This commit is contained in:
parent
bd3ffc7b76
commit
d4c4effb5e
@ -22,16 +22,12 @@
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
"""
|
||||
This is where most of the action happens in Spack.
|
||||
See the Package docs for detailed instructions on how the class works
|
||||
and on how to write your own packages.
|
||||
"""This is where most of the action happens in Spack.
|
||||
|
||||
The spack package class structure is based strongly on Homebrew
|
||||
(http://brew.sh/), mainly because Homebrew makes it very easy to create
|
||||
packages.
|
||||
|
||||
The spack package structure is based strongly on Homebrew
|
||||
(http://wiki.github.com/mxcl/homebrew/), mainly because
|
||||
Homebrew makes it very easy to create packages. For a complete
|
||||
rundown on spack and how it differs from homebrew, look at the
|
||||
README.
|
||||
"""
|
||||
import base64
|
||||
import contextlib
|
||||
@ -313,209 +309,39 @@ class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)):
|
||||
|
||||
***The Package class***
|
||||
|
||||
Package is where the bulk of the work of installing packages is done.
|
||||
|
||||
A package defines how to fetch, verfiy (via, e.g., md5), build, and
|
||||
install a piece of software. A Package also defines what other
|
||||
A package defines how to fetch, verify (via, e.g., sha256), build,
|
||||
and install a piece of software. A Package also defines what other
|
||||
packages it depends on, so that dependencies can be installed along
|
||||
with the package itself. Packages are written in pure python.
|
||||
with the package itself. Packages are written in pure python by
|
||||
users of Spack.
|
||||
|
||||
Packages live in repositories (see repo.py). If spack is installed
|
||||
in ``$prefix``, all of its built-in package files are in the builtin
|
||||
repo at ``$prefix/var/spack/repos/builtin/packages``.
|
||||
There are two main parts of a Spack package:
|
||||
|
||||
All you have to do to create a package is make a new subclass of Package
|
||||
in this directory. Spack automatically scans the python files there
|
||||
and figures out which one to import when you invoke it.
|
||||
1. **The package class**. Classes contain ``directives``, which are
|
||||
special functions, that add metadata (versions, patches,
|
||||
dependencies, and other information) to packages (see
|
||||
``directives.py``). Directives provide the constraints that are
|
||||
used as input to the concretizer.
|
||||
|
||||
**An example package**
|
||||
2. **Package instances**. Once instantiated, a package is
|
||||
essentially an installer for a particular piece of
|
||||
software. Spack calls methods like ``do_install()`` on the
|
||||
``Package`` object, and it uses those to drive user-implemented
|
||||
methods like ``patch()``, ``install()``, and other build steps.
|
||||
To install software, An instantiated package needs a *concrete*
|
||||
spec, which guides the behavior of the various install methods.
|
||||
|
||||
Let's look at the cmake package to start with. This package lives in
|
||||
``$prefix/var/spack/repos/builtin/packages/cmake/package.py``:
|
||||
Packages are imported from repos (see ``repo.py``).
|
||||
|
||||
.. code-block:: python
|
||||
**Package DSL**
|
||||
|
||||
from spack import *
|
||||
class Cmake(Package):
|
||||
homepage = 'https://www.cmake.org'
|
||||
url = 'http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz'
|
||||
md5 = '097278785da7182ec0aea8769d06860c'
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure('--prefix=%s' % prefix,
|
||||
'--parallel=%s' % make_jobs)
|
||||
make()
|
||||
make('install')
|
||||
|
||||
**Naming conventions**
|
||||
|
||||
There are two names you should care about:
|
||||
|
||||
1. The module name, ``cmake``.
|
||||
|
||||
* User will refers to this name, e.g. 'spack install cmake'.
|
||||
* It can include ``_``, ``-``, and numbers (it can even start with a
|
||||
number).
|
||||
|
||||
2. The class name, "Cmake". This is formed by converting `-` or
|
||||
``_`` in the module name to camel case. If the name starts with
|
||||
a number, we prefix the class name with ``_``. Examples:
|
||||
|
||||
=========== ==========
|
||||
Module Name Class Name
|
||||
=========== ==========
|
||||
foo_bar FooBar
|
||||
docbook-xml DocbookXml
|
||||
FooBar Foobar
|
||||
3proxy _3proxy
|
||||
=========== ==========
|
||||
|
||||
The class name is what spack looks for when it loads a package module.
|
||||
|
||||
**Required Attributes**
|
||||
|
||||
Aside from proper naming, here is the bare minimum set of things you
|
||||
need when you make a package:
|
||||
|
||||
homepage:
|
||||
informational URL, so that users know what they're
|
||||
installing.
|
||||
|
||||
url or url_for_version(self, version):
|
||||
If url, then the URL of the source archive that spack will fetch.
|
||||
If url_for_version(), then a method returning the URL required
|
||||
to fetch a particular version.
|
||||
|
||||
install():
|
||||
This function tells spack how to build and install the
|
||||
software it downloaded.
|
||||
|
||||
**Optional Attributes**
|
||||
|
||||
You can also optionally add these attributes, if needed:
|
||||
|
||||
list_url:
|
||||
Webpage to scrape for available version strings. Default is the
|
||||
directory containing the tarball; use this if the default isn't
|
||||
correct so that invoking 'spack versions' will work for this
|
||||
package.
|
||||
|
||||
url_version(self, version):
|
||||
When spack downloads packages at particular versions, it just
|
||||
converts version to string with str(version). Override this if
|
||||
your package needs special version formatting in its URL. boost
|
||||
is an example of a package that needs this.
|
||||
|
||||
***Creating Packages***
|
||||
|
||||
As a package creator, you can probably ignore most of the preceding
|
||||
information, because you can use the 'spack create' command to do it
|
||||
all automatically.
|
||||
|
||||
You as the package creator generally only have to worry about writing
|
||||
your install function and specifying dependencies.
|
||||
|
||||
**spack create**
|
||||
|
||||
Most software comes in nicely packaged tarballs, like this one
|
||||
|
||||
http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
|
||||
|
||||
Taking a page from homebrew, spack deduces pretty much everything it
|
||||
needs to know from the URL above. If you simply type this::
|
||||
|
||||
spack create http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
|
||||
|
||||
Spack will download the tarball, generate an md5 hash, figure out the
|
||||
version and the name of the package from the URL, and create a new
|
||||
package file for you with all the names and attributes set correctly.
|
||||
|
||||
Once this skeleton code is generated, spack pops up the new package in
|
||||
your $EDITOR so that you can modify the parts that need changes.
|
||||
|
||||
**Dependencies**
|
||||
|
||||
If your package requires another in order to build, you can specify that
|
||||
like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class Stackwalker(Package):
|
||||
...
|
||||
depends_on("libdwarf")
|
||||
...
|
||||
|
||||
This tells spack that before it builds stackwalker, it needs to build
|
||||
the libdwarf package as well. Note that this is the module name, not
|
||||
the class name (The class name is really only used by spack to find
|
||||
your package).
|
||||
|
||||
Spack will download and install each dependency before it installs your
|
||||
package. In addtion, it will add -L, -I, and rpath arguments to your
|
||||
compiler and linker for each dependency. In most cases, this allows you
|
||||
to avoid specifying any dependencies in your configure or cmake line;
|
||||
you can just run configure or cmake without any additional arguments and
|
||||
it will find the dependencies automatically.
|
||||
|
||||
**The Install Function**
|
||||
|
||||
The install function is designed so that someone not too terribly familiar
|
||||
with Python could write a package installer. For example, we put a number
|
||||
of commands in install scope that you can use almost like shell commands.
|
||||
These include make, configure, cmake, rm, rmtree, mkdir, mkdirp, and
|
||||
others.
|
||||
|
||||
You can see above in the cmake script that these commands are used to run
|
||||
configure and make almost like they're used on the command line. The
|
||||
only difference is that they are python function calls and not shell
|
||||
commands.
|
||||
|
||||
It may be puzzling to you where the commands and functions in install live.
|
||||
They are NOT instance variables on the class; this would require us to
|
||||
type 'self.' all the time and it makes the install code unnecessarily long.
|
||||
Rather, spack puts these commands and variables in *module* scope for your
|
||||
Package subclass. Since each package has its own module, this doesn't
|
||||
pollute other namespaces, and it allows you to more easily implement an
|
||||
install function.
|
||||
|
||||
For a full list of commands and variables available in module scope, see
|
||||
the add_commands_to_module() function in this class. This is where most
|
||||
of them are created and set on the module.
|
||||
|
||||
**Parallel Builds**
|
||||
|
||||
By default, Spack will run make in parallel when you run make() in your
|
||||
install function. Spack figures out how many cores are available on
|
||||
your system and runs make with -j<cores>. If you do not want this
|
||||
behavior, you can explicitly mark a package not to use parallel make:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class SomePackage(Package):
|
||||
...
|
||||
parallel = False
|
||||
...
|
||||
|
||||
This changes the default behavior so that make is sequential. If you still
|
||||
want to build some parts in parallel, you can do this in your install
|
||||
function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
make(parallel=True)
|
||||
|
||||
Likewise, if you do not supply parallel = True in your Package, you can
|
||||
keep the default parallel behavior and run make like this when you want a
|
||||
sequential build:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
make(parallel=False)
|
||||
Look in ``lib/spack/docs`` or check https://spack.readthedocs.io for
|
||||
the full documentation of the package domain-specific language. That
|
||||
used to be partially documented here, but as it grew, the docs here
|
||||
became increasingly out of date.
|
||||
|
||||
**Package Lifecycle**
|
||||
|
||||
This section is really only for developers of new spack commands.
|
||||
|
||||
A package's lifecycle over a run of Spack looks something like this:
|
||||
|
||||
.. code-block:: python
|
||||
@ -541,8 +367,14 @@ class SomePackage(Package):
|
||||
package writers to override, and doing so may break the functionality
|
||||
of the Package class.
|
||||
|
||||
Package creators override functions like install() (all of them do this),
|
||||
clean() (some of them do this), and others to provide custom behavior.
|
||||
Package creators have a lot of freedom, and they could technically
|
||||
override anything in this class. That is not usually required.
|
||||
|
||||
For most use cases. Package creators typically just add attributes
|
||||
like ``url`` and ``homepage``, or functions like ``install()``.
|
||||
There are many custom ``Package`` subclasses in the
|
||||
``spack.build_systems`` package that make things even easier for
|
||||
specific build systems.
|
||||
|
||||
"""
|
||||
#
|
||||
|
Loading…
Reference in New Issue
Block a user