New interface for passing build information among specs (#1875)

- Added a new interface for Specs to pass build information
  - Calls forwarded from Spec to Package are now explicit
  - Added descriptor within Spec to manage forwarding
  - Added state in Spec to maintain query information
  - Modified a few packages (the one involved in spack install pexsi) to showcase changes

- This uses an object wrapper to `spec` to implement the `libs` sub-calls.
  - wrapper is returned from `__getitem__` only if spec is concrete
  - allows packagers to access build information easily
This commit is contained in:
Massimiliano Culpo 2017-03-02 19:01:29 +01:00 committed by Todd Gamblin
parent 5ce926d2d1
commit ed582cef68
45 changed files with 390 additions and 148 deletions

View file

@ -374,3 +374,17 @@ def duplicate_stream(original):
:rtype: file like object
"""
return os.fdopen(os.dup(original.fileno()))
class ObjectWrapper(object):
"""Base class that wraps an object. Derived classes can add new behavior
while staying undercover.
This class is modeled after the stackoverflow answer:
- http://stackoverflow.com/a/1445289/771663
"""
def __init__(self, wrapped_object):
wrapped_cls = type(wrapped_object)
wrapped_name = wrapped_cls.__name__
self.__class__ = type(wrapped_name, (type(self), wrapped_cls), {})
self.__dict__ = wrapped_object.__dict__

View file

@ -42,7 +42,6 @@
import sys
import textwrap
import time
from StringIO import StringIO
import llnl.util.lock
import llnl.util.tty as tty
@ -57,6 +56,7 @@
import spack.repository
import spack.url
import spack.util.web
from StringIO import StringIO
from llnl.util.filesystem import *
from llnl.util.lang import *
from llnl.util.link_tree import LinkTree
@ -1053,6 +1053,10 @@ def do_fake_install(self):
touch(join_path(self.prefix.bin, 'fake'))
mkdirp(self.prefix.include)
mkdirp(self.prefix.lib)
library_name = 'lib' + self.name
dso_suffix = 'dylib' if sys.platform == 'darwin' else 'so'
touch(join_path(self.prefix.lib, library_name + dso_suffix))
touch(join_path(self.prefix.lib, library_name + '.a'))
mkdirp(self.prefix.man1)
def _if_make_target_execute(self, target):

View file

@ -96,32 +96,35 @@
expansion when it is the first character in an id typed on the command line.
"""
import base64
import hashlib
import collections
import csv
import ctypes
from StringIO import StringIO
import hashlib
import itertools
from operator import attrgetter
from yaml.error import MarkedYAMLError
import cStringIO
import llnl.util.tty as tty
from llnl.util.lang import *
from llnl.util.tty.color import *
import spack
import spack.architecture
import spack.store
import spack.compilers as compilers
import spack.error
import spack.parse
from spack.build_environment import get_path_from_module, load_module
from spack.util.prefix import Prefix
from spack.util.string import *
import spack.util.spack_yaml as syaml
import spack.store
import spack.util.spack_json as sjson
from spack.util.spack_yaml import syaml_dict
from spack.util.crypto import prefix_bits
from spack.version import *
import spack.util.spack_yaml as syaml
from cStringIO import StringIO
from llnl.util.filesystem import find_libraries
from llnl.util.lang import *
from llnl.util.tty.color import *
from spack.build_environment import get_path_from_module, load_module
from spack.provider_index import ProviderIndex
from spack.util.crypto import prefix_bits
from spack.util.prefix import Prefix
from spack.util.spack_yaml import syaml_dict
from spack.util.string import *
from spack.version import *
from yaml.error import MarkedYAMLError
__all__ = [
'Spec',
@ -750,6 +753,161 @@ def __str__(self):
return "{deps: %s}" % ', '.join(str(d) for d in sorted(self.values()))
def _libs_default_handler(descriptor, spec, cls):
"""Default handler when looking for 'libs' attribute. The default
tries to search for 'lib{spec.name}' recursively starting from
`spec.prefix`.
:param ForwardQueryToPackage descriptor: descriptor that triggered
the call
:param Spec spec: spec that is being queried
:param type(spec) cls: type of spec, to match the signature of the
descriptor `__get__` method
"""
name = 'lib' + spec.name
shared = '+shared' in spec
return find_libraries(
[name], root=spec.prefix, shared=shared, recurse=True
)
def _cppflags_default_handler(descriptor, spec, cls):
"""Default handler when looking for cppflags attribute. The default
just returns '-I{spec.prefix.include}'.
:param ForwardQueryToPackage descriptor: descriptor that triggered
the call
:param Spec spec: spec that is being queried
:param type(spec) cls: type of spec, to match the signature of the
descriptor `__get__` method
"""
return '-I' + spec.prefix.include
class ForwardQueryToPackage(object):
"""Descriptor used to forward queries from Spec to Package"""
def __init__(self, attribute_name, default_handler=None):
"""Initializes the instance of the descriptor
:param str attribute_name: name of the attribute to be
searched for in the Package instance
:param callable default_handler: [optional] default function
to be called if the attribute was not found in the Package
instance
"""
self.attribute_name = attribute_name
# Turn the default handler into a function with the right
# signature that always returns None
if default_handler is None:
default_handler = lambda descriptor, spec, cls: None
self.default = default_handler
def __get__(self, instance, cls):
"""Retrieves the property from Package using a well defined chain
of responsibility.
The order of call is :
1. if the query was through the name of a virtual package try to
search for the attribute `{virtual_name}_{attribute_name}`
in Package
2. try to search for attribute `{attribute_name}` in Package
3. try to call the default handler
The first call that produces a value will stop the chain.
If no call can handle the request or a None value is produced,
then AttributeError is raised.
"""
pkg = instance.package
try:
query = instance.last_query
except AttributeError:
# There has been no query yet: this means
# a spec is trying to access its own attributes
_ = instance[instance.name] # NOQA: ignore=F841
query = instance.last_query
callbacks_chain = []
# First in the chain : specialized attribute for virtual packages
if query.isvirtual:
specialized_name = '{0}_{1}'.format(
query.name, self.attribute_name
)
callbacks_chain.append(lambda: getattr(pkg, specialized_name))
# Try to get the generic method from Package
callbacks_chain.append(lambda: getattr(pkg, self.attribute_name))
# Final resort : default callback
callbacks_chain.append(lambda: self.default(self, instance, cls))
# Trigger the callbacks in order, the first one producing a
# value wins
value = None
for f in callbacks_chain:
try:
value = f()
break
except AttributeError:
pass
# 'None' value raises AttributeError : this permits to 'disable'
# the call in a particular package by returning None from the
# queried attribute, or will trigger an exception if things
# searched for were not found
if value is None:
fmt = '\'{name}\' package has no relevant attribute \'{query}\'\n' # NOQA: ignore=E501
fmt += '\tspec : \'{spec}\'\n'
fmt += '\tqueried as : \'{spec.last_query.name}\'\n'
fmt += '\textra parameters : \'{spec.last_query.extra_parameters}\'\n' # NOQA: ignore=E501
message = fmt.format(
name=pkg.name,
query=self.attribute_name,
spec=instance
)
raise AttributeError(message)
return value
def __set__(self, instance, value):
cls_name = type(instance).__name__
msg = "'{0}' object attribute '{1}' is read-only"
raise AttributeError(msg.format(cls_name, self.attribute_name))
class SpecBuildInterface(ObjectWrapper):
libs = ForwardQueryToPackage(
'libs',
default_handler=_libs_default_handler
)
cppflags = ForwardQueryToPackage(
'cppflags',
default_handler=_cppflags_default_handler
)
def __init__(self, spec, name, query_parameters):
super(SpecBuildInterface, self).__init__(spec)
# Represents a query state in a BuildInterface object
QueryState = collections.namedtuple(
'QueryState', ['name', 'extra_parameters', 'isvirtual']
)
is_virtual = Spec.is_virtual(name)
self._query_to_package = QueryState(
name=name,
extra_parameters=query_parameters,
isvirtual=is_virtual
)
@property
def last_query(self):
return self._query_to_package
@key_ordering
class Spec(object):
@ -818,14 +976,6 @@ def __init__(self, spec_like, *dep_like, **kwargs):
self._add_dependency(spec, deptypes)
deptypes = ()
def __getattr__(self, item):
"""Delegate to self.package if the attribute is not in the spec"""
# This line is to avoid infinite recursion in case package is
# not present among self attributes
if item.endswith('libs'):
return getattr(self.package, item)
raise AttributeError(item)
def get_dependency(self, name):
dep = self._dependencies.get(name)
if dep is not None:
@ -2239,22 +2389,46 @@ def version(self):
return self.versions[0]
def __getitem__(self, name):
"""Get a dependency from the spec by its name."""
for spec in self.traverse():
if spec.name == name:
return spec
"""Get a dependency from the spec by its name. This call implicitly
sets a query state in the package being retrieved. The behavior of
packages may be influenced by additional query parameters that are
passed after a colon symbol.
if Spec.is_virtual(name):
# TODO: this is a kind of kludgy way to find providers
# TODO: should we just keep virtual deps in the DAG instead of
# TODO: removing them on concretize?
for spec in self.traverse():
if spec.virtual:
continue
if spec.package.provides(name):
return spec
Note that if a virtual package is queried a copy of the Spec is
returned while for non-virtual a reference is returned.
"""
query_parameters = name.split(':')
if len(query_parameters) > 2:
msg = 'key has more than one \':\' symbol.'
msg += ' At most one is admitted.'
raise KeyError(msg)
raise KeyError("No spec with name %s in %s" % (name, self))
name, query_parameters = query_parameters[0], query_parameters[1:]
if query_parameters:
# We have extra query parameters, which are comma separated
# values
f = cStringIO.StringIO(query_parameters.pop())
try:
query_parameters = next(csv.reader(f, skipinitialspace=True))
except StopIteration:
query_parameters = ['']
try:
value = next(
itertools.chain(
# Regular specs
(x for x in self.traverse() if x.name == name),
(x for x in self.traverse()
if (not x.virtual) and x.package.provides(name))
)
)
except StopIteration:
raise KeyError("No spec with name %s in %s" % (name, self))
if self._concrete:
return SpecBuildInterface(value, name, query_parameters)
return value
def __contains__(self, spec):
"""True if this spec satisfies the provided spec, or if any dependency

View file

@ -103,6 +103,18 @@ def _mock_remove(spec):
spec.package.do_uninstall(spec)
def test_default_queries(database):
install_db = database.mock.db
rec = install_db.get_record('zmpi')
spec = rec.spec
libraries = spec['zmpi'].libs
assert len(libraries) == 1
cppflags_expected = '-I' + spec.prefix.include
assert spec['zmpi'].cppflags == cppflags_expected
def test_005_db_exists(database):
"""Make sure db cache file exists after creating."""
install_path = database.mock.path

View file

@ -24,9 +24,6 @@
##############################################################################
"""
These tests check Spec DAG operations using dummy packages.
You can find the dummy packages here::
spack/lib/spack/spack/test/mock_packages
"""
import pytest
import spack
@ -690,3 +687,47 @@ def test_copy_deptypes(self):
s4 = s3.copy()
self.check_diamond_deptypes(s4)
def test_getitem_query(self):
s = Spec('mpileaks')
s.concretize()
# Check a query to a non-virtual package
a = s['callpath']
query = a.last_query
assert query.name == 'callpath'
assert len(query.extra_parameters) == 0
assert not query.isvirtual
# Check a query to a virtual package
a = s['mpi']
query = a.last_query
assert query.name == 'mpi'
assert len(query.extra_parameters) == 0
assert query.isvirtual
# Check a query to a virtual package with
# extra parameters after query
a = s['mpi:cxx,fortran']
query = a.last_query
assert query.name == 'mpi'
assert len(query.extra_parameters) == 2
assert 'cxx' in query.extra_parameters
assert 'fortran' in query.extra_parameters
assert query.isvirtual
def test_getitem_exceptional_paths(self):
s = Spec('mpileaks')
s.concretize()
# Needed to get a proxy object
q = s['mpileaks']
# Test that the attribute is read-only
with pytest.raises(AttributeError):
q.libs = 'foo'
with pytest.raises(AttributeError):
q.libs

View file

@ -42,6 +42,9 @@ class Mpileaks(Package):
depends_on("mpi")
depends_on("callpath")
# Will be used to try raising an exception
libs = None
def install(self, spec, prefix):
pass

View file

@ -127,13 +127,13 @@ def install(self, spec, prefix):
# BLAS/LAPACK
if '+scalapack' in spec:
oapp("--with-linalg-flavor=custom+scalapack")
linalg = (spec['scalapack'].scalapack_libs +
spec['lapack'].lapack_libs + spec['blas'].blas_libs)
linalg = (spec['scalapack'].libs +
spec['lapack'].libs + spec['blas'].libs)
# elif '+elpa' in spec:
else:
oapp("--with-linalg-flavor=custom")
linalg = spec['lapack'].lapack_libs + spec['blas'].blas_libs
linalg = spec['lapack'].libs + spec['blas'].libs
oapp("--with-linalg-libs=%s" % linalg.ld_flags)

View file

@ -55,9 +55,9 @@ def install(self, spec, prefix):
# ARPACK support
'-DARPACK_LIBRARY={0}'.format(arpack.joined()),
# BLAS support
'-DBLAS_LIBRARY={0}'.format(spec['blas'].blas_libs.joined()),
'-DBLAS_LIBRARY={0}'.format(spec['blas'].libs.joined()),
# LAPACK support
'-DLAPACK_LIBRARY={0}'.format(spec['lapack'].lapack_libs.joined()),
'-DLAPACK_LIBRARY={0}'.format(spec['lapack'].libs.joined()),
# SuperLU support
'-DSuperLU_INCLUDE_DIR={0}'.format(spec['superlu'].prefix.include),
'-DSuperLU_LIBRARY={0}'.format(superlu.joined()),

View file

@ -88,8 +88,8 @@ def install(self, spec, prefix):
options.append('-DCMAKE_INSTALL_NAME_DIR:PATH=%s/lib' % prefix)
# Make sure we use Spack's blas/lapack:
lapack_libs = spec['lapack'].lapack_libs.joined(';')
blas_libs = spec['blas'].blas_libs.joined(';')
lapack_libs = spec['lapack'].libs.joined(';')
blas_libs = spec['blas'].libs.joined(';')
options.extend([
'-DLAPACK_FOUND=true',
@ -129,8 +129,8 @@ def install(self, spec, prefix):
])
options.extend([
'--with-blas={0}'.format(spec['blas'].blas_libs.ld_flags),
'--with-lapack={0}'.format(spec['lapack'].lapack_libs.ld_flags)
'--with-blas={0}'.format(spec['blas'].libs.ld_flags),
'--with-lapack={0}'.format(spec['lapack'].libs.ld_flags)
])
if '+shared' not in spec:
options.append('--enable-shared=no')

View file

@ -112,8 +112,7 @@ def install(self, spec, prefix):
make("install")
self.install_test()
@property
def blas_libs(self):
def libs(self):
# libsatlas.[so,dylib,dll ] contains all serial APIs (serial lapack,
# serial BLAS), and all ATLAS symbols needed to support them. Whereas
# libtatlas.[so,dylib,dll ] is parallel (multithreaded) version.
@ -135,10 +134,6 @@ def blas_libs(self):
to_find, root=self.prefix, shared=shared, recurse=True
)
@property
def lapack_libs(self):
return self.blas_libs
def install_test(self):
source_file = join_path(os.path.dirname(self.module.__file__),
'test_cblas_dgemm.c')
@ -146,7 +141,7 @@ def install_test(self):
'test_cblas_dgemm.output')
include_flags = ["-I%s" % self.spec.prefix.include]
link_flags = self.lapack_libs.ld_flags.split()
link_flags = self.libs.ld_flags.split()
output = compile_c_and_execute(source_file, include_flags, link_flags)
compare_output_file(output, blessed_file)

View file

@ -49,7 +49,7 @@ class Atompaw(Package):
def install(self, spec, prefix):
options = ['--prefix=%s' % prefix]
linalg = spec['lapack'].lapack_libs + spec['blas'].blas_libs
linalg = spec['lapack'].libs + spec['blas'].libs
options.extend([
"--with-linalg-libs=%s" % linalg.ld_flags,
"--enable-libxc",

View file

@ -85,7 +85,7 @@ def install(self, spec, prefix):
# BLAS/LAPACK support
if '+lapack' in spec:
lapack_blas = spec['lapack'].lapack_libs + spec['blas'].blas_libs
lapack_blas = spec['lapack'].libs + spec['blas'].libs
options.extend([
'blas_lapack_libs={0}'.format(','.join(lapack_blas.names)),
'blas_lapack_dir={0}'.format(spec['lapack'].prefix.lib)

View file

@ -88,12 +88,10 @@ def install(self, spec, prefix):
cppflags = [
'-D__FFTW3',
'-D__LIBINT',
'-I' + spec['fftw'].prefix.include
spec['fftw'].cppflags
]
fcflags = copy.deepcopy(optflags[self.spec.compiler.name])
fcflags.extend([
'-I' + spec['fftw'].prefix.include
])
fcflags.append(spec['fftw'].cppflags)
fftw = find_libraries(['libfftw3'], root=spec['fftw'].prefix.lib)
ldflags = [fftw.search_flags]
libs = [
@ -154,15 +152,17 @@ def install(self, spec, prefix):
'-D__SCALAPACK'
])
fcflags.extend([
# spec['elpa:fortran'].cppflags
'-I' + join_path(
spec['elpa'].prefix,
'include',
'elpa-{0}'.format(str(spec['elpa'].version)),
'modules'
),
# spec[pexsi:fortran].cppflags
'-I' + join_path(spec['pexsi'].prefix, 'fortran')
])
scalapack = spec['scalapack'].scalapack_libs
scalapack = spec['scalapack'].libs
ldflags.append(scalapack.search_flags)
libs.extend([
join_path(spec['elpa'].prefix.lib,
@ -184,8 +184,8 @@ def install(self, spec, prefix):
libs.extend(self.spec['mpi'].mpicxx_shared_libs)
libs.extend(self.compiler.stdcxx_libs)
# LAPACK / BLAS
lapack = spec['lapack'].lapack_libs
blas = spec['blas'].blas_libs
lapack = spec['lapack'].libs
blas = spec['blas'].libs
ldflags.append((lapack + blas).search_flags)
libs.extend([str(x) for x in (fftw, lapack, blas)])

View file

@ -145,7 +145,7 @@ def cmake_args(self):
options = []
cxx_flags = []
lapack_blas = spec['lapack'].lapack_libs + spec['blas'].blas_libs
lapack_blas = spec['lapack'].libs + spec['blas'].libs
options.extend([
'-DDEAL_II_COMPONENT_EXAMPLES=ON',
'-DDEAL_II_WITH_THREADS:BOOL=ON',

View file

@ -90,9 +90,9 @@ def configure(self, spec):
blas = 'blas.a'
lapack = 'lapack.a'
if '+blas' in spec:
blas = spec['blas'].blas_libs.joined()
blas = spec['blas'].libs.joined()
if '+lapack' in spec:
lapack = spec['lapack'].lapack_libs.joined()
lapack = spec['lapack'].libs.joined()
# lapack must come before blas
config['LIB_LPK'] = ' '.join([lapack, blas])

View file

@ -59,16 +59,16 @@ def install(self, spec, prefix):
'FC={0}'.format(self.spec['mpi'].mpifc),
'CXX={0}'.format(self.spec['mpi'].mpicxx),
'FCFLAGS={0}'.format(
spec['lapack'].lapack_libs.joined()
spec['lapack'].libs.joined()
),
'LDFLAGS={0}'.format(
spec['lapack'].lapack_libs.joined()
spec['lapack'].libs.joined()
),
'SCALAPACK_FCFLAGS={0}'.format(
spec['scalapack'].scalapack_libs.joined()
spec['scalapack'].libs.joined()
),
'SCALAPACK_LDFLAGS={0}'.format(
spec['scalapack'].scalapack_libs.joined()
spec['scalapack'].libs.joined()
),
'--prefix={0}'.format(self.prefix)
]

View file

@ -88,7 +88,7 @@ def cmake_args(self):
options.append('-DENABLE_OS_SPECIFIC_INSTALL=OFF')
# Make sure GMSH picks up correct BlasLapack by providing linker flags
blas_lapack = spec['lapack'].lapack_libs + spec['blas'].blas_libs
blas_lapack = spec['lapack'].libs + spec['blas'].libs
options.append(
'-DBLAS_LAPACK_LIBRARIES={0}'.format(blas_lapack.ld_flags))

View file

@ -78,7 +78,7 @@ def configure(self, spec, arch):
'MPlib = -L{0}'.format(spec['mpi'].prefix.lib),
# Linear Algebra library (BLAS or VSIPL)
'LAinc = {0}'.format(spec['blas'].prefix.include),
'LAlib = {0}'.format(spec['blas'].blas_libs.joined()),
'LAlib = {0}'.format(spec['blas'].libs.joined()),
# F77 / C interface
'F2CDEFS = -DAdd_ -DF77_INTEGER=int -DStringSunStyle',
# HPL includes / libraries / specifics

View file

@ -62,8 +62,8 @@ def install(self, spec, prefix):
os.environ['F77'] = spec['mpi'].mpif77
# Note: --with-(lapack|blas)_libs= needs space separated list of names
lapack = spec['lapack'].lapack_libs
blas = spec['blas'].blas_libs
lapack = spec['lapack'].libs
blas = spec['blas'].libs
configure_args = [
'--prefix=%s' % prefix,

View file

@ -83,7 +83,7 @@ def blas_libs(self):
@property
def lapack_libs(self):
return self.blas_libs
return self.libs
@property
def scalapack_libs(self):

View file

@ -127,7 +127,7 @@ def blas_libs(self):
@property
def lapack_libs(self):
return self.blas_libs
return self.libs
@property
def scalapack_libs(self):

View file

@ -53,8 +53,8 @@ def install(self, spec, prefix):
mumps_flags = "-ldmumps -lmumps_common -lpord -lmpiseq"
mumps_libcmd = "-L%s " % mumps_dir.lib + mumps_flags
blas_lib = spec['blas'].blas_libs.ld_flags
lapack_lib = spec['lapack'].lapack_libs.ld_flags
blas_lib = spec['blas'].libs.ld_flags
lapack_lib = spec['lapack'].libs.ld_flags
configure_args = [
"--prefix=%s" % prefix,

View file

@ -102,7 +102,7 @@ def install(self, spec, prefix):
options = ['PREFIX=%s' % prefix]
if '+lapack' in spec:
lapack_lib = (spec['lapack'].lapack_libs + spec['blas'].blas_libs).ld_flags # NOQA: ignore=E501
lapack_lib = (spec['lapack'].libs + spec['blas'].libs).ld_flags # NOQA: ignore=E501
options.extend([
'MFEM_USE_LAPACK=YES',
'LAPACK_OPT=-I%s' % spec['lapack'].prefix.include,

View file

@ -82,8 +82,8 @@ def write_makefile_inc(self):
raise RuntimeError(
'You cannot use the variants parmetis or ptscotch without mpi')
lapack_blas = (self.spec['lapack'].lapack_libs +
self.spec['blas'].blas_libs)
lapack_blas = (self.spec['lapack'].libs +
self.spec['blas'].libs)
makefile_conf = ["LIBBLAS = %s" % lapack_blas.ld_flags]
orderings = ['-Dpord']
@ -156,7 +156,7 @@ def write_makefile_inc(self):
'OPTC = %s -O ' % fpic])
if '+mpi' in self.spec:
scalapack = self.spec['scalapack'].scalapack_libs
scalapack = self.spec['scalapack'].libs
makefile_conf.extend(
['CC = {0}'.format(self.spec['mpi'].mpicc),
'FC = {0}'.format(self.spec['mpi'].mpifc),

View file

@ -113,7 +113,7 @@ def install_one(self, spec, prefix, shared):
if '+external-blas' in spec:
cmake_args.extend([
'-DUSE_OPTIMIZED_BLAS:BOOL=ON',
'-DBLAS_LIBRARIES:PATH=%s' % spec['blas'].blas_libs.joined(';')
'-DBLAS_LIBRARIES:PATH=%s' % spec['blas'].libs.joined(';')
])
cmake_args.extend(std_cmake_args)

View file

@ -74,8 +74,8 @@ def install(self, spec, prefix):
]
# Make sure we use Spack's Lapack:
blas = spec['blas'].blas_libs
lapack = spec['lapack'].lapack_libs
blas = spec['blas'].libs
lapack = spec['lapack'].libs
options.extend([
'-DLAPACK_FOUND=true',
'-DLAPACK_INCLUDE_DIRS=%s' % spec['lapack'].prefix.include,

View file

@ -73,9 +73,9 @@ class Nwchem(Package):
patch(url, when=condition, level=0, md5=md5)
def install(self, spec, prefix):
scalapack = spec['scalapack'].scalapack_libs
lapack = spec['lapack'].lapack_libs
blas = spec['blas'].blas_libs
scalapack = spec['scalapack'].libs
lapack = spec['lapack'].libs
blas = spec['blas'].libs
# see http://www.nwchem-sw.org/index.php/Compiling_NWChem
args = []
args.extend([

View file

@ -108,8 +108,8 @@ def configure_args(self):
# Required dependencies
config_args.extend([
"--with-blas=%s" % spec['blas'].blas_libs.ld_flags,
"--with-lapack=%s" % spec['lapack'].lapack_libs.ld_flags
"--with-blas=%s" % spec['blas'].libs.ld_flags,
"--with-lapack=%s" % spec['lapack'].libs.ld_flags
])
# Strongly recommended dependencies

View file

@ -71,8 +71,8 @@ def url_for_version(self, version):
def install(self, spec, prefix):
arpack = find_libraries(['libarpack'], root=spec[
'arpack-ng'].prefix.lib, shared=True)
lapack = spec['lapack'].lapack_libs
blas = spec['blas'].blas_libs
lapack = spec['lapack'].libs
blas = spec['blas'].libs
args = []
args.extend([
'--prefix=%s' % prefix,
@ -105,8 +105,8 @@ def install(self, spec, prefix):
])
if '+scalapack' in spec:
args.extend([
'--with-blacs=%s' % spec['scalapack'].scalapack_libs,
'--with-scalapack=%s' % spec['scalapack'].scalapack_libs,
'--with-blacs=%s' % spec['scalapack'].libs,
'--with-scalapack=%s' % spec['scalapack'].libs,
])
# --with-etsf-io-prefix=
# --with-sparskit=${prefix}/lib/libskit.a

View file

@ -59,17 +59,6 @@ class Openblas(MakefilePackage):
parallel = False
@property
def blas_libs(self):
shared = True if '+shared' in self.spec else False
return find_libraries(
['libopenblas'], root=self.prefix, shared=shared, recurse=True
)
@property
def lapack_libs(self):
return self.blas_libs
@run_before('edit')
def check_compilers(self):
# As of 06/2016 there is no mechanism to specify that packages which
@ -151,13 +140,15 @@ def check_install(self):
blessed_file = join_path(os.path.dirname(self.module.__file__),
'test_cblas_dgemm.output')
include_flags = ["-I%s" % join_path(spec.prefix, "include")]
link_flags = self.lapack_libs.ld_flags.split()
include_flags = spec.cppflags
link_flags = spec.libs.ld_flags
if self.compiler.name == 'intel':
link_flags.extend(["-lifcore"])
link_flags.extend(["-lpthread"])
link_flags += ' -lifcore'
link_flags += ' -lpthread'
if '+openmp' in spec:
link_flags.extend([self.compiler.openmp_flag])
link_flags += ' ' + self.compiler.openmp_flag
output = compile_c_and_execute(source_file, include_flags, link_flags)
output = compile_c_and_execute(
source_file, [include_flags], link_flags.split()
)
compare_output_file(output, blessed_file)

View file

@ -116,6 +116,18 @@ def url_for_version(self, version):
return "http://www.open-mpi.org/software/ompi/v%s/downloads/openmpi-%s.tar.bz2" % (
version.up_to(2), version)
@property
def libs(self):
query_parameters = self.spec.last_query.extra_parameters
libraries = ['libmpi']
if 'cxx' in query_parameters:
libraries = ['libmpi_cxx'] + libraries
return find_libraries(
libraries, root=self.prefix, shared=True, recurse=True
)
def setup_dependent_environment(self, spack_env, run_env, dependent_spec):
spack_env.set('MPICC', join_path(self.prefix.bin, 'mpicc'))
spack_env.set('MPICXX', join_path(self.prefix.bin, 'mpic++'))

View file

@ -37,7 +37,7 @@ class Opium(Package):
depends_on('lapack')
def install(self, spec, prefix):
libs = spec['lapack'].lapack_libs + spec['blas'].blas_libs
libs = spec['lapack'].libs + spec['blas'].libs
options = ['LDFLAGS=%s' % libs.ld_flags]
configure(*options)

View file

@ -161,7 +161,7 @@ def install(self, spec, prefix):
])
# Make sure we use exactly the same Blas/Lapack libraries
# across the DAG. To that end list them explicitly
lapack_blas = spec['lapack'].lapack_libs + spec['blas'].blas_libs
lapack_blas = spec['lapack'].libs + spec['blas'].libs
options.extend([
'--with-blas-lapack-lib=%s' % lapack_blas.joined()
])

View file

@ -36,7 +36,7 @@ DSUPERLU_INCLUDE = -I${DSUPERLU_DIR}/include
INCLUDES = ${PEXSI_INCLUDE} ${DSUPERLU_INCLUDE}
# Libraries
CPP_LIB = @STDCXX_LIB @MPICXX_LIB
CPP_LIB = @MPICXX_LIB @STDCXX_LIB
#GFORTRAN_LIB = /usr/lib/gcc/x86_64-linux-gnu/4.8/libgfortran.a
LAPACK_LIB = @LAPACK_LIBS
BLAS_LIB = @BLAS_LIBS

View file

@ -59,7 +59,7 @@ def install(self, spec, prefix):
'@MPICC': self.spec['mpi'].mpicc,
'@MPICXX': self.spec['mpi'].mpicxx,
'@MPIFC': self.spec['mpi'].mpifc,
'@MPICXX_LIB': ' '.join(self.spec['mpi'].mpicxx_shared_libs),
'@MPICXX_LIB': self.spec['mpi:cxx'].libs.joined(),
'@RANLIB': 'ranlib',
'@PEXSI_STAGE': self.stage.source_path,
'@SUPERLU_PREFIX': self.spec['superlu-dist'].prefix,
@ -67,8 +67,9 @@ def install(self, spec, prefix):
'@PARMETIS_PREFIX': self.spec['parmetis'].prefix,
'@LAPACK_PREFIX': self.spec['lapack'].prefix,
'@BLAS_PREFIX': self.spec['blas'].prefix,
'@LAPACK_LIBS': self.spec['lapack'].lapack_libs.joined(),
'@BLAS_LIBS': self.spec['lapack'].blas_libs.joined(),
'@LAPACK_LIBS': self.spec['lapack'].libs.joined(),
'@BLAS_LIBS': self.spec['blas'].libs.joined(),
# FIXME : what to do with compiler provided libraries ?
'@STDCXX_LIB': ' '.join(self.compiler.stdcxx_libs)
}

View file

@ -62,10 +62,10 @@ class Psi4(Package):
def install(self, spec, prefix):
cmake_args = [
'-DBLAS_TYPE={0}'.format(spec['blas'].name.upper()),
'-DBLAS_LIBRARIES={0}'.format(spec['blas'].blas_libs.joined()),
'-DBLAS_LIBRARIES={0}'.format(spec['blas'].libs.joined()),
'-DLAPACK_TYPE={0}'.format(spec['lapack'].name.upper()),
'-DLAPACK_LIBRARIES={0}'.format(
spec['lapack'].lapack_libs.joined()),
spec['lapack'].libs.joined()),
'-DBOOST_INCLUDEDIR={0}'.format(spec['boost'].prefix.include),
'-DBOOST_LIBRARYDIR={0}'.format(spec['boost'].prefix.lib),
'-DENABLE_CHEMPS2=OFF'

View file

@ -70,10 +70,10 @@ def patch(self):
# for build notes see http://www.scipy.org/scipylib/building/linux.html
lapackblas = LibraryList('')
if '+lapack' in spec:
lapackblas += spec['lapack'].lapack_libs
lapackblas += spec['lapack'].libs
if '+blas' in spec:
lapackblas += spec['blas'].blas_libs
lapackblas += spec['blas'].libs
if '+blas' in spec or '+lapack' in spec:
# note that one should not use [blas_opt] and [lapack_opt], see

View file

@ -101,8 +101,8 @@ def install(self, spec, prefix):
# Make sure Spack's Blas/Lapack is used. Otherwise System's
# Blas/Lapack might be picked up.
blas = spec['blas'].blas_libs.ld_flags
lapack = spec['lapack'].lapack_libs.ld_flags
blas = spec['blas'].libs.ld_flags
lapack = spec['lapack'].libs.ld_flags
if '@4.5.1' in spec:
# adding -lstdc++ is clearly an ugly way to do this, but it follows
# with the TCOV path of SparseSuite 4.5.1's Suitesparse_config.mk

View file

@ -80,8 +80,8 @@ def install(self, spec, prefix):
cmake_args.extend([
'-DLAPACK_ENABLE=ON',
'-DLAPACK_LIBRARIES={0}'.format(
(spec['lapack'].lapack_libs +
spec['blas'].blas_libs).joined(';')
(spec['lapack'].libs +
spec['blas'].libs).joined(';')
)
])
else:

View file

@ -53,7 +53,7 @@ class SuperluDist(Package):
depends_on('metis@5:')
def install(self, spec, prefix):
lapack_blas = spec['lapack'].lapack_libs + spec['blas'].blas_libs
lapack_blas = spec['lapack'].libs + spec['blas'].libs
makefile_inc = []
makefile_inc.extend([
'PLAT = _mac_x',
@ -61,17 +61,17 @@ def install(self, spec, prefix):
'DSUPERLULIB = $(DSuperLUroot)/lib/libsuperlu_dist.a',
'BLASDEF = -DUSE_VENDOR_BLAS',
'BLASLIB = %s' % lapack_blas.ld_flags,
'METISLIB = -L%s -lmetis' % spec['metis'].prefix.lib,
'PARMETISLIB = -L%s -lparmetis' % spec['parmetis'].prefix.lib,
'METISLIB = %s' % spec['metis'].libs.ld_flags,
'PARMETISLIB = %s' % spec['parmetis'].libs.ld_flags,
'FLIBS =',
'LIBS = $(DSUPERLULIB) $(BLASLIB) $(PARMETISLIB) $(METISLIB)', # noqa
'ARCH = ar',
'ARCHFLAGS = cr',
'RANLIB = true',
'CC = {0}'.format(self.spec['mpi'].mpicc),
'CFLAGS = -fPIC -std=c99 -O2 -I%s -I%s %s' % (
spec['parmetis'].prefix.include,
spec['metis'].prefix.include,
'CFLAGS = -fPIC -std=c99 -O2 %s %s %s' % (
spec['parmetis'].cppflags,
spec['metis'].cppflags,
'-D_LONGINT' if '+int64' in spec else ''),
'NOOPTS = -fPIC -std=c99',
'FORTRAN = {0}'.format(self.spec['mpi'].mpif77),

View file

@ -86,7 +86,7 @@ def configure(self, spec):
if '+blas' in spec:
config.extend([
'BLASDEF = -DUSE_VENDOR_BLAS',
'BLASLIB = {0}'.format(spec['blas'].blas_libs.ld_flags)
'BLASLIB = {0}'.format(spec['blas'].libs.ld_flags)
])
else:
config.append('BLASLIB = ../lib/libblas$(PLAT).a')

View file

@ -48,7 +48,7 @@ class Superlu(Package):
def install(self, spec, prefix):
cmake_args = [
'-Denable_blaslib=OFF',
'-DBLAS_blas_LIBRARY={0}'.format(spec['blas'].blas_libs.joined())
'-DBLAS_blas_LIBRARY={0}'.format(spec['blas'].libs.joined())
]
if '+fpic' in spec:
@ -76,7 +76,7 @@ def install(self, spec, prefix):
'SUPERLULIB = $(SuperLUroot)/lib/libsuperlu_{0}.a' \
.format(self.spec.version),
'BLASDEF = -DUSE_VENDOR_BLAS',
'BLASLIB = {0}'.format(spec['blas'].blas_libs.ld_flags),
'BLASLIB = {0}'.format(spec['blas'].libs.ld_flags),
# or BLASLIB = -L/usr/lib64 -lblas
'TMGLIB = libtmglib.a',
'LIBS = $(SUPERLULIB) $(BLASLIB)',

View file

@ -147,8 +147,8 @@ def cmake_args(self):
mpi_bin = spec['mpi'].prefix.bin
# Note: -DXYZ_LIBRARY_NAMES= needs semicolon separated list of names
blas = spec['blas'].blas_libs
lapack = spec['lapack'].lapack_libs
blas = spec['blas'].libs
lapack = spec['lapack'].libs
options.extend([
'-DTrilinos_ENABLE_ALL_PACKAGES:BOOL=ON',
'-DTrilinos_ENABLE_ALL_OPTIONAL_PACKAGES:BOOL=ON',

View file

@ -44,17 +44,12 @@ class Veclibfort(Package):
provides('blas')
provides('lapack')
@property
def blas_libs(self):
def libs(self):
shared = True if '+shared' in self.spec else False
return find_libraries(
['libvecLibFort'], root=self.prefix, shared=shared, recurse=True
)
@property
def lapack_libs(self):
return self.blas_libs
def install(self, spec, prefix):
if sys.platform != 'darwin':
raise InstallError('vecLibFort can be installed on macOS only')
@ -65,6 +60,6 @@ def install(self, spec, prefix):
# test
fc = which('fc')
flags = ['-o', 'tester', '-O', 'tester.f90']
flags.extend(self.lapack_libs.ld_flags.split())
flags.extend(spec.libs.ld_flags.split())
fc(*flags)
Executable('./tester')()

View file

@ -47,8 +47,8 @@ class Wannier90(Package):
def install(self, spec, prefix):
lapack = self.spec['lapack'].lapack_libs
blas = self.spec['blas'].blas_libs
lapack = self.spec['lapack'].libs
blas = self.spec['blas'].libs
substitutions = {
'@F90': spack_fc,
'@MPIF90': self.spec['mpi'].mpifc,