Merge pull request #993 from xjrc/packages/metis

Update Package : METIS/ParMETIS
This commit is contained in:
Todd Gamblin 2016-05-26 17:37:33 -05:00
commit 96f65479e7
3 changed files with 131 additions and 108 deletions

View file

@ -8,6 +8,9 @@
# - E221: multiple spaces before operator # - E221: multiple spaces before operator
# - E241: multiple spaces after , # - E241: multiple spaces after ,
# #
# Let people use terse Python features:
# - E731 : lambda expressions
#
# Spack allows wildcard imports: # Spack allows wildcard imports:
# - F403: disable wildcard import # - F403: disable wildcard import
# #
@ -16,5 +19,5 @@
# - F999: name name be undefined or undefined from star imports. # - F999: name name be undefined or undefined from star imports.
# #
[flake8] [flake8]
ignore = E221,E241,F403,F821,F999 ignore = E221,E241,E731,F403,F821,F999
max-line-length = 79 max-line-length = 79

View file

@ -24,55 +24,61 @@
############################################################################## ##############################################################################
from spack import * from spack import *
import glob, sys, os import glob
import sys
import os
class Metis(Package): class Metis(Package):
""" """METIS is a set of serial programs for partitioning graphs, partitioning
METIS is a set of serial programs for partitioning graphs, partitioning finite element meshes, and producing fill finite element meshes, and producing fill reducing orderings for sparse
reducing orderings for sparse matrices. The algorithms implemented in METIS are based on the multilevel matrices. The algorithms implemented in METIS are based on the
recursive-bisection, multilevel k-way, and multi-constraint partitioning schemes. multilevel recursive-bisection, multilevel k-way, and multi-constraint
""" partitioning schemes."""
homepage = 'http://glaros.dtc.umn.edu/gkhome/metis/metis/overview' homepage = "http://glaros.dtc.umn.edu/gkhome/metis/metis/overview"
url = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz" base_url = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis"
version('5.1.0', '5465e67079419a69e0116de24fce58fe', version('5.1.0', '5465e67079419a69e0116de24fce58fe')
url='http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz') version('5.0.2', 'acb521a4e8c2e6dd559a7f9abd0468c5')
version('4.0.3', '5efa35de80703c1b2c4d0de080fafbcf4e0d363a21149a1ad2f96e0144841a55', version('4.0.3', 'd3848b454532ef18dc83e4fb160d1e10')
url='http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/OLD/metis-4.0.3.tar.gz')
variant('shared', default=True, description='Enables the build of shared libraries') variant('shared', default=True, description='Enables the build of shared libraries')
variant('debug', default=False, description='Builds the library in debug mode') variant('debug', default=False, description='Builds the library in debug mode')
variant('gdb', default=False, description='Enables gdb support') variant('gdb', default=False, description='Enables gdb support')
variant('idx64', default=False, description='Use int64_t as default index type') variant('idx64', default=False, description='Use int64_t as default index type')
variant('double', default=False, description='Use double precision floating point types') variant('real64', default=False, description='Use double precision floating point types')
depends_on('cmake@2.8:', when='@5:') # build-time dependency depends_on('cmake@2.8:', when='@5:') # build-time dependency
depends_on('gdb', when='+gdb')
patch('install_gklib_defs_rename.patch', when='@5:') patch('install_gklib_defs_rename.patch', when='@5:')
def url_for_version(self, version):
verdir = 'OLD/' if version < Version('4.0.3') else ''
return '%s/%smetis-%s.tar.gz' % (Metis.base_url, verdir, version)
@when('@4:4.0.3') @when('@:4')
def install(self, spec, prefix): def install(self, spec, prefix):
# Process library spec and options
if '+gdb' in spec: unsupp_vars = [v for v in ('+gdb', '+idx64', '+real64') if v in spec]
raise InstallError('gdb support not implemented in METIS 4!') if unsupp_vars:
if '+idx64' in spec: msg = 'Given variants %s are unsupported by METIS 4!' % unsupp_vars
raise InstallError('idx64 option not implemented in METIS 4!') raise InstallError(msg)
if '+double' in spec:
raise InstallError('double option not implemented for METIS 4!')
options = ['COPTIONS=-fPIC'] options = ['COPTIONS=-fPIC']
if '+debug' in spec: if '+debug' in spec:
options.append('OPTFLAGS=-g -O0') options.append('OPTFLAGS=-g -O0')
make(*options) make(*options)
# Compile and install library files
ccompile = Executable(self.compiler.cc)
mkdir(prefix.bin) mkdir(prefix.bin)
for x in ('pmetis', 'kmetis', 'oemetis', 'onmetis', 'partnmesh', binfiles = ('pmetis', 'kmetis', 'oemetis', 'onmetis', 'partnmesh',
'partdmesh', 'mesh2nodal', 'mesh2dual', 'graphchk'): 'partdmesh', 'mesh2nodal', 'mesh2dual', 'graphchk')
install(x, prefix.bin) for binfile in binfiles:
install(binfile, prefix.bin)
mkdir(prefix.lib) mkdir(prefix.lib)
install('libmetis.a', prefix.lib) install('libmetis.a', prefix.lib)
@ -82,93 +88,107 @@ def install(self, spec, prefix):
install(h, prefix.include) install(h, prefix.include)
mkdir(prefix.share) mkdir(prefix.share)
for f in (join_path(*p) sharefiles = (('Graphs', '4elt.graph'), ('Graphs', 'metis.mesh'),
for p in (('Programs', 'io.c'), ('Graphs', 'test.mgraph'))
('Test','mtest.c'), for sharefile in tuple(join_path(*sf) for sf in sharefiles):
('Graphs','4elt.graph'), install(sharefile, prefix.share)
('Graphs', 'metis.mesh'),
('Graphs', 'test.mgraph'))):
install(f, prefix.share)
if '+shared' in spec: if '+shared' in spec:
shared_flags = ['-fPIC', '-shared']
if sys.platform == 'darwin': if sys.platform == 'darwin':
lib_dsuffix = 'dylib' shared_suffix = 'dylib'
load_flag = '-Wl,-all_load' shared_flags.extend(['-Wl,-all_load', 'libmetis.a'])
no_load_flag = ''
else: else:
lib_dsuffix = 'so' shared_suffix = 'so'
load_flag = '-Wl,-whole-archive' shared_flags.extend(['-Wl,-whole-archive', 'libmetis.a',
no_load_flag = '-Wl,-no-whole-archive' '-Wl,-no-whole-archive'])
os.system(spack_cc + ' -fPIC -shared ' + load_flag + shared_out = '%s/libmetis.%s' % (prefix.lib, shared_suffix)
' libmetis.a ' + no_load_flag + ' -o libmetis.' + shared_flags.extend(['-o', shared_out])
lib_dsuffix)
install('libmetis.' + lib_dsuffix, prefix.lib) ccompile(*shared_flags)
# Set up and run tests on installation # Set up and run tests on installation
symlink(join_path(prefix.share, 'io.c'), 'io.c') ccompile('-I%s' % prefix.include, '-L%s' % prefix.lib,
symlink(join_path(prefix.share, 'mtest.c'), 'mtest.c') '-Wl,-rpath=%s' % (prefix.lib if '+shared' in spec else ''),
os.system(spack_cc + ' -I%s' % prefix.include + ' -c io.c') join_path('Programs', 'io.o'), join_path('Test', 'mtest.c'),
os.system(spack_cc + ' -I%s' % prefix.include + '-o', '%s/mtest' % prefix.bin, '-lmetis', '-lm')
' -L%s' % prefix.lib + ' -lmetis mtest.c io.o -o mtest')
_4eltgraph = join_path(prefix.share, '4elt.graph')
test_mgraph = join_path(prefix.share, 'test.mgraph')
metis_mesh = join_path(prefix.share, 'metis.mesh')
kmetis = join_path(prefix.bin, 'kmetis')
os.system('./mtest ' + _4eltgraph)
os.system(kmetis + ' ' + _4eltgraph + ' 40')
os.system(join_path(prefix.bin, 'onmetis') + ' ' + _4eltgraph)
os.system(join_path(prefix.bin, 'pmetis') + ' ' + test_mgraph + ' 2')
os.system(kmetis + ' ' + test_mgraph + ' 2')
os.system(kmetis + ' ' + test_mgraph + ' 5')
os.system(join_path(prefix.bin, 'partnmesh') + metis_mesh + ' 10')
os.system(join_path(prefix.bin, 'partdmesh') + metis_mesh + ' 10')
os.system(join_path(prefix.bin, 'mesh2dual') + metis_mesh)
test_bin = lambda testname: join_path(prefix.bin, testname)
test_graph = lambda graphname: join_path(prefix.share, graphname)
graph = test_graph('4elt.graph')
os.system('%s %s' % (test_bin('mtest'), graph))
os.system('%s %s 40' % (test_bin('kmetis'), graph))
os.system('%s %s' % (test_bin('onmetis'), graph))
graph = test_graph('test.mgraph')
os.system('%s %s 2' % (test_bin('pmetis'), graph))
os.system('%s %s 2' % (test_bin('kmetis'), graph))
os.system('%s %s 5' % (test_bin('kmetis'), graph))
graph = test_graph('metis.mesh')
os.system('%s %s 10' % (test_bin('partnmesh'), graph))
os.system('%s %s 10' % (test_bin('partdmesh'), graph))
os.system('%s %s' % (test_bin('mesh2dual'), graph))
# FIXME: The following code should replace the testing code in the
# block above since it causes installs to fail when one or more of the
# Metis tests fail, but it currently doesn't work because the 'mtest',
# 'onmetis', and 'partnmesh' tests return error codes that trigger
# false positives for failure.
"""
Executable(test_bin('mtest'))(test_graph('4elt.graph'))
Executable(test_bin('kmetis'))(test_graph('4elt.graph'), '40')
Executable(test_bin('onmetis'))(test_graph('4elt.graph'))
Executable(test_bin('pmetis'))(test_graph('test.mgraph'), '2')
Executable(test_bin('kmetis'))(test_graph('test.mgraph'), '2')
Executable(test_bin('kmetis'))(test_graph('test.mgraph'), '5')
Executable(test_bin('partnmesh'))(test_graph('metis.mesh'), '10')
Executable(test_bin('partdmesh'))(test_graph('metis.mesh'), '10')
Executable(test_bin('mesh2dual'))(test_graph('metis.mesh'))
"""
@when('@5:') @when('@5:')
def install(self, spec, prefix): def install(self, spec, prefix):
options = [] options = []
options.extend(std_cmake_args) options.extend(std_cmake_args)
build_directory = join_path(self.stage.path, 'spack-build') build_directory = join_path(self.stage.path, 'spack-build')
source_directory = self.stage.source_path source_directory = self.stage.source_path
options.append('-DGKLIB_PATH:PATH={metis_source}/GKlib'.format(metis_source=source_directory)) options.append('-DGKLIB_PATH:PATH=%s/GKlib' % source_directory)
options.append('-DCMAKE_INSTALL_NAME_DIR:PATH=%s/lib' % prefix) options.append('-DCMAKE_INSTALL_NAME_DIR:PATH=%s/lib' % prefix)
if '+shared' in spec: if '+shared' in spec:
options.append('-DSHARED:BOOL=ON') options.append('-DSHARED:BOOL=ON')
if '+debug' in spec: if '+debug' in spec:
options.extend(['-DDEBUG:BOOL=ON', options.extend(['-DDEBUG:BOOL=ON',
'-DCMAKE_BUILD_TYPE:STRING=Debug']) '-DCMAKE_BUILD_TYPE:STRING=Debug'])
if '+gdb' in spec: if '+gdb' in spec:
options.append('-DGDB:BOOL=ON') options.append('-DGDB:BOOL=ON')
metis_header = join_path(source_directory, 'include', 'metis.h') metis_header = join_path(source_directory, 'include', 'metis.h')
if '+idx64' in spec: if '+idx64' in spec:
filter_file('IDXTYPEWIDTH 32', 'IDXTYPEWIDTH 64', metis_header) filter_file('IDXTYPEWIDTH 32', 'IDXTYPEWIDTH 64', metis_header)
if '+real64' in spec:
if '+double' in spec:
filter_file('REALTYPEWIDTH 32', 'REALTYPEWIDTH 64', metis_header) filter_file('REALTYPEWIDTH 32', 'REALTYPEWIDTH 64', metis_header)
# Make clang 7.3 happy. # Make clang 7.3 happy.
# Prevents "ld: section __DATA/__thread_bss extends beyond end of file" # Prevents "ld: section __DATA/__thread_bss extends beyond end of file"
# See upstream LLVM issue https://llvm.org/bugs/show_bug.cgi?id=27059 # See upstream LLVM issue https://llvm.org/bugs/show_bug.cgi?id=27059
# Adopted from https://github.com/Homebrew/homebrew-science/blob/master/metis.rb # and https://github.com/Homebrew/homebrew-science/blob/master/metis.rb
if spec.satisfies('%clang@7.3.0'): if spec.satisfies('%clang@7.3.0'):
filter_file('#define MAX_JBUFS 128', '#define MAX_JBUFS 24', join_path(source_directory, 'GKlib', 'error.c')) filter_file('#define MAX_JBUFS 128', '#define MAX_JBUFS 24',
join_path(source_directory, 'GKlib', 'error.c'))
with working_dir(build_directory, create=True): with working_dir(build_directory, create=True):
cmake(source_directory, *options) cmake(source_directory, *options)
make() make()
make("install") make('install')
# now run some tests: # now run some tests:
for f in ["4elt", "copter2", "mdual"]: for f in ['4elt', 'copter2', 'mdual']:
graph = join_path(source_directory, 'graphs', '%s.graph' % f) graph = join_path(source_directory, 'graphs', '%s.graph' % f)
Executable(join_path(prefix.bin, 'graphchk'))(graph) Executable(join_path(prefix.bin, 'graphchk'))(graph)
Executable(join_path(prefix.bin, 'gpmetis'))(graph, '2') Executable(join_path(prefix.bin, 'gpmetis'))(graph, '2')
@ -182,6 +202,6 @@ def install(self, spec, prefix):
# install GKlib headers, which will be needed for ParMETIS # install GKlib headers, which will be needed for ParMETIS
GKlib_dist = join_path(prefix.include, 'GKlib') GKlib_dist = join_path(prefix.include, 'GKlib')
mkdirp(GKlib_dist) mkdirp(GKlib_dist)
fs = glob.glob(join_path(source_directory,'GKlib',"*.h")) hfiles = glob.glob(join_path(source_directory, 'GKlib', '*.h'))
for f in fs: for hfile in hfiles:
install(f, GKlib_dist) install(hfile, GKlib_dist)

