spack/var/spack/repos/builtin/packages/metis/package.py
Kelly (KT) Thompson 322b016230 Provide build_type variant for Metis. (#6808)
* Provide build_type variant for Metis.

+ Ideally, we would make Metis a CMakePackage, but `metis@:5` doesn't use CMake.
+ For now, provide a `build_type=` variant similar what is found in
  CMakePackage.
+ There is a potential for duplicate specification of `CMAKE_BUILD_TYPE` if both
  variants `+debug` and `build_type=` are specified. I am looking for advice on
  how this can be resolved.

* Update metis recipe in response to flake8 and user comments.

+ Wrap comment lines that used more than 80 columns.
+ Change `+debug` variant to avoid potential for multiple `-DCMAKE_BUID_TYPE=`
  arguments provided to cmake.  Specifying this variant no longer appends this
  configure option.  However, if `+debug` is specified, require
  `build_type=Debug` to maintain expected behavior.

* For metis, remove +debug variant; use build_type= instead.

+ Update recipe for metis@4 to extract `build_type=` values and set `OPTFLAGS`
  accordingly.
+ For metis@5:, the behavior from the previously supported variant `+debug` can
  be obtained with the options `+gdb build_type=Debug`

* Conflicts added for metis@4 when build_type != Release|Debug.

* Use spack function conflicts instead of 'raise InstallError'.
2018-01-05 13:45:21 -06:00

244 lines
11 KiB
Python

##############################################################################
# Copyright (c) 2013-2017, 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/spack/spack
# Please also see the NOTICE and LICENSE files 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 *
import glob
import sys
import os
class Metis(Package):
"""METIS is a set of serial programs for partitioning graphs, partitioning
finite element meshes, and producing fill reducing orderings for sparse
matrices. The algorithms implemented in METIS are based on the
multilevel recursive-bisection, multilevel k-way, and multi-constraint
partitioning schemes."""
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"
list_url = "http://glaros.dtc.umn.edu/gkhome/fsroot/sw/metis/OLD"
version('5.1.0', '5465e67079419a69e0116de24fce58fe')
version('5.0.2', 'acb521a4e8c2e6dd559a7f9abd0468c5')
version('4.0.3', 'd3848b454532ef18dc83e4fb160d1e10')
variant('shared', default=True, description='Enables the build of shared libraries.')
variant('gdb', default=False, description='Enables gdb support (version 5+).')
variant('int64', default=False, description='Sets the bit width of METIS\'s index type to 64.')
variant('real64', default=False, description='Sets the bit width of METIS\'s real type to 64.')
# For Metis version 5:, the build system is CMake, provide the
# `build_type` variant.
variant('build_type', default='Release',
description='The build type for the installation (only Debug or'
' Release allowed for version 4).',
values=('Debug', 'Release', 'RelWithDebInfo', 'MinSizeRel'))
# Prior to version 5, the (non-cmake) build system only knows about
# 'build_type=Debug|Release'.
conflicts('@:4.999', when='build_type=RelWithDebInfo')
conflicts('@:4.999', when='build_type=MinSizeRel')
conflicts('@:4.999', when='+gdb')
conflicts('@:4.999', when='+int64')
conflicts('@:4.999', when='+real64')
depends_on('cmake@2.8:', when='@5:', type='build')
patch('install_gklib_defs_rename.patch', when='@5:')
def url_for_version(self, version):
url = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis"
if version < Version('4.0.3'):
url += "/OLD"
url += "/metis-{0}.tar.gz".format(version)
return url
@when('@5:')
def patch(self):
source_path = self.stage.source_path
metis_header = FileFilter(join_path(source_path, 'include', 'metis.h'))
metis_header.filter(
r'(\b)(IDXTYPEWIDTH )(\d+)(\b)',
r'\1\2{0}\4'.format('64' if '+int64' in self.spec else '32'),
)
metis_header.filter(
r'(\b)(REALTYPEWIDTH )(\d+)(\b)',
r'\1\2{0}\4'.format('64' if '+real64' in self.spec else '32'),
)
# Make clang 7.3 happy.
# Prevents "ld: section __DATA/__thread_bss extends beyond end of file"
# See upstream LLVM issue https://llvm.org/bugs/show_bug.cgi?id=27059
# and https://github.com/Homebrew/homebrew-science/blob/master/metis.rb
if self.spec.satisfies('%clang@7.3.0'):
filter_file('#define MAX_JBUFS 128', '#define MAX_JBUFS 24',
join_path(source_path, 'GKlib', 'error.c'))
@when('@:4')
def install(self, spec, prefix):
# Process library spec and options
options = ['COPTIONS={0}'.format(self.compiler.pic_flag)]
if spec.variants['build_type'].value == 'Debug':
options.append('OPTFLAGS=-g -O0')
make(*options)
# Compile and install library files
ccompile = Executable(self.compiler.cc)
mkdir(prefix.bin)
binfiles = ('pmetis', 'kmetis', 'oemetis', 'onmetis', 'partnmesh',
'partdmesh', 'mesh2nodal', 'mesh2dual', 'graphchk')
for binfile in binfiles:
install(binfile, prefix.bin)
mkdir(prefix.lib)
install('libmetis.a', prefix.lib)
mkdir(prefix.include)
for h in glob.glob(join_path('Lib', '*.h')):
install(h, prefix.include)
mkdir(prefix.share)
sharefiles = (('Graphs', '4elt.graph'), ('Graphs', 'metis.mesh'),
('Graphs', 'test.mgraph'))
for sharefile in tuple(join_path(*sf) for sf in sharefiles):
install(sharefile, prefix.share)
if '+shared' in spec:
shared_flags = [self.compiler.pic_flag, '-shared']
if sys.platform == 'darwin':
shared_suffix = 'dylib'
shared_flags.extend(['-Wl,-all_load', 'libmetis.a'])
else:
shared_suffix = 'so'
shared_flags.extend(['-Wl,-whole-archive', 'libmetis.a',
'-Wl,-no-whole-archive'])
shared_out = '%s/libmetis.%s' % (prefix.lib, shared_suffix)
shared_flags.extend(['-o', shared_out])
ccompile(*shared_flags)
# Set up and run tests on installation
ccompile('-I%s' % prefix.include, '-L%s' % prefix.lib,
self.compiler.cc_rpath_arg +
'%s' % (prefix.lib if '+shared' in spec else ''),
join_path('Programs', 'io.o'), join_path('Test', 'mtest.c'),
'-o', '%s/mtest' % prefix.bin, '-lmetis', '-lm')
if self.run_tests:
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:')
def install(self, spec, prefix):
source_directory = self.stage.source_path
build_directory = join_path(source_directory, 'build')
options = std_cmake_args[:]
options.append('-DGKLIB_PATH:PATH=%s/GKlib' % source_directory)
options.append('-DCMAKE_INSTALL_NAME_DIR:PATH=%s/lib' % prefix)
# Normally this is available via the 'CMakePackage' object, but metis
# IS-A 'Package' (not a 'CMakePackage') to support non-cmake metis@:5.
build_type = spec.variants['build_type'].value
options.extend(['-DCMAKE_BUILD_TYPE:STRING={0}'.format(build_type)])
if '+shared' in spec:
options.append('-DSHARED:BOOL=ON')
else:
# Remove all RPATH options
# (RPATHxxx options somehow trigger cmake to link dynamically)
rpath_options = []
for o in options:
if o.find('RPATH') >= 0:
rpath_options.append(o)
for o in rpath_options:
options.remove(o)
if '+gdb' in spec:
options.append('-DGDB:BOOL=ON')
with working_dir(build_directory, create=True):
cmake(source_directory, *options)
make()
make('install')
# install GKlib headers, which will be needed for ParMETIS
GKlib_dist = join_path(prefix.include, 'GKlib')
mkdirp(GKlib_dist)
hfiles = glob.glob(join_path(source_directory, 'GKlib', '*.h'))
for hfile in hfiles:
install(hfile, GKlib_dist)
if self.run_tests:
# FIXME: On some systems, the installed binaries for METIS cannot
# be executed without first being read.
ls = which('ls')
ls('-a', '-l', prefix.bin)
for f in ['4elt', 'copter2', 'mdual']:
graph = join_path(source_directory, 'graphs', '%s.graph' % f)
Executable(join_path(prefix.bin, 'graphchk'))(graph)
Executable(join_path(prefix.bin, 'gpmetis'))(graph, '2')
Executable(join_path(prefix.bin, 'ndmetis'))(graph)
graph = join_path(source_directory, 'graphs', 'test.mgraph')
Executable(join_path(prefix.bin, 'gpmetis'))(graph, '2')
graph = join_path(source_directory, 'graphs', 'metis.mesh')
Executable(join_path(prefix.bin, 'mpmetis'))(graph, '2')