diff options
-rw-r--r-- | lib/spack/spack/package.py | 242 |
1 files changed, 37 insertions, 205 deletions
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py index 75aed2e899..3b4c5fa394 100644 --- a/lib/spack/spack/package.py +++ b/lib/spack/spack/package.py @@ -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. - -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. +"""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. + """ 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. - - 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``. - - 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. - - **An example package** - - Let's look at the cmake package to start with. This package lives in - ``$prefix/var/spack/repos/builtin/packages/cmake/package.py``: - - .. code-block:: python - - 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** + with the package itself. Packages are written in pure python by + users of Spack. - You can also optionally add these attributes, if needed: + There are two main parts of a Spack package: - 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. + 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. - 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. + 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. - ***Creating Packages*** + Packages are imported from repos (see ``repo.py``). - 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. + **Package DSL** - 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 PackageBase(with_metaclass(PackageMeta, PackageViewMixin, object)): 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. """ # |