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
|
# License along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
"""
|
"""This is where most of the action happens in Spack.
|
||||||
This is where most of the action happens in Spack.
|
|
||||||
See the Package docs for detailed instructions on how the class works
|
The spack package class structure is based strongly on Homebrew
|
||||||
and on how to write your own packages.
|
(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 base64
|
||||||
import contextlib
|
import contextlib
|
||||||
@ -313,209 +309,39 @@ class PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)):
|
|||||||
|
|
||||||
***The Package class***
|
***The Package class***
|
||||||
|
|
||||||
Package is where the bulk of the work of installing packages is done.
|
A package defines how to fetch, verify (via, e.g., sha256), build,
|
||||||
|
and install a piece of software. A Package also defines what other
|
||||||
A package defines how to fetch, verfiy (via, e.g., md5), build, and
|
|
||||||
install a piece of software. A Package also defines what other
|
|
||||||
packages it depends on, so that dependencies can be installed along
|
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
|
There are two main parts of a Spack package:
|
||||||
in ``$prefix``, all of its built-in package files are in the builtin
|
|
||||||
repo at ``$prefix/var/spack/repos/builtin/packages``.
|
|
||||||
|
|
||||||
All you have to do to create a package is make a new subclass of Package
|
1. **The package class**. Classes contain ``directives``, which are
|
||||||
in this directory. Spack automatically scans the python files there
|
special functions, that add metadata (versions, patches,
|
||||||
and figures out which one to import when you invoke it.
|
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
|
Packages are imported from repos (see ``repo.py``).
|
||||||
``$prefix/var/spack/repos/builtin/packages/cmake/package.py``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
**Package DSL**
|
||||||
|
|
||||||
from spack import *
|
Look in ``lib/spack/docs`` or check https://spack.readthedocs.io for
|
||||||
class Cmake(Package):
|
the full documentation of the package domain-specific language. That
|
||||||
homepage = 'https://www.cmake.org'
|
used to be partially documented here, but as it grew, the docs here
|
||||||
url = 'http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz'
|
became increasingly out of date.
|
||||||
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)
|
|
||||||
|
|
||||||
**Package Lifecycle**
|
**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:
|
A package's lifecycle over a run of Spack looks something like this:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@ -541,8 +367,14 @@ class SomePackage(Package):
|
|||||||
package writers to override, and doing so may break the functionality
|
package writers to override, and doing so may break the functionality
|
||||||
of the Package class.
|
of the Package class.
|
||||||
|
|
||||||
Package creators override functions like install() (all of them do this),
|
Package creators have a lot of freedom, and they could technically
|
||||||
clean() (some of them do this), and others to provide custom behavior.
|
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