View file

@ -26,15 +26,17 @@
from spack import * from spack import *
import sys import sys
class Parmetis(Package): class Parmetis(Package):
""" """ParMETIS is an MPI-based parallel library that implements a variety of
ParMETIS is an MPI-based parallel library that implements a variety of algorithms for partitioning unstructured algorithms for partitioning unstructured graphs, meshes, and for
graphs, meshes, and for computing fill-reducing orderings of sparse matrices. computing fill-reducing orderings of sparse matrices."""
"""
homepage = 'http://glaros.dtc.umn.edu/gkhome/metis/parmetis/overview' homepage = 'http://glaros.dtc.umn.edu/gkhome/metis/parmetis/overview'
url = 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/parmetis/parmetis-4.0.3.tar.gz' base_url = 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/parmetis'
version('4.0.3', 'f69c479586bf6bb7aff6a9bc0c739628') version('4.0.3', 'f69c479586bf6bb7aff6a9bc0c739628')
version('4.0.2', '0912a953da5bb9b5e5e10542298ffdce')
variant('shared', default=True, description='Enables the build of shared libraries') variant('shared', default=True, description='Enables the build of shared libraries')
variant('debug', default=False, description='Builds the library in debug mode') variant('debug', default=False, description='Builds the library in debug mode')
@ -42,17 +44,18 @@ class Parmetis(Package):
depends_on('cmake@2.8:') # build dependency depends_on('cmake@2.8:') # build dependency
depends_on('mpi') depends_on('mpi')
patch('enable_external_metis.patch')
depends_on('metis@5:') depends_on('metis@5:')
patch('enable_external_metis.patch')
# bug fixes from PETSc developers # bug fixes from PETSc developers
# https://bitbucket.org/petsc/pkg-parmetis/commits/1c1a9fd0f408dc4d42c57f5c3ee6ace411eb222b/raw/ # https://bitbucket.org/petsc/pkg-parmetis/commits/1c1a9fd0f408dc4d42c57f5c3ee6ace411eb222b/raw/ # NOQA: ignore=E501
patch('pkg-parmetis-1c1a9fd0f408dc4d42c57f5c3ee6ace411eb222b.patch') patch('pkg-parmetis-1c1a9fd0f408dc4d42c57f5c3ee6ace411eb222b.patch')
# https://bitbucket.org/petsc/pkg-parmetis/commits/82409d68aa1d6cbc70740d0f35024aae17f7d5cb/raw/ # https://bitbucket.org/petsc/pkg-parmetis/commits/82409d68aa1d6cbc70740d0f35024aae17f7d5cb/raw/ # NOQA: ignore=E501
patch('pkg-parmetis-82409d68aa1d6cbc70740d0f35024aae17f7d5cb.patch') patch('pkg-parmetis-82409d68aa1d6cbc70740d0f35024aae17f7d5cb.patch')
depends_on('gdb', when='+gdb') def url_for_version(self, version):
verdir = 'OLD/' if version < Version('3.2.0') else ''
return '%s/%sparmetis-%s.tar.gz' % (Parmetis.base_url, verdir, version)
def install(self, spec, prefix): def install(self, spec, prefix):
options = [] options = []
@ -60,30 +63,27 @@ def install(self, spec, prefix):
build_directory = join_path(self.stage.path, 'spack-build') build_directory = join_path(self.stage.path, 'spack-build')
source_directory = self.stage.source_path source_directory = self.stage.source_path
metis_source = join_path(source_directory, 'metis')
# FIXME : Once a contract is defined, MPI compilers should be retrieved indirectly via spec['mpi'] in case options.extend([
# FIXME : they use a non-standard name '-DGKLIB_PATH:PATH=%s/GKlib' % spec['metis'].prefix.include,
options.extend(['-DGKLIB_PATH:PATH={metis_source}/GKlib'.format(metis_source=spec['metis'].prefix.include), '-DMETIS_PATH:PATH=%s' % spec['metis'].prefix,
'-DMETIS_PATH:PATH={metis_source}'.format(metis_source=spec['metis'].prefix), '-DCMAKE_C_COMPILER:STRING=%s' % spec['mpi'].mpicc,
'-DCMAKE_C_COMPILER:STRING=mpicc', '-DCMAKE_CXX_COMPILER:STRING=%s' % spec['mpi'].mpicxx
'-DCMAKE_CXX_COMPILER:STRING=mpicxx']) ])
if '+shared' in spec: if '+shared' in spec:
options.append('-DSHARED:BOOL=ON') options.append('-DSHARED:BOOL=ON')
if '+debug' in spec: if '+debug' in spec:
options.extend(['-DDEBUG:BOOL=ON', options.extend(['-DDEBUG:BOOL=ON',
'-DCMAKE_BUILD_TYPE:STRING=Debug']) '-DCMAKE_BUILD_TYPE:STRING=Debug'])
if '+gdb' in spec: if '+gdb' in spec:
options.append('-DGDB:BOOL=ON') options.append('-DGDB:BOOL=ON')
with working_dir(build_directory, create=True): with working_dir(build_directory, create=True):
cmake(source_directory, *options) cmake(source_directory, *options)
make() make()
make("install") make('install')
# The shared library is not installed correctly on Darwin; correct this # The shared library is not installed correctly on Darwin; fix this
if (sys.platform == 'darwin') and ('+shared' in spec): if (sys.platform == 'darwin') and ('+shared' in spec):
fix_darwin_install_name(prefix.lib) fix_darwin_install_name(prefix.lib)