Added mixins to modularize common behaviors across build-systems.

Modifications:
  * added a mixin to filter compiler wrappers from files
  * modified hdf5, openmpi, mpich, mvapich2 to use it
This commit is contained in:
alalazo 2017-06-09 21:07:20 +02:00 committed by Todd Gamblin
parent 4d97b540a8
commit 28e129b087
8 changed files with 144 additions and 119 deletions

View file

@ -214,6 +214,9 @@
'IntelPackage',
]
from spack.mixins import FilterCompilerWrappersPackageMixin
__all__ += ['FilterCompilerWrappersPackageMixin']
from spack.version import Version, ver
__all__ += ['Version', 'ver']

82
lib/spack/spack/mixins.py Normal file
View file

@ -0,0 +1,82 @@
##############################################################################
# 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 os
import llnl.util.filesystem
class FilterCompilerWrappersPackageMixin(object):
"""This mixin class registers a callback that filters a list of files
after installation and substitutes hardcoded paths pointing to the Spack
compiler wrappers with the corresponding 'real' compilers.
"""
#: compiler wrappers to be filtered (needs to be overridden)
compiler_wrappers = []
#: phase after which the callback is invoked (default 'install')
filter_phase = 'install'
def __init__(self):
attr_name = '_InstallPhase_{0}'.format(self.filter_phase)
# Here we want to get the attribute directly from the class (noe from
# the instance), so that we can modify it and add the mixin method
phase = getattr(type(self), attr_name)
# Due to MRO, we may have taken a method from a parent class
# and modifying it may influence other packages in unwanted manners.
# Solve the problem by copying the phase into the most derived class.
setattr(type(self), attr_name, phase.copy())
phase = getattr(type(self), attr_name)
phase.run_after.append(
FilterCompilerWrappersPackageMixin.filter_compilers
)
super(FilterCompilerWrappersPackageMixin, self).__init__()
def filter_compilers(self):
"""Substitutes any path referring to a Spack compiler wrapper
with the path of the underlying compiler that has been used.
If this isn't done, the files will have CC, CXX, F77, and FC set
to Spack's generic cc, c++, f77, and f90. We want them to
be bound to whatever compiler they were built with.
"""
kwargs = {'ignore_absent': True, 'backup': False, 'string': True}
if self.compiler_wrappers:
x = llnl.util.filesystem.FileFilter(*self.compiler_wrappers)
x.filter(os.environ['CC'], self.compiler.cc, **kwargs)
x.filter(os.environ['CXX'], self.compiler.cxx, **kwargs)
x.filter(os.environ['F77'], self.compiler.f77, **kwargs)
x.filter(os.environ['FC'], self.compiler.fc, **kwargs)
# Remove this linking flag if present (it turns RPATH into RUNPATH)
x.filter('-Wl,--enable-new-dtags', '', **kwargs)

View file

