diff options
author | Milton Woods <miltonjwoods@gmail.com> | 2017-03-31 09:38:58 +1000 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2017-03-30 16:38:58 -0700 |
commit | 9e43ff821c1549d5813eebd5a9ca81a7869786e7 (patch) | |
tree | c7f4ad5e12302acae6ebc1a286e384b5b0ae617c | |
parent | 9e1abb13dcc4fb21042c6ca3b2e5c445811d6c15 (diff) | |
download | spack-9e43ff821c1549d5813eebd5a9ca81a7869786e7.tar.gz spack-9e43ff821c1549d5813eebd5a9ca81a7869786e7.tar.bz2 spack-9e43ff821c1549d5813eebd5a9ca81a7869786e7.tar.xz spack-9e43ff821c1549d5813eebd5a9ca81a7869786e7.zip |
Extendable Perl (#3614)
* perl: make extendable and add Module::Build package
* perl: allow 'spack create' to identify perl packages from their contents
* perl-module-build: fix indenting of package docstring
* perl: split install() method for extensions into phases
* perl: auto-detect build method (Makefile.PL vs Build.PL) and define a 'check' method
* PerlPackage: use import statements similar to those in AutotoolsPackage
* PerlModule: fix detection of Build.PL
* PerlPackageTemplate: remove extraneous lines to avoid flake8 warnings
* PerlPackageTemplate: split into separate templates for Makefile.PL and Build.PL
* PerlPackage: add cross-references to docstrings
* AutotoolsPackage: fix ambiguous cross-references to avoid errors in doc tests
* PerlbuildPackageTemplate: depend on perl-module-build if Build.PL exists
-rw-r--r-- | lib/spack/docs/packaging_guide.rst | 4 | ||||
-rw-r--r-- | lib/spack/spack/__init__.py | 4 | ||||
-rw-r--r-- | lib/spack/spack/build_systems/autotools.py | 8 | ||||
-rw-r--r-- | lib/spack/spack/build_systems/perl.py | 117 | ||||
-rw-r--r-- | lib/spack/spack/cmd/build.py | 3 | ||||
-rw-r--r-- | lib/spack/spack/cmd/configure.py | 3 | ||||
-rw-r--r-- | lib/spack/spack/cmd/create.py | 45 | ||||
-rw-r--r-- | lib/spack/spack/test/build_system_guess.py | 2 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/perl-module-build/package.py | 41 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/perl/package.py | 45 |
10 files changed, 264 insertions, 8 deletions
diff --git a/lib/spack/docs/packaging_guide.rst b/lib/spack/docs/packaging_guide.rst index 729ea5d656..1a64c7db4a 100644 --- a/lib/spack/docs/packaging_guide.rst +++ b/lib/spack/docs/packaging_guide.rst @@ -2043,6 +2043,10 @@ The classes that are currently provided by Spack are: | :py:class:`.PythonPackage` | Specialized class for | | | :py:class:`.Python` extensions | +------------------------------------+----------------------------------+ + | :py:class:`.PerlPackage` | Specialized class for | + | | :py:class:`.Perl` extensions | + +------------------------------------+----------------------------------+ + diff --git a/lib/spack/spack/__init__.py b/lib/spack/spack/__init__.py index 6a28fbb2b0..b0f2faed76 100644 --- a/lib/spack/spack/__init__.py +++ b/lib/spack/spack/__init__.py @@ -162,6 +162,7 @@ from spack.build_systems.autotools import AutotoolsPackage from spack.build_systems.cmake import CMakePackage from spack.build_systems.python import PythonPackage from spack.build_systems.r import RPackage +from spack.build_systems.perl import PerlPackage __all__ += [ 'run_before', @@ -172,7 +173,8 @@ __all__ += [ 'AutotoolsPackage', 'MakefilePackage', 'PythonPackage', - 'RPackage' + 'RPackage', + 'PerlPackage' ] from spack.version import Version, ver diff --git a/lib/spack/spack/build_systems/autotools.py b/lib/spack/spack/build_systems/autotools.py index a11a84acd0..76dfd0d16f 100644 --- a/lib/spack/spack/build_systems/autotools.py +++ b/lib/spack/spack/build_systems/autotools.py @@ -49,7 +49,8 @@ class AutotoolsPackage(PackageBase): 4. :py:meth:`~.AutotoolsPackage.install` They all have sensible defaults and for many packages the only thing - necessary will be to override the helper method :py:meth:`.configure_args`. + necessary will be to override the helper method + :py:meth:`~.AutotoolsPackage.configure_args`. For a finer tuning you may also override: +-----------------------------------------------+--------------------+ @@ -234,7 +235,7 @@ class AutotoolsPackage(PackageBase): appropriately, otherwise raises an error. :raises RuntimeError: if a configure script is not found in - :py:meth:`~.configure_directory` + :py:meth:`~AutotoolsPackage.configure_directory` """ # Check if a configure script is there. If not raise a RuntimeError. if not os.path.exists(self.configure_abs_path): @@ -255,7 +256,8 @@ class AutotoolsPackage(PackageBase): return [] def configure(self, spec, prefix): - """Runs configure with the arguments specified in :py:meth:`.configure_args` + """Runs configure with the arguments specified in + :py:meth:`~.AutotoolsPackage.configure_args` and an appropriately set prefix. """ options = ['--prefix={0}'.format(prefix)] + self.configure_args() diff --git a/lib/spack/spack/build_systems/perl.py b/lib/spack/spack/build_systems/perl.py new file mode 100644 index 0000000000..78184c85dc --- /dev/null +++ b/lib/spack/spack/build_systems/perl.py @@ -0,0 +1,117 @@ +############################################################################## +# 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 +import os + +from llnl.util.filesystem import join_path +from spack.directives import extends +from spack.package import PackageBase, run_after +from spack.util.executable import Executable + + +class PerlPackage(PackageBase): + """Specialized class for packages that are built using Perl. + + This class provides four phases that can be overridden if required: + + 1. :py:meth:`~.PerlPackage.configure` + 2. :py:meth:`~.PerlPackage.build` + 3. :py:meth:`~.PerlPackage.check` + 4. :py:meth:`~.PerlPackage.install` + + The default methods use, in order of preference: + (1) Makefile.PL, + (2) Build.PL. + + Some packages may need to override + :py:meth:`~.PerlPackage.configure_args`, + which produces a list of arguments for + :py:meth:`~.PerlPackage.configure`. + Arguments should not include the installation base directory. + """ + #: Phases of a Perl package + phases = ['configure', 'build', 'install'] + + #: This attribute is used in UI queries that need to know the build + #: system base class + build_system_class = 'PerlPackage' + + #: Callback names for build-time test + build_time_test_callbacks = ['check'] + + extends('perl') + + def configure_args(self): + """Produces a list containing the arguments that must be passed to + :py:meth:`~.PerlPackage.configure`. Arguments should not include + the installation base directory, which is prepended automatically. + + :return: list of arguments for Makefile.PL or Build.PL + """ + return [] + + def configure(self, spec, prefix): + """Runs Makefile.PL or Build.PL with arguments consisting of + an appropriate installation base directory followed by the + list returned by :py:meth:`~.PerlPackage.configure_args`. + + :raise RuntimeError: if neither Makefile.PL or Build.PL exist + """ + if os.path.isfile('Makefile.PL'): + self.build_method = 'Makefile.PL' + self.build_executable = inspect.getmodule(self).make + elif os.path.isfile('Build.PL'): + self.build_method = 'Build.PL' + self.build_executable = Executable( + join_path(self.stage.source_path, 'Build')) + else: + raise RuntimeError('Unknown build_method for perl package') + + if self.build_method == 'Makefile.PL': + options = ['Makefile.PL', 'INSTALL_BASE={0}'.format(prefix)] + elif self.build_method == 'Build.PL': + options = ['Build.PL', '--install_base', prefix] + options += self.configure_args() + + inspect.getmodule(self).perl(*options) + + def build(self, spec, prefix): + """Builds a Perl package.""" + self.build_executable() + + # Ensure that tests run after build (if requested): + run_after('build')(PackageBase._run_default_build_time_test_callbacks) + + def check(self): + """Runs built-in tests of a Perl package.""" + self.build_executable('test') + + def install(self, spec, prefix): + """Installs a Perl package.""" + self.build_executable('install') + + # 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 6a90af907d..90157a85af 100644 --- a/lib/spack/spack/cmd/build.py +++ b/lib/spack/spack/cmd/build.py @@ -31,7 +31,8 @@ description = 'stops at build stage when installing a package, if possible' build_system_to_phase = { CMakePackage: 'build', AutotoolsPackage: 'build', - PythonPackage: 'build' + PythonPackage: 'build', + PerlPackage: 'build' } diff --git a/lib/spack/spack/cmd/configure.py b/lib/spack/spack/cmd/configure.py index 7b1ef04522..b6669f33a2 100644 --- a/lib/spack/spack/cmd/configure.py +++ b/lib/spack/spack/cmd/configure.py @@ -36,7 +36,8 @@ description = 'stops at configuration stage when installing a package, if possib build_system_to_phase = { CMakePackage: 'cmake', - AutotoolsPackage: 'configure' + AutotoolsPackage: 'configure', + PerlPackage: 'configure' } diff --git a/lib/spack/spack/cmd/create.py b/lib/spack/spack/cmd/create.py index 14b213a756..cc90669158 100644 --- a/lib/spack/spack/cmd/create.py +++ b/lib/spack/spack/cmd/create.py @@ -268,6 +268,45 @@ class RPackageTemplate(PackageTemplate): super(RPackageTemplate, self).__init__(name, *args) +class PerlmakePackageTemplate(PackageTemplate): + """Provides appropriate overrides for Perl extensions + that come with a Makefile.PL""" + base_class_name = 'PerlPackage' + + dependencies = """\ + # FIXME: Add dependencies if required: + # depends_on('perl-foo') + # depends_on('barbaz', type=('build', 'link', 'run'))""" + + body = """\ + # FIXME: If non-standard arguments are used for configure step: + # def configure_args(self): + # return ['my', 'configure', 'args'] + + # FIXME: in unusual cases, it may be necessary to override methods for + # configure(), build(), check() or install().""" + + def __init__(self, name, *args): + # If the user provided `--name perl-cpp`, don't rename it perl-perl-cpp + if not name.startswith('perl-'): + # Make it more obvious that we are renaming the package + tty.msg("Changing package name from {0} to perl-{0}".format(name)) + name = 'perl-{0}'.format(name) + + super(PerlmakePackageTemplate, self).__init__(name, *args) + + +class PerlbuildPackageTemplate(PerlmakePackageTemplate): + """Provides appropriate overrides for Perl extensions + that come with a Build.PL instead of a Makefile.PL""" + dependencies = """\ + depends_on('perl-module-build', type='build') + + # FIXME: Add additional dependencies if required: + # depends_on('perl-foo') + # depends_on('barbaz', type=('build', 'link', 'run'))""" + + class OctavePackageTemplate(PackageTemplate): """Provides appropriate overrides for octave packages""" @@ -305,6 +344,8 @@ templates = { 'bazel': BazelPackageTemplate, 'python': PythonPackageTemplate, 'r': RPackageTemplate, + 'perlmake': PerlmakePackageTemplate, + 'perlbuild': PerlbuildPackageTemplate, 'octave': OctavePackageTemplate, 'generic': PackageTemplate } @@ -363,7 +404,9 @@ class BuildSystemGuesser: (r'/SConstruct$', 'scons'), (r'/setup.py$', 'python'), (r'/NAMESPACE$', 'r'), - (r'/WORKSPACE$', 'bazel') + (r'/WORKSPACE$', 'bazel'), + (r'/Build.PL$', 'perlbuild'), + (r'/Makefile.PL$', 'perlmake'), ] # Peek inside the compressed file. diff --git a/lib/spack/spack/test/build_system_guess.py b/lib/spack/spack/test/build_system_guess.py index 82bf1964b2..e6fb84b37d 100644 --- a/lib/spack/spack/test/build_system_guess.py +++ b/lib/spack/spack/test/build_system_guess.py @@ -38,6 +38,8 @@ import spack.stage ('setup.py', 'python'), ('NAMESPACE', 'r'), ('WORKSPACE', 'bazel'), + ('Makefile.PL', 'perlmake'), + ('Build.PL', 'perlbuild'), ('foobar', 'generic') ] ) diff --git a/var/spack/repos/builtin/packages/perl-module-build/package.py b/var/spack/repos/builtin/packages/perl-module-build/package.py new file mode 100644 index 0000000000..cccc5d7b5a --- /dev/null +++ b/var/spack/repos/builtin/packages/perl-module-build/package.py @@ -0,0 +1,41 @@ +############################################################################## +# 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 +############################################################################## +# +from spack import * + + +class PerlModuleBuild(PerlPackage): + """Module::Build is a system for building, testing, and installing Perl + modules. It is meant to be an alternative to ExtUtils::MakeMaker. + Developers may alter the behavior of the module through subclassing in a + much more straightforward way than with MakeMaker. It also does not + require a make on your system - most of the Module::Build code is + pure-perl and written in a very cross-platform way. + """ + + homepage = "http://search.cpan.org/perldoc/Module::Build" + url = "http://search.cpan.org/CPAN/authors/id/L/LE/LEONT/Module-Build-0.4220.tar.gz" + + version('0.4220', '9df204e188462a4410d496f316c2c531') diff --git a/var/spack/repos/builtin/packages/perl/package.py b/var/spack/repos/builtin/packages/perl/package.py index 4bacad427b..b8874c124e 100644 --- a/var/spack/repos/builtin/packages/perl/package.py +++ b/var/spack/repos/builtin/packages/perl/package.py @@ -23,6 +23,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ############################################################################## # +# Author: Milton Woods <milton.woods@bom.gov.au> +# Date: March 22, 2017 # Author: George Hartzell <hartzell@alerce.com> # Date: July 21, 2016 # Author: Justin Too <justin@doubleotoo.com> @@ -36,7 +38,7 @@ class Perl(Package): # Perl doesn't use Autotools, it should subclass Package 27 years of development.""" homepage = "http://www.perl.org" # URL must remain http:// so Spack can bootstrap curl - url = "http://www.cpan.org/src/5.0/perl-5.24.1.tar.gz" + url = "http://www.cpan.org/src/5.0/perl-5.24.1.tar.gz" version('5.24.1', '765ef511b5b87a164e2531403ee16b3c') version('5.24.0', 'c5bf7f3285439a2d3b6a488e14503701') @@ -46,6 +48,8 @@ class Perl(Package): # Perl doesn't use Autotools, it should subclass Package # https://rt.perl.org/Public/Bug/Display.html?id=123784 # version('5.18.4' , '1f9334ff730adc05acd3dd7130d295db') + extendable = True + # Installing cpanm alongside the core makes it safe and simple for # people/projects to install their own sets of perl modules. Not # having it in core increases the "energy of activation" for doing @@ -80,3 +84,42 @@ class Perl(Package): # Perl doesn't use Autotools, it should subclass Package perl('Makefile.PL') make() make('install') + + def setup_environment(self, spack_env, run_env): + """Set PERL5LIB to support activation of Perl packages""" + run_env.set('PERL5LIB', join_path(self.prefix, 'lib', 'perl5')) + + def setup_dependent_environment(self, spack_env, run_env, extension_spec): + """Set PATH and PERL5LIB to include the extension and + any other perl extensions it depends on, + assuming they were installed with INSTALL_BASE defined.""" + perl_lib_dirs = [] + perl_bin_dirs = [] + for d in extension_spec.traverse( + deptype=('build', 'run'), deptype_query='run'): + if d.package.extends(self.spec): + perl_lib_dirs.append(join_path(d.prefix, 'lib', 'perl5')) + perl_bin_dirs.append(join_path(d.prefix, 'bin')) + perl_bin_path = ':'.join(perl_bin_dirs) + perl_lib_path = ':'.join(perl_lib_dirs) + spack_env.prepend_path('PATH', perl_bin_path) + spack_env.prepend_path('PERL5LIB', perl_lib_path) + run_env.prepend_path('PATH', perl_bin_path) + run_env.prepend_path('PERL5LIB', perl_lib_path) + + def setup_dependent_package(self, module, ext_spec): + """Called before perl modules' install() methods. + In most cases, extensions will only need to have one line: + perl('Makefile.PL','INSTALL_BASE=%s' % self.prefix) + """ + + # perl extension builds can have a global perl executable function + module.perl = Executable(join_path(self.spec.prefix.bin, 'perl')) + + # Add variables for library directory + module.perl_lib_dir = join_path(ext_spec.prefix, 'lib', 'perl5') + + # Make the site packages directory for extensions, + # if it does not exist already. + if ext_spec.package.is_extension: + mkdirp(module.perl_lib_dir) |