Update Package : Zoltan (#1793)

* Refactored and reorganized the 'zoltan' install script.

* Fixed a few bugs with the '+mpi' and '+fortan' variants of 'zoltan'.

* Reintroduced and improved the '+shared' variant for the 'zoltan' package.

* Improved compatibility with different MPI providers for 'zoltan'.
This commit is contained in:
Joseph Ciurej 2016-09-20 02:46:13 -07:00 committed by Todd Gamblin
parent c9fe2cd469
commit e73a7c80bf

View File

@ -22,10 +22,11 @@
# License along with this program; if not, write to the Free Software # License along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
############################################################################## ##############################################################################
from spack import *
import re import re
import os import os
import glob import glob
from spack import *
class Zoltan(Package): class Zoltan(Package):
@ -47,23 +48,28 @@ class Zoltan(Package):
version('3.6', '9cce794f7241ecd8dbea36c3d7a880f9') version('3.6', '9cce794f7241ecd8dbea36c3d7a880f9')
version('3.3', '5eb8f00bda634b25ceefa0122bd18d65') version('3.3', '5eb8f00bda634b25ceefa0122bd18d65')
variant('debug', default=False, variant('debug', default=False, description='Builds a debug version of the library.')
description='Builds a debug version of the library') variant('shared', default=True, description='Builds a shared version of the library.')
variant('shared', default=True,
description='Builds a shared version of the library')
variant('fortran', default=True, description='Enable Fortran support') variant('fortran', default=True, description='Enable Fortran support.')
variant('mpi', default=False, description='Enable MPI support') variant('mpi', default=True, description='Enable MPI support.')
depends_on('mpi', when='+mpi') depends_on('mpi', when='+mpi')
def install(self, spec, prefix): def url_for_version(self, version):
config_args = [ return '%s/zoltan_distrib_v%s.tar.gz' % (Zoltan.base_url, version)
'--enable-f90interface'
if '+fortan' in spec else '--disable-f90interface',
'--enable-mpi' def install(self, spec, prefix):
if '+mpi' in spec else '--disable-mpi', # FIXME: The older Zoltan versions fail to compile the F90 MPI wrappers
# because of some complicated generic type problem.
if spec.satisfies('@:3.6+fortran+mpi'):
raise RuntimeError(('Cannot build Zoltan v{0} with +fortran and '
'+mpi; please disable one of these features '
'or upgrade versions.').format(self.version))
config_args = [
self.get_config_flag('f90interface', 'fortran'),
self.get_config_flag('mpi', 'mpi'),
] ]
config_cflags = [ config_cflags = [
'-O0' if '+debug' in spec else '-O3', '-O0' if '+debug' in spec else '-O3',
@ -71,49 +77,70 @@ def install(self, spec, prefix):
] ]
if '+shared' in spec: if '+shared' in spec:
config_args.append('--with-ar=$(CXX) -shared $(LDFLAGS) -o')
config_args.append('RANLIB=echo') config_args.append('RANLIB=echo')
config_args.append('--with-ar=$(CXX) -shared $(LDFLAGS) -o')
config_cflags.append('-fPIC') config_cflags.append('-fPIC')
if spec.satisfies('%gcc'):
config_args.append('--with-libs={0}'.format('-lgfortran'))
if '+mpi' in spec: if '+mpi' in spec:
config_args.append('CC=%s/mpicc' % spec['mpi'].prefix.bin) config_args.append('CC={0}'.format(spec['mpi'].mpicc))
config_args.append('CXX=%s/mpicxx' % spec['mpi'].prefix.bin) config_args.append('CXX={0}'.format(spec['mpi'].mpicxx))
config_args.append('--with-mpi=%s' % spec['mpi'].prefix) config_args.append('FC={0}'.format(spec['mpi'].mpifc))
config_args.append('--with-mpi-compilers=%s' %
spec['mpi'].prefix.bin) mpi_libs = ' -l'.join(self.get_mpi_libs())
config_args.append('--with-mpi={0}'.format(spec['mpi'].prefix))
config_args.append('--with-mpi-libs=-l{0}'.format(mpi_libs))
# NOTE: Early versions of Zoltan come packaged with a few embedded # NOTE: Early versions of Zoltan come packaged with a few embedded
# library packages (e.g. ParMETIS, Scotch), which messes with Spack's # library packages (e.g. ParMETIS, Scotch), which messes with Spack's
# ability to descend directly into the package's source directory. # ability to descend directly into the package's source directory.
source_directory = self.stage.source_path
if spec.satisfies('@:3.6'): if spec.satisfies('@:3.6'):
cd('Zoltan_v%s' % self.version) zoltan_directory = 'Zoltan_v{0}'.format(self.version)
source_directory = join_path(source_directory, zoltan_directory)
mkdirp('build') build_directory = join_path(source_directory, 'build')
cd('build') with working_dir(build_directory, create=True):
config = Executable(join_path(source_directory, 'configure'))
config(
'--prefix={0}'.format(prefix),
'--with-cflags={0}'.format(' '.join(config_cflags)),
'--with-cxxflags={0}'.format(' '.join(config_cflags)),
'--with-fcflags={0}'.format(' '.join(config_cflags)),
*config_args
)
config_zoltan = Executable('../configure') # NOTE: Earlier versions of Zoltan cannot be built in parallel
config_zoltan( # because they contain nested Makefile dependency bugs.
'--prefix=%s' % pwd(), make(parallel=not spec.satisfies('@:3.6+fortran'))
'--with-cflags=%s' % ' '.join(config_cflags), make('install')
'--with-cxxflags=%s' % ' '.join(config_cflags),
*config_args)
make()
make('install')
# NOTE: Unfortunately, Zoltan doesn't provide any configuration # NOTE: Unfortunately, Zoltan doesn't provide any configuration
# options for the extension of the output library files, so this # options for the extension of the output library files, so this
# script must change these extensions as a post-processing step. # script must change these extensions as a post-processing step.
if '+shared' in spec: if '+shared' in spec:
for libpath in glob.glob('lib/*.a'): for lib_path in glob.glob(join_path(prefix, 'lib', '*.a')):
libdir, libname = (os.path.dirname(libpath), lib_static_name = os.path.basename(lib_path)
os.path.basename(libpath)) lib_shared_name = re.sub(r'\.a$', '.{0}'.format(dso_suffix),
move(libpath, os.path.join( lib_static_name)
libdir, re.sub(r'\.a$', '.so', libname))) move(lib_path, join_path(prefix, 'lib', lib_shared_name))
mkdirp(prefix) def get_config_flag(self, flag_name, flag_variant):
move('include', prefix) flag_pre = 'en' if '+{0}'.format(flag_variant) in self.spec else 'dis'
move('lib', prefix) return '--{0}able-{1}'.format(flag_pre, flag_name)
def url_for_version(self, version): # NOTE: Zoltan assumes that it's linking against an MPI library that can
return '%s/zoltan_distrib_v%s.tar.gz' % (Zoltan.base_url, version) # be found with '-lmpi,' which isn't the case for many MPI packages. This
# function finds the names of the actual libraries for Zoltan's MPI dep.
def get_mpi_libs(self):
mpi_libs = set()
for lib_path in glob.glob(join_path(self.spec['mpi'].prefix.lib, '*')):
mpi_lib_match = re.match(
r'^(lib)((\w*)mpi(\w*))\.((a)|({0}))$'.format(dso_suffix),
os.path.basename(lib_path))
if mpi_lib_match:
mpi_libs.add(mpi_lib_match.group(2))
return list(mpi_libs)