@ -182,6 +182,9 @@ def _flush_callbacks(check_name):
PackageMeta.phase_fmt.format(phase_name),
None
)
if phase is not None:
break
attr_dict[PackageMeta.phase_fmt.format(
phase_name)] = phase.copy()
phase = attr_dict[
@ -618,6 +621,8 @@ def __init__(self, spec):
self.extra_args = {}
super(PackageBase, self).__init__()
def possible_dependencies(self, transitive=True, visited=None):
"""Return set of possible transitive dependencies of this package.

View file

@ -22,12 +22,13 @@
# 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 *
import shutil
import sys
from spack import *
class Hdf5(AutotoolsPackage):
class Hdf5(AutotoolsPackage, FilterCompilerWrappersPackageMixin):
"""HDF5 is a data model, library, and file format for storing and managing
data. It supports an unlimited variety of datatypes, and is designed for
flexible and efficient I/O and for high volume and complex data.
@ -294,3 +295,11 @@ def check_install(self):
print('-' * 80)
raise RuntimeError("HDF5 install check failed")
shutil.rmtree(checkdir)
@property
def compiler_wrappers(self):
return [
join_path(self.prefix.bin, 'h5c++'),
join_path(self.prefix.bin, 'h5cc'),
join_path(self.prefix.bin, 'h5fc'),
]

View file

@ -26,7 +26,7 @@
import os
class Mpich(AutotoolsPackage):
class Mpich(AutotoolsPackage, FilterCompilerWrappersPackageMixin):
"""MPICH is a high performance and widely portable implementation of
the Message Passing Interface (MPI) standard."""
@ -170,33 +170,11 @@ def configure_args(self):
return config_args
@run_after('install')
def filter_compilers(self):
"""Run after install to make the MPI compilers use the
compilers that Spack built the package with.
If this isn't done, they'll have CC, CXX, F77, and FC set
to Spack's generic cc, c++, f77, and f90. We want them to
be bound to whatever compiler they were built with."""
mpicc = join_path(self.prefix.bin, 'mpicc')
mpicxx = join_path(self.prefix.bin, 'mpicxx')
mpif77 = join_path(self.prefix.bin, 'mpif77')
mpif90 = join_path(self.prefix.bin, 'mpif90')
# Substitute Spack compile wrappers for the real
# underlying compiler
kwargs = {
'ignore_absent': True,
'backup': False,
'string': True
}
filter_file(env['CC'], self.compiler.cc, mpicc, **kwargs)
filter_file(env['CXX'], self.compiler.cxx, mpicxx, **kwargs)
filter_file(env['F77'], self.compiler.f77, mpif77, **kwargs)
filter_file(env['FC'], self.compiler.fc, mpif90, **kwargs)
# Remove this linking flag if present
# (it turns RPATH into RUNPATH)
for wrapper in (mpicc, mpicxx, mpif77, mpif90):
filter_file('-Wl,--enable-new-dtags', '', wrapper, **kwargs)
@property
def compiler_wrappers(self):
return [
join_path(self.prefix.bin, 'mpicc'),
join_path(self.prefix.bin, 'mpicxx'),
join_path(self.prefix.bin, 'mpif77'),
join_path(self.prefix.bin, 'mpif90')
]

View file

@ -35,7 +35,7 @@ def _process_manager_validator(values):
)
class Mvapich2(AutotoolsPackage):
class Mvapich2(AutotoolsPackage, FilterCompilerWrappersPackageMixin):
"""MVAPICH2 is an MPI implementation for Infiniband networks."""
homepage = "http://mvapich.cse.ohio-state.edu/"
url = "http://mvapich.cse.ohio-state.edu/download/mvapich/mv2/mvapich2-2.2.tar.gz"
@ -232,32 +232,11 @@ def configure_args(self):
args.extend(self.network_options)
return args
@run_after('install')
def filter_compilers(self):
"""Run after install to make the MPI compilers use the
compilers that Spack built the package with.
If this isn't done, they'll have CC, CXX, F77, and FC set
to Spack's generic cc, c++, f77, and f90. We want them to
be bound to whatever compiler they were built with.
"""
bin = self.prefix.bin
mpicc = join_path(bin, 'mpicc')
mpicxx = join_path(bin, 'mpicxx')
mpif77 = join_path(bin, 'mpif77')
mpif90 = join_path(bin, 'mpif90')
mpifort = join_path(bin, 'mpifort')
# Substitute Spack compile wrappers for the real
# underlying compiler
kwargs = {'ignore_absent': True, 'backup': False, 'string': True}
filter_file(env['CC'], self.compiler.cc, mpicc, **kwargs)
filter_file(env['CXX'], self.compiler.cxx, mpicxx, **kwargs)
filter_file(env['F77'], self.compiler.f77, mpif77, **kwargs)
filter_file(env['FC'], self.compiler.fc, mpif90, **kwargs)
filter_file(env['FC'], self.compiler.fc, mpifort, **kwargs)
# Remove this linking flag if present
# (it turns RPATH into RUNPATH)
for wrapper in (mpicc, mpicxx, mpif77, mpif90, mpifort):
filter_file('-Wl,--enable-new-dtags', '', wrapper, **kwargs)
@property
def compiler_wrappers(self):
return [
join_path(self.prefix.bin, 'mpicc'),
join_path(self.prefix.bin, 'mpicxx'),
join_path(self.prefix.bin, 'mpif77'),
join_path(self.prefix.bin, 'mpif90')
]

View file

