From 2511520b32fb6559084684c24ec51f54e30f4bb4 Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Mon, 1 May 2017 10:00:09 -0500 Subject: Add a WafPackage base class (#3975) * Add a WafPackage base class * Correct comment in docstring * Be more specific about the Python versions supported --- lib/spack/docs/packaging_guide.rst | 55 +++++------ lib/spack/spack/__init__.py | 8 +- lib/spack/spack/build_systems/waf.py | 148 +++++++++++++++++++++++++++++ lib/spack/spack/cmd/build.py | 5 +- lib/spack/spack/cmd/configure.py | 5 +- lib/spack/spack/cmd/create.py | 14 ++- lib/spack/spack/test/build_system_guess.py | 1 + 7 files changed, 201 insertions(+), 35 deletions(-) create mode 100644 lib/spack/spack/build_systems/waf.py (limited to 'lib') diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst index 6f4a3ecf1a..bf6f3f3cf9 100644 --- a/lib/spack/docs/packaging_guide.rst +++ b/lib/spack/docs/packaging_guide.rst @@ -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:: diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index 85d881a769..73963b848c 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -165,6 +165,7 @@ from spack.package import Package, run_before, run_after, on_package_attributes 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 @@ __all__ += [ 'run_after', 'on_package_attributes', 'Package', - 'CMakePackage', - 'AutotoolsPackage', 'MakefilePackage', + 'AutotoolsPackage', + 'CMakePackage', + 'WafPackage', 'PythonPackage', 'RPackage', - 'PerlPackage' + 'PerlPackage', ] from spack.version import Version, ver diff --git a/lib/spack/spack/build_systems/waf.py b/lib/spack/spack/build_systems/waf.py new file mode 100644 index 0000000000..bb4fa6c369 --- /dev/null +++ b/lib/spack/spack/build_systems/waf.py @@ -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 that runs: + + .. code-block:: console + + $ python waf -j + + where is the number of parallel jobs to build with. Each phase + also has a 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) diff --git a/lib/spack/spack/cmd/build.py b/lib/spack/spack/cmd/build.py index 90157a85af..877f2ce0cf 100644 --- a/lib/spack/spack/cmd/build.py +++ b/lib/spack/spack/cmd/build.py @@ -29,10 +29,11 @@ from spack import * 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', } diff --git a/lib/spack/spack/cmd/configure.py b/lib/spack/spack/cmd/configure.py index 037705f480..7f6c07c34b 100644 --- a/lib/spack/spack/cmd/configure.py +++ b/lib/spack/spack/cmd/configure.py @@ -34,9 +34,10 @@ description = 'stops at configuration stage when installing a package, if possib build_system_to_phase = { - CMakePackage: 'cmake', AutotoolsPackage: 'configure', - PerlPackage: 'configure' + CMakePackage: 'cmake', + WafPackage: 'configure', + PerlPackage: 'configure', } diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py index 504ac9d844..adaf388387 100644 --- a/lib/spack/spack/cmd/create.py +++ b/lib/spack/spack/cmd/create.py @@ -204,6 +204,16 @@ class SconsPackageTemplate(PackageTemplate): 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 @@ templates = { 'autoreconf': AutoreconfPackageTemplate, 'cmake': CMakePackageTemplate, 'scons': SconsPackageTemplate, + 'waf': WafPackageTemplate, 'bazel': BazelPackageTemplate, 'python': PythonPackageTemplate, 'r': RPackageTemplate, @@ -354,7 +365,7 @@ templates = { 'perlbuild': PerlbuildPackageTemplate, 'octave': OctavePackageTemplate, 'makefile': MakefilePackageTemplate, - 'generic': PackageTemplate + 'generic': PackageTemplate, } @@ -413,6 +424,7 @@ class BuildSystemGuesser: ('/Makefile.am$', 'autoreconf'), ('/CMakeLists.txt$', 'cmake'), ('/SConstruct$', 'scons'), + ('/waf$', 'waf'), ('/setup.py$', 'python'), ('/NAMESPACE$', 'r'), ('/WORKSPACE$', 'bazel'), diff --git a/lib/spack/spack/test/build_system_guess.py b/lib/spack/spack/test/build_system_guess.py index 9ea76e7bfc..73b619cb22 100644 --- a/lib/spack/spack/test/build_system_guess.py +++ b/lib/spack/spack/test/build_system_guess.py @@ -35,6 +35,7 @@ import spack.stage ('configure', 'autotools'), ('CMakeLists.txt', 'cmake'), ('SConstruct', 'scons'), + ('waf', 'waf'), ('setup.py', 'python'), ('NAMESPACE', 'r'), ('WORKSPACE', 'bazel'), -- cgit v1.2.3-60-g2f50