Add a WafPackage base class (#3975)

* Add a WafPackage base class

* Correct comment in docstring

* Be more specific about the Python versions supported
This commit is contained in:
Adam J. Stewart 2017-05-01 10:00:09 -05:00 committed by Todd Gamblin
parent b3ce04cba3
commit 2511520b32
9 changed files with 220 additions and 47 deletions

View File

@ -2085,33 +2085,34 @@ The package base class, usually specialized for a given build system, determines
actual set of entities available for overriding.
The classes that are currently provided by Spack are:
+------------------------------------+----------------------------------+
| | **Base class purpose** |
+====================================+==================================+
| :py:class:`.Package` | General base class not |
| | specialized for any build system |
+------------------------------------+----------------------------------+
| :py:class:`.MakefilePackage` | Specialized class for packages |
| | built invoking |
| | hand-written Makefiles |
+------------------------------------+----------------------------------+
| :py:class:`.AutotoolsPackage` | Specialized class for packages |
| | built using GNU Autotools |
+------------------------------------+----------------------------------+
| :py:class:`.CMakePackage` | Specialized class for packages |
| | built using CMake |
+------------------------------------+----------------------------------+
| :py:class:`.RPackage` | Specialized class for |
| | :py:class:`.R` extensions |
+------------------------------------+----------------------------------+
| :py:class:`.PythonPackage` | Specialized class for |
| | :py:class:`.Python` extensions |
+------------------------------------+----------------------------------+
| :py:class:`.PerlPackage` | Specialized class for |
| | :py:class:`.Perl` extensions |
+------------------------------------+----------------------------------+
+-------------------------------+----------------------------------+
| **Base Class** | **Purpose** |
+===============================+==================================+
| :py:class:`.Package` | General base class not |
| | specialized for any build system |
+-------------------------------+----------------------------------+
| :py:class:`.MakefilePackage` | Specialized class for packages |
| | built invoking |
| | hand-written Makefiles |
+-------------------------------+----------------------------------+
| :py:class:`.AutotoolsPackage` | Specialized class for packages |
| | built using GNU Autotools |
+-------------------------------+----------------------------------+
| :py:class:`.CMakePackage` | Specialized class for packages |
| | built using CMake |
+-------------------------------+----------------------------------+
| :py:class:`.WafPackage` | Specialize class for packages |
| | built using Waf |
+-------------------------------+----------------------------------+
| :py:class:`.RPackage` | Specialized class for |
| | :py:class:`.R` extensions |
+-------------------------------+----------------------------------+
| :py:class:`.PythonPackage` | Specialized class for |
| | :py:class:`.Python` extensions |
+-------------------------------+----------------------------------+
| :py:class:`.PerlPackage` | Specialized class for |
| | :py:class:`.Perl` extensions |
+-------------------------------+----------------------------------+
.. note::

View File

@ -165,6 +165,7 @@
from spack.build_systems.makefile import MakefilePackage
from spack.build_systems.autotools import AutotoolsPackage
from spack.build_systems.cmake import CMakePackage
from spack.build_systems.waf import WafPackage
from spack.build_systems.python import PythonPackage
from spack.build_systems.r import RPackage
from spack.build_systems.perl import PerlPackage
@ -174,12 +175,13 @@
'run_after',
'on_package_attributes',
'Package',
'CMakePackage',
'AutotoolsPackage',
'MakefilePackage',
'AutotoolsPackage',
'CMakePackage',
'WafPackage',
'PythonPackage',
'RPackage',
'PerlPackage'
'PerlPackage',
]
from spack.version import Version, ver

View File

@ -0,0 +1,148 @@
##############################################################################
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
# Produced at the Lawrence Livermore National Laboratory.
#
# This file is part of Spack.
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
# LLNL-CODE-647188
#
# For details, see https://github.com/llnl/spack
# Please also see the LICENSE file for our notice and the LGPL.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License (as
# published by the Free Software Foundation) version 2.1, February 1999.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
# conditions of the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##############################################################################
import inspect
from spack.directives import depends_on
from spack.package import PackageBase, run_after
from llnl.util.filesystem import working_dir
class WafPackage(PackageBase):
"""Specialized class for packages that are built using the
Waf build system. See https://waf.io/book/ for more information.
This class provides the following phases that can be overridden:
* configure
* build
* install
These are all standard Waf commands and can be found by running:
.. code-block:: console
$ python waf --help
Each phase provides a function <phase> that runs:
.. code-block:: console
$ python waf -j<jobs> <phase>
where <jobs> is the number of parallel jobs to build with. Each phase
also has a <phase_args> function that can pass arguments to this call.
All of these functions are empty except for the ``configure_args``
function, which passes ``--prefix=/path/to/installation/prefix``.
"""
# Default phases
phases = ['configure', 'build', 'install']
# To be used in UI queries that require to know which
# build-system class we are using
build_system_class = 'WafPackage'
# Callback names for build-time test
build_time_test_callbacks = ['test']
# Callback names for install-time test
install_time_test_callbacks = ['installtest']
# Much like AutotoolsPackage does not require automake and autoconf
# to build, WafPackage does not require waf to build. It only requires
# python to run the waf build script.
depends_on('python@2.5:', type='build')
@property
def build_directory(self):
"""The directory containing the ``waf`` file."""
return self.stage.source_path
def python(self, *args, **kwargs):
"""The python ``Executable``."""
inspect.getmodule(self).python(*args, **kwargs)
def waf(self, *args, **kwargs):
"""Runs the waf ``Executable``."""
jobs = inspect.getmodule(self).make_jobs
with working_dir(self.build_directory):
self.python('waf', '-j{0}'.format(jobs), *args, **kwargs)
def configure(self, spec, prefix):
"""Configures the project."""
args = self.configure_args(spec, prefix)
self.waf('configure', *args)
def configure_args(self, spec, prefix):
"""Arguments to pass to configure."""
return ['--prefix={0}'.format(prefix)]
def build(self, spec, prefix):
"""Executes the build."""
args = self.build_args(spec, prefix)
self.waf('build', *args)
def build_args(self, spec, prefix):
"""Arguments to pass to build."""
return []
def install(self, spec, prefix):
"""Installs the targets on the system."""
args = self.install_args(spec, prefix)
self.waf('install', *args)
def install_args(self, spec, prefix):
"""Arguments to pass to install."""
return []
# Testing
def test(self):
"""Run unit tests after build.
By default, does nothing. Override this if you want to
add package-specific tests.
"""
pass
run_after('build')(PackageBase._run_default_build_time_test_callbacks)
def installtest(self):
"""Run unit tests after install.
By default, does nothing. Override this if you want to
add package-specific tests.
"""
pass
run_after('install')(PackageBase._run_default_install_time_test_callbacks)
# Check that self.prefix is there after installation
run_after('install')(PackageBase.sanity_check_prefix)