@ -64,7 +64,7 @@ def _mxm_dir():
return None
class Openmpi(AutotoolsPackage):
class Openmpi(AutotoolsPackage, FilterCompilerWrappersPackageMixin):
"""The Open MPI Project is an open source Message Passing Interface
implementation that is developed and maintained by a consortium
of academic, research, and industry partners. Open MPI is
@ -375,43 +375,28 @@ def configure_args(self):
return config_args
@run_after('install')
def filter_compilers(self):
"""Run after install to make the MPI compilers use the
compilers that Spack built the package with.
@property
def compiler_wrappers(self):
If this isn't done, they'll have CC, CXX and FC set
to Spack's generic cc, c++ and f90. We want them to
be bound to whatever compiler they were built with.
"""
kwargs = {'ignore_absent': True, 'backup': False, 'string': False}
wrapper_basepath = join_path(self.prefix, 'share', 'openmpi')
basepath = join_path(self.prefix, 'share', 'openmpi')
wrappers = [
('mpicc-vt-wrapper-data.txt', self.compiler.cc),
('mpicc-wrapper-data.txt', self.compiler.cc),
('ortecc-wrapper-data.txt', self.compiler.cc),
('shmemcc-wrapper-data.txt', self.compiler.cc),
('mpic++-vt-wrapper-data.txt', self.compiler.cxx),
('mpic++-wrapper-data.txt', self.compiler.cxx),
('ortec++-wrapper-data.txt', self.compiler.cxx),
('mpifort-vt-wrapper-data.txt', self.compiler.fc),
('mpifort-wrapper-data.txt', self.compiler.fc),
('shmemfort-wrapper-data.txt', self.compiler.fc),
('mpif90-vt-wrapper-data.txt', self.compiler.fc),
('mpif90-wrapper-data.txt', self.compiler.fc),
('mpif77-vt-wrapper-data.txt', self.compiler.f77),
('mpif77-wrapper-data.txt', self.compiler.f77)
'mpicc-vt-wrapper-data.txt',
'mpicc-wrapper-data.txt',
'ortecc-wrapper-data.txt',
'shmemcc-wrapper-data.txt',
'mpic++-vt-wrapper-data.txt',
'mpic++-wrapper-data.txt',
'ortec++-wrapper-data.txt',
'mpifort-vt-wrapper-data.txt',
'mpifort-wrapper-data.txt',
'shmemfort-wrapper-data.txt',
'mpif90-vt-wrapper-data.txt',
'mpif90-wrapper-data.txt',
'mpif77-vt-wrapper-data.txt',
'mpif77-wrapper-data.txt'
]
for wrapper_name, compiler in wrappers:
wrapper = join_path(wrapper_basepath, wrapper_name)
if not os.path.islink(wrapper):
# Substitute Spack compile wrappers for the real
# underlying compiler
match = 'compiler=.*'
substitute = 'compiler={compiler}'.format(compiler=compiler)
filter_file(match, substitute, wrapper, **kwargs)
# Remove this linking flag if present
# (it turns RPATH into RUNPATH)
filter_file('-Wl,--enable-new-dtags', '', wrapper, **kwargs)
abs_wrappers = [join_path(basepath, x) for x in wrappers]
return [x for x in abs_wrappers if not os.path.islink(x)]

View file

@ -26,7 +26,7 @@
from spack import *
class R(AutotoolsPackage):
class R(AutotoolsPackage, FilterCompilerWrappersPackageMixin):
"""R is 'GNU S', a freely available language and environment for
statistical computing and graphics which provides a wide variety of
statistical and graphical techniques: linear and nonlinear modelling,
@ -129,25 +129,9 @@ def copy_makeconf(self):
dst_makeconf = join_path(self.etcdir, 'Makeconf.spack')
shutil.copy(src_makeconf, dst_makeconf)
@run_after('install')
def filter_compilers(self):
"""Run after install to tell the configuration files and Makefiles
to use the compilers that Spack built the package with.
If this isn't done, they'll have CC and CXX set to Spack's generic
cc and c++. We want them to be bound to whatever compiler
they were built with."""
kwargs = {'ignore_absent': True, 'backup': False, 'string': True}
filter_file(env['CC'], self.compiler.cc,
join_path(self.etcdir, 'Makeconf'), **kwargs)
filter_file(env['CXX'], self.compiler.cxx,
join_path(self.etcdir, 'Makeconf'), **kwargs)
filter_file(env['F77'], self.compiler.f77,
join_path(self.etcdir, 'Makeconf'), **kwargs)
filter_file(env['FC'], self.compiler.fc,
join_path(self.etcdir, 'Makeconf'), **kwargs)
@property
def compiler_wrappers(self):
return [join_path(self.etcdir, 'Makeconf')]
# ========================================================================
# Set up environment to make install easy for R extensions.