View File

@ -29,10 +29,11 @@
description = 'stops at build stage when installing a package, if possible'
build_system_to_phase = {
CMakePackage: 'build',
AutotoolsPackage: 'build',
CMakePackage: 'build',
WafPackage: 'build',
PythonPackage: 'build',
PerlPackage: 'build'
PerlPackage: 'build',
}

View File

@ -34,9 +34,10 @@
build_system_to_phase = {
CMakePackage: 'cmake',
AutotoolsPackage: 'configure',
PerlPackage: 'configure'
CMakePackage: 'cmake',
WafPackage: 'configure',
PerlPackage: 'configure',
}

View File

@ -204,6 +204,16 @@ def install(self, spec, prefix):
scons('install')"""
class WafPackageTemplate(PackageTemplate):
"""Provides appropriate override for Waf-based packages"""
base_class_name = 'WafPackage'
body = """\
# FIXME: Override configure_args(), build_args(),
# or install_args() if necessary."""
class BazelPackageTemplate(PackageTemplate):
"""Provides appropriate overrides for Bazel-based packages"""
@ -347,6 +357,7 @@ def edit(self, spec, prefix):
'autoreconf': AutoreconfPackageTemplate,
'cmake': CMakePackageTemplate,
'scons': SconsPackageTemplate,
'waf': WafPackageTemplate,
'bazel': BazelPackageTemplate,
'python': PythonPackageTemplate,
'r': RPackageTemplate,
@ -354,7 +365,7 @@ def edit(self, spec, prefix):
'perlbuild': PerlbuildPackageTemplate,
'octave': OctavePackageTemplate,
'makefile': MakefilePackageTemplate,
'generic': PackageTemplate
'generic': PackageTemplate,
}
@ -413,6 +424,7 @@ def __call__(self, stage, url):
('/Makefile.am$', 'autoreconf'),
('/CMakeLists.txt$', 'cmake'),
('/SConstruct$', 'scons'),
('/waf$', 'waf'),
('/setup.py$', 'python'),
('/NAMESPACE$', 'r'),
('/WORKSPACE$', 'bazel'),

View File

@ -35,6 +35,7 @@
('configure', 'autotools'),
('CMakeLists.txt', 'cmake'),
('SConstruct', 'scons'),
('waf', 'waf'),
('setup.py', 'python'),
('NAMESPACE', 'r'),
('WORKSPACE', 'bazel'),

View File

@ -25,7 +25,7 @@
from spack import *
class PyPy2cairo(Package):
class PyPy2cairo(WafPackage):
"""Pycairo is a set of Python bindings for the cairo graphics library."""
homepage = "https://www.cairographics.org/pycairo/"
@ -35,10 +35,15 @@ class PyPy2cairo(Package):
extends('python')
depends_on('cairo')
depends_on('python', type=('build', 'run'))
depends_on('cairo@1.10.0:')
depends_on('pixman')
depends_on('pkg-config', type='build')
def install(self, spec, prefix):
python('waf', 'configure', '--prefix={0}'.format(prefix))
python('waf', 'build')
python('waf', 'install')
# TODO: Add a 'test' deptype
# depends_on('py-pytest', type='test')
def installtest(self):
with working_dir('test'):
pytest = which('py.test')
pytest()

View File

@ -25,7 +25,7 @@
from spack import *
class Tut(Package):
class Tut(WafPackage):
"""TUT is a small and portable unit test framework for C++."""
homepage = "http://mrzechonek.github.io/tut-framework/"
@ -33,9 +33,11 @@ class Tut(Package):
version('2016-12-19', '8b1967fa295ae1ce4d4431c2f811e521')
extends('python')
def build_args(self, spec, prefix):
args = []
def install(self, spec, prefix):
python('waf', 'configure', '--prefix={0}'.format(prefix))
python('waf', 'build')
python('waf', 'install')
if self.run_tests:
# Run unit tests
args.append('--test')
return args