Compare commits
17 Commits
packages/a
...
releases/v
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c21c03f01a | ||
![]() |
e905f8cf83 | ||
![]() |
41e6eb130c | ||
![]() |
880e319cf6 | ||
![]() |
1cc9241030 | ||
![]() |
9835f5077b | ||
![]() |
4fb3b30d3e | ||
![]() |
e0826804c2 | ||
![]() |
c2a10a2aa2 | ||
![]() |
ba6c39310b | ||
![]() |
974d166c8a | ||
![]() |
7a0a907b5c | ||
![]() |
57608a6dc4 | ||
![]() |
52a9e5d2a3 | ||
![]() |
4f8167b7ed | ||
![]() |
164da8eed1 | ||
![]() |
6e1257ed2d |
31
.travis.yml
31
.travis.yml
@@ -14,12 +14,17 @@ branches:
|
||||
jobs:
|
||||
fast_finish: true
|
||||
include:
|
||||
- stage: 'flake8'
|
||||
- stage: 'flake8 + documentation'
|
||||
python: '2.7'
|
||||
os: linux
|
||||
language: python
|
||||
env: TEST_SUITE=flake8
|
||||
- stage: 'unit tests + documentation'
|
||||
- stage: 'flake8 + documentation'
|
||||
python: '2.7'
|
||||
os: linux
|
||||
language: python
|
||||
env: TEST_SUITE=doc
|
||||
- stage: 'unit tests'
|
||||
python: '2.6'
|
||||
os: linux
|
||||
language: python
|
||||
@@ -44,13 +49,10 @@ jobs:
|
||||
os: linux
|
||||
language: python
|
||||
env: [ TEST_SUITE=unit, COVERAGE=true ]
|
||||
- os: osx
|
||||
- stage: 'unit tests - osx'
|
||||
os: osx
|
||||
language: generic
|
||||
env: [ TEST_SUITE=unit, PYTHON_VERSION=2.7, COVERAGE=true ]
|
||||
- python: '2.7'
|
||||
os: linux
|
||||
language: python
|
||||
env: TEST_SUITE=doc
|
||||
# mpich (AutotoolsPackage)
|
||||
- stage: 'build tests'
|
||||
python: '2.7'
|
||||
@@ -93,6 +95,14 @@ jobs:
|
||||
language: python
|
||||
env: [ TEST_SUITE=build, COVERAGE=true, 'SPEC=mpich' ]
|
||||
|
||||
stages:
|
||||
- 'flake8 + documentation'
|
||||
- 'unit tests'
|
||||
- 'build tests'
|
||||
- name: 'unit tests - osx'
|
||||
if: type IN (cron)
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Environment
|
||||
#=============================================================================
|
||||
@@ -148,10 +158,9 @@ before_script:
|
||||
#=============================================================================
|
||||
# Building
|
||||
#=============================================================================
|
||||
script: share/spack/qa/run-$TEST_SUITE-tests
|
||||
|
||||
after_success:
|
||||
- codecov --env PY_VERSION
|
||||
script:
|
||||
- share/spack/qa/run-$TEST_SUITE-tests
|
||||
- if [[ "$COVERAGE" == "true" ]]; then codecov --env PYTHON_VERSION --required --flags "${TEST_SUITE}${TRAVIS_OS_NAME}"; fi
|
||||
|
||||
#=============================================================================
|
||||
# Notifications
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# <img src="https://cdn.rawgit.com/spack/spack/features/svg-logo/share/spack/logo/spack-logo.svg" width="64" valign="middle" alt="Spack"/> Spack
|
||||
# <img src="https://cdn.rawgit.com/spack/spack/develop/share/spack/logo/spack-logo.svg" width="64" valign="middle" alt="Spack"/> Spack
|
||||
|
||||
[](https://travis-ci.org/spack/spack)
|
||||
[](https://codecov.io/gh/spack/spack)
|
||||
|
@@ -2564,98 +2564,104 @@ build system.
|
||||
Compiler flags
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Compiler flags set by the user through the Spec object can be passed to
|
||||
the build in one of two ways. For packages inheriting from the
|
||||
``CmakePackage`` or ``AutotoolsPackage`` classes, the build environment
|
||||
passes those flags to the relevant environment variables (``CFLAGS``,
|
||||
``CXXFLAGS``, etc) that are respected by the build system. For all other
|
||||
packages, the default behavior is to inject the flags directly into the
|
||||
compiler commands using Spack's compiler wrappers.
|
||||
Compiler flags set by the user through the Spec object can be passed
|
||||
to the build in one of three ways. By default, the build environment
|
||||
injects these flags directly into the compiler commands using Spack's
|
||||
compiler wrappers. In cases where the build system requires knowledge
|
||||
of the compiler flags, they can be registered with the build system by
|
||||
alternatively passing them through environment variables or as build
|
||||
system arguments. The flag_handler method can be used to change this
|
||||
behavior.
|
||||
|
||||
Packages can override the flag_handler method with one of three
|
||||
built-in flag_handlers. The built-in flag_handlers are named
|
||||
``inject_flags``, ``env_flags``, and ``build_system_flags``. The
|
||||
``inject_flags`` method is the default. The ``env_flags`` method puts
|
||||
all of the flags into the environment variables that ``make`` uses as
|
||||
implicit variables ('CFLAGS', 'CXXFLAGS', etc.). The
|
||||
``build_system_flags`` method adds the flags as
|
||||
arguments to the invocation of ``configure`` or ``cmake``,
|
||||
respectively.
|
||||
|
||||
.. warning::
|
||||
|
||||
The flag handling methods described in this section are in beta.
|
||||
The exact semantics are liable to change to improve usability.
|
||||
Passing compiler flags using build system arguments is only
|
||||
supported for CMake and Autotools packages. Individual packages may
|
||||
also differ in whether they properly respect these arguments.
|
||||
|
||||
Individual packages can override the default behavior for the flag
|
||||
handling. Packages can define a ``default_flag_handler`` method that
|
||||
applies to all sets of flags handled by Spack, or may define
|
||||
individual methods ``cflags_handler``, ``cxxflags_handler``,
|
||||
etc. Spack will apply the individual method for a flag set if it
|
||||
exists, otherwise the ``default_flag_handler`` method if it exists,
|
||||
and fall back on the default for that package class if neither exists.
|
||||
Individual packages may also define their own ``flag_handler``
|
||||
methods. The ``flag_handler`` method takes the package instance
|
||||
(``self``), the name of the flag, and a list of the values of the
|
||||
flag. It will be called on each of the six compiler flags supported in
|
||||
Spack. It should return a triple of ``(injf, envf, bsf)`` where
|
||||
``injf`` is a list of flags to inject via the Spack compiler wrappers,
|
||||
``envf`` is a list of flags to set in the appropriate environment
|
||||
variables, and ``bsf`` is a list of flags to pass to the build system
|
||||
as arguments.
|
||||
|
||||
These methods are defined on the package class, and take two
|
||||
parameters in addition to the packages itself. The ``env`` parameter
|
||||
is an ``EnvironmentModifications`` object that can be used to change
|
||||
the build environment. The ``flag_val`` parameter is a tuple. Its
|
||||
first entry is the name of the flag (``cflags``, ``cxxflags``, etc.)
|
||||
and its second entry is a list of the values for that flag.
|
||||
.. warning::
|
||||
|
||||
There are three primary idioms that can be combined to create whatever
|
||||
behavior the package requires.
|
||||
Passing a non-empty list of flags to ``bsf`` for a build system
|
||||
that does not support build system arguments will result in an
|
||||
error.
|
||||
|
||||
1. The default behavior for packages inheriting from
|
||||
``AutotoolsPackage`` or ``CmakePackage``.
|
||||
Here are the definitions of the three built-in flag handlers:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def default_flag_handler(self, env, flag_val):
|
||||
env.append_flags(flag_val[0].upper(), ' '.join(flag_val[1]))
|
||||
return []
|
||||
def inject_flags(self, name, flags):
|
||||
return (flags, None, None)
|
||||
|
||||
2. The default behavior for other packages
|
||||
def env_flags(self, name, flags):
|
||||
return (None, flags, None)
|
||||
|
||||
def build_system_flags(self, name, flags):
|
||||
return (None, None, flags)
|
||||
|
||||
.. note::
|
||||
|
||||
Returning ``[]`` and ``None`` are equivalent in a ``flag_handler``
|
||||
method.
|
||||
|
||||
Packages can override the default behavior either by specifying one of
|
||||
the built-in flag handlers,
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def default_flag_handler(self, env, flag_val):
|
||||
return flag_val[1]
|
||||
flag_handler = <PackageClass>.env_flags
|
||||
|
||||
where ``<PackageClass>`` can be any of the subclasses of PackageBase
|
||||
discussed in :ref:`installation_procedure`,
|
||||
|
||||
3. Packages may have additional flags to add to the build. These flags
|
||||
can be added to either idiom above. For example:
|
||||
or by implementing the flag_handler method. Suppose for a package
|
||||
``Foo`` we need to pass ``cflags``, ``cxxflags``, and ``cppflags``
|
||||
through the environment, the rest of the flags through compiler
|
||||
wrapper injection, and we need to add ``-lbar`` to ``ldlibs``. The
|
||||
following flag handler method accomplishes that.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def default_flag_handler(self, env, flag_val):
|
||||
flags = flag_val[1]
|
||||
flags.append('-flag')
|
||||
return flags
|
||||
|
||||
or
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def default_flag_handler(self, env, flag_val):
|
||||
env.append_flags(flag_val[0].upper(), ' '.join(flag_val[1]))
|
||||
env.append_flags(flag_val[0].upper(), '-flag')
|
||||
return []
|
||||
|
||||
Packages may also opt for methods that include aspects of any of the
|
||||
idioms above. E.g.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def default_flag_handler(self, env, flag_val):
|
||||
flags = []
|
||||
if len(flag_val[1]) > 3:
|
||||
env.append_flags(flag_val[0].upper(), ' '.join(flag_val[1][3:]))
|
||||
flags = flag_val[1][:3]
|
||||
else:
|
||||
flags = flag_val[1]
|
||||
flags.append('-flag')
|
||||
return flags
|
||||
def flag_handler(self, name, flags):
|
||||
if name in ['cflags', 'cxxflags', 'cppflags']:
|
||||
return (None, flags, None)
|
||||
elif name == 'ldlibs':
|
||||
flags.append('-lbar')
|
||||
return (flags, None, None)
|
||||
|
||||
Because these methods can pass values through environment variables,
|
||||
it is important not to override these variables unnecessarily in other
|
||||
package methods. In the ``setup_environment`` and
|
||||
it is important not to override these variables unnecessarily
|
||||
(E.g. setting ``env['CFLAGS']``) in other package methods when using
|
||||
non-default flag handlers. In the ``setup_environment`` and
|
||||
``setup_dependent_environment`` methods, use the ``append_flags``
|
||||
method of the ``EnvironmentModifications`` class to append values to a
|
||||
list of flags whenever there is no good reason to override the
|
||||
existing value. In the ``install`` method and other methods that can
|
||||
operate on the build environment directly through the ``env``
|
||||
variable, test for environment variable existance before overriding
|
||||
values to add compiler flags.
|
||||
list of flags whenever the flag handler is ``env_flags``. If the
|
||||
package passes flags through the environment or the build system
|
||||
manually (in the install method, for example), we recommend using the
|
||||
default flag handler, or removind manual references and implementing a
|
||||
custom flag handler method that adds the desired flags to export as
|
||||
environment variables or pass to the build system. Manual flag passing
|
||||
is likely to interfere with the ``env_flags`` and
|
||||
``build_system_flags`` methods.
|
||||
|
||||
In rare circumstances such as compiling and running small unit tests, a
|
||||
package developer may need to know what are the appropriate compiler
|
||||
|
@@ -42,7 +42,6 @@ correspond to sections in the slides above.
|
||||
4. :ref:`build-systems-tutorial`
|
||||
5. :ref:`advanced-packaging-tutorial`
|
||||
6. :ref:`modules-tutorial`
|
||||
7. :ref:`modules-tutorial`
|
||||
|
||||
Full contents:
|
||||
|
||||
|
@@ -1,460 +0,0 @@
|
||||
##############################################################################
|
||||
# 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/llnl/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
|
||||
##############################################################################
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import os.path
|
||||
import shutil
|
||||
import stat
|
||||
from subprocess import PIPE
|
||||
from subprocess import check_call
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import working_dir, join_path, force_remove
|
||||
from spack.package import PackageBase, run_after, run_before
|
||||
from spack.util.executable import Executable
|
||||
|
||||
|
||||
class AutotoolsPackage(PackageBase):
|
||||
"""Specialized class for packages built using GNU Autotools.
|
||||
|
||||
This class provides four phases that can be overridden:
|
||||
|
||||
1. :py:meth:`~.AutotoolsPackage.autoreconf`
|
||||
2. :py:meth:`~.AutotoolsPackage.configure`
|
||||
3. :py:meth:`~.AutotoolsPackage.build`
|
||||
4. :py:meth:`~.AutotoolsPackage.install`
|
||||
|
||||
They all have sensible defaults and for many packages the only thing
|
||||
necessary will be to override the helper method
|
||||
:py:meth:`~.AutotoolsPackage.configure_args`.
|
||||
For a finer tuning you may also override:
|
||||
|
||||
+-----------------------------------------------+--------------------+
|
||||
| **Method** | **Purpose** |
|
||||
+===============================================+====================+
|
||||
| :py:attr:`~.AutotoolsPackage.build_targets` | Specify ``make`` |
|
||||
| | targets for the |
|
||||
| | build phase |
|
||||
+-----------------------------------------------+--------------------+
|
||||
| :py:attr:`~.AutotoolsPackage.install_targets` | Specify ``make`` |
|
||||
| | targets for the |
|
||||
| | install phase |
|
||||
+-----------------------------------------------+--------------------+
|
||||
| :py:meth:`~.AutotoolsPackage.check` | Run build time |
|
||||
| | tests if required |
|
||||
+-----------------------------------------------+--------------------+
|
||||
|
||||
"""
|
||||
#: Phases of a GNU Autotools package
|
||||
phases = ['autoreconf', 'configure', 'build', 'install']
|
||||
#: This attribute is used in UI queries that need to know the build
|
||||
#: system base class
|
||||
build_system_class = 'AutotoolsPackage'
|
||||
#: Whether or not to update ``config.guess`` on old architectures
|
||||
patch_config_guess = True
|
||||
|
||||
#: Targets for ``make`` during the :py:meth:`~.AutotoolsPackage.build`
|
||||
#: phase
|
||||
build_targets = []
|
||||
#: Targets for ``make`` during the :py:meth:`~.AutotoolsPackage.install`
|
||||
#: phase
|
||||
install_targets = ['install']
|
||||
|
||||
#: Callback names for build-time test
|
||||
build_time_test_callbacks = ['check']
|
||||
|
||||
#: Callback names for install-time test
|
||||
install_time_test_callbacks = ['installcheck']
|
||||
|
||||
#: Set to true to force the autoreconf step even if configure is present
|
||||
force_autoreconf = False
|
||||
#: Options to be passed to autoreconf when using the default implementation
|
||||
autoreconf_extra_args = []
|
||||
|
||||
@run_after('autoreconf')
|
||||
def _do_patch_config_guess(self):
|
||||
"""Some packages ship with an older config.guess and need to have
|
||||
this updated when installed on a newer architecture. In particular,
|
||||
config.guess fails for PPC64LE for version prior to a 2013-06-10
|
||||
build date (automake 1.13.4)."""
|
||||
|
||||
if not self.patch_config_guess or not self.spec.satisfies(
|
||||
'target=ppc64le'
|
||||
):
|
||||
return
|
||||
my_config_guess = None
|
||||
config_guess = None
|
||||
if os.path.exists('config.guess'):
|
||||
# First search the top-level source directory
|
||||
my_config_guess = 'config.guess'
|
||||
else:
|
||||
# Then search in all sub directories.
|
||||
# We would like to use AC_CONFIG_AUX_DIR, but not all packages
|
||||
# ship with their configure.in or configure.ac.
|
||||
d = '.'
|
||||
dirs = [os.path.join(d, o) for o in os.listdir(d)
|
||||
if os.path.isdir(os.path.join(d, o))]
|
||||
for dirname in dirs:
|
||||
path = os.path.join(dirname, 'config.guess')
|
||||
if os.path.exists(path):
|
||||
my_config_guess = path
|
||||
|
||||
if my_config_guess is not None:
|
||||
try:
|
||||
check_call([my_config_guess], stdout=PIPE, stderr=PIPE)
|
||||
# The package's config.guess already runs OK, so just use it
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
|
||||
# Look for a spack-installed automake package
|
||||
if 'automake' in self.spec:
|
||||
automake_path = os.path.join(self.spec['automake'].prefix, 'share',
|
||||
'automake-' +
|
||||
str(self.spec['automake'].version))
|
||||
path = os.path.join(automake_path, 'config.guess')
|
||||
if os.path.exists(path):
|
||||
config_guess = path
|
||||
# Look for the system's config.guess
|
||||
if config_guess is None and os.path.exists('/usr/share'):
|
||||
automake_dir = [s for s in os.listdir('/usr/share') if
|
||||
"automake" in s]
|
||||
if automake_dir:
|
||||
automake_path = os.path.join('/usr/share', automake_dir[0])
|
||||
path = os.path.join(automake_path, 'config.guess')
|
||||
if os.path.exists(path):
|
||||
config_guess = path
|
||||
if config_guess is not None:
|
||||
try:
|
||||
check_call([config_guess], stdout=PIPE, stderr=PIPE)
|
||||
mod = os.stat(my_config_guess).st_mode & 0o777 | stat.S_IWUSR
|
||||
os.chmod(my_config_guess, mod)
|
||||
shutil.copyfile(config_guess, my_config_guess)
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
raise RuntimeError('Failed to find suitable config.guess')
|
||||
|
||||
@property
|
||||
def configure_directory(self):
|
||||
"""Returns the directory where 'configure' resides.
|
||||
|
||||
:return: directory where to find configure
|
||||
"""
|
||||
return self.stage.source_path
|
||||
|
||||
@property
|
||||
def configure_abs_path(self):
|
||||
# Absolute path to configure
|
||||
configure_abs_path = join_path(
|
||||
os.path.abspath(self.configure_directory), 'configure'
|
||||
)
|
||||
return configure_abs_path
|
||||
|
||||
@property
|
||||
def build_directory(self):
|
||||
"""Override to provide another place to build the package"""
|
||||
return self.configure_directory
|
||||
|
||||
def default_flag_handler(self, spack_env, flag_val):
|
||||
# Relies on being the first thing that can affect the spack_env
|
||||
# EnvironmentModification after it is instantiated or no other
|
||||
# method trying to affect these variables. Currently both are true
|
||||
# flag_val is a tuple (flag, value_list).
|
||||
spack_env.set(flag_val[0].upper(),
|
||||
' '.join(flag_val[1]))
|
||||
return []
|
||||
|
||||
@run_before('autoreconf')
|
||||
def delete_configure_to_force_update(self):
|
||||
if self.force_autoreconf:
|
||||
force_remove(self.configure_abs_path)
|
||||
|
||||
def autoreconf(self, spec, prefix):
|
||||
"""Not needed usually, configure should be already there"""
|
||||
# If configure exists nothing needs to be done
|
||||
if os.path.exists(self.configure_abs_path):
|
||||
return
|
||||
# Else try to regenerate it
|
||||
autotools = ['m4', 'autoconf', 'automake', 'libtool']
|
||||
missing = [x for x in autotools if x not in spec]
|
||||
if missing:
|
||||
msg = 'Cannot generate configure: missing dependencies {0}'
|
||||
raise RuntimeError(msg.format(missing))
|
||||
tty.msg('Configure script not found: trying to generate it')
|
||||
tty.warn('*********************************************************')
|
||||
tty.warn('* If the default procedure fails, consider implementing *')
|
||||
tty.warn('* a custom AUTORECONF phase in the package *')
|
||||
tty.warn('*********************************************************')
|
||||
with working_dir(self.configure_directory):
|
||||
m = inspect.getmodule(self)
|
||||
# This part should be redundant in principle, but
|
||||
# won't hurt
|
||||
m.libtoolize()
|
||||
m.aclocal()
|
||||
# This line is what is needed most of the time
|
||||
# --install, --verbose, --force
|
||||
autoreconf_args = ['-ivf']
|
||||
if 'pkg-config' in spec:
|
||||
autoreconf_args += [
|
||||
'-I',
|
||||
join_path(spec['pkg-config'].prefix, 'share', 'aclocal'),
|
||||
]
|
||||
autoreconf_args += self.autoreconf_extra_args
|
||||
m.autoreconf(*autoreconf_args)
|
||||
|
||||
@run_after('autoreconf')
|
||||
def set_configure_or_die(self):
|
||||
"""Checks the presence of a ``configure`` file after the
|
||||
autoreconf phase. If it is found sets a module attribute
|
||||
appropriately, otherwise raises an error.
|
||||
|
||||
:raises RuntimeError: if a configure script is not found in
|
||||
:py:meth:`~AutotoolsPackage.configure_directory`
|
||||
"""
|
||||
# Check if a configure script is there. If not raise a RuntimeError.
|
||||
if not os.path.exists(self.configure_abs_path):
|
||||
msg = 'configure script not found in {0}'
|
||||
raise RuntimeError(msg.format(self.configure_directory))
|
||||
|
||||
# Monkey-patch the configure script in the corresponding module
|
||||
inspect.getmodule(self).configure = Executable(
|
||||
self.configure_abs_path
|
||||
)
|
||||
|
||||
def configure_args(self):
|
||||
"""Produces a list containing all the arguments that must be passed to
|
||||
configure, except ``--prefix`` which will be pre-pended to the list.
|
||||
|
||||
:return: list of arguments for configure
|
||||
"""
|
||||
return []
|
||||
|
||||
def configure(self, spec, prefix):
|
||||
"""Runs configure with the arguments specified in
|
||||
:py:meth:`~.AutotoolsPackage.configure_args`
|
||||
and an appropriately set prefix.
|
||||
"""
|
||||
options = ['--prefix={0}'.format(prefix)] + self.configure_args()
|
||||
|
||||
with working_dir(self.build_directory, create=True):
|
||||
inspect.getmodule(self).configure(*options)
|
||||
|
||||
def build(self, spec, prefix):
|
||||
"""Makes the build targets specified by
|
||||
:py:attr:``~.AutotoolsPackage.build_targets``
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
inspect.getmodule(self).make(*self.build_targets)
|
||||
|
||||
def install(self, spec, prefix):
|
||||
"""Makes the install targets specified by
|
||||
:py:attr:``~.AutotoolsPackage.install_targets``
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
inspect.getmodule(self).make(*self.install_targets)
|
||||
|
||||
run_after('build')(PackageBase._run_default_build_time_test_callbacks)
|
||||
|
||||
def check(self):
|
||||
"""Searches the Makefile for targets ``test`` and ``check``
|
||||
and runs them if found.
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
self._if_make_target_execute('test')
|
||||
self._if_make_target_execute('check')
|
||||
|
||||
def _activate_or_not(
|
||||
self,
|
||||
name,
|
||||
activation_word,
|
||||
deactivation_word,
|
||||
activation_value=None
|
||||
):
|
||||
"""This function contains the current implementation details of
|
||||
:py:meth:`~.AutotoolsPackage.with_or_without` and
|
||||
:py:meth:`~.AutotoolsPackage.enable_or_disable`.
|
||||
|
||||
Args:
|
||||
name (str): name of the variant that is being processed
|
||||
activation_word (str): the default activation word ('with' in the
|
||||
case of ``with_or_without``)
|
||||
deactivation_word (str): the default deactivation word ('without'
|
||||
in the case of ``with_or_without``)
|
||||
activation_value (callable): callable that accepts a single
|
||||
value. This value is either one of the allowed values for a
|
||||
multi-valued variant or the name of a bool-valued variant.
|
||||
Returns the parameter to be used when the value is activated.
|
||||
|
||||
The special value 'prefix' can also be assigned and will return
|
||||
``spec[name].prefix`` as activation parameter.
|
||||
|
||||
Examples:
|
||||
|
||||
Given a package with:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
variant('foo', values=('x', 'y'), description='')
|
||||
variant('bar', default=True, description='')
|
||||
|
||||
calling this function like:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
_activate_or_not(
|
||||
'foo', 'with', 'without', activation_value='prefix'
|
||||
)
|
||||
_activate_or_not('bar', 'with', 'without')
|
||||
|
||||
will generate the following configuration options:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
--with-x=<prefix-to-x> --without-y --with-bar
|
||||
|
||||
for ``<spec-name> foo=x +bar``
|
||||
|
||||
Returns:
|
||||
list of strings that corresponds to the activation/deactivation
|
||||
of the variant that has been processed
|
||||
|
||||
Raises:
|
||||
KeyError: if name is not among known variants
|
||||
"""
|
||||
spec = self.spec
|
||||
args = []
|
||||
|
||||
if activation_value == 'prefix':
|
||||
activation_value = lambda x: spec[x].prefix
|
||||
|
||||
# Defensively look that the name passed as argument is among
|
||||
# variants
|
||||
if name not in self.variants:
|
||||
msg = '"{0}" is not a variant of "{1}"'
|
||||
raise KeyError(msg.format(name, self.name))
|
||||
|
||||
# Create a list of pairs. Each pair includes a configuration
|
||||
# option and whether or not that option is activated
|
||||
if set(self.variants[name].values) == set((True, False)):
|
||||
# BoolValuedVariant carry information about a single option.
|
||||
# Nonetheless, for uniformity of treatment we'll package them
|
||||
# in an iterable of one element.
|
||||
condition = '+{name}'.format(name=name)
|
||||
options = [(name, condition in spec)]
|
||||
else:
|
||||
condition = '{name}={value}'
|
||||
options = [
|
||||
(value, condition.format(name=name, value=value) in spec)
|
||||
for value in self.variants[name].values
|
||||
]
|
||||
|
||||
# For each allowed value in the list of values
|
||||
for option_value, activated in options:
|
||||
# Search for an override in the package for this value
|
||||
override_name = '{0}_or_{1}_{2}'.format(
|
||||
activation_word, deactivation_word, option_value
|
||||
)
|
||||
line_generator = getattr(self, override_name, None)
|
||||
# If not available use a sensible default
|
||||
if line_generator is None:
|
||||
def _default_generator(is_activated):
|
||||
if is_activated:
|
||||
line = '--{0}-{1}'.format(
|
||||
activation_word, option_value
|
||||
)
|
||||
if activation_value is not None and activation_value(option_value): # NOQA=ignore=E501
|
||||
line += '={0}'.format(
|
||||
activation_value(option_value)
|
||||
)
|
||||
return line
|
||||
return '--{0}-{1}'.format(deactivation_word, option_value)
|
||||
line_generator = _default_generator
|
||||
args.append(line_generator(activated))
|
||||
return args
|
||||
|
||||
def with_or_without(self, name, activation_value=None):
|
||||
"""Inspects a variant and returns the arguments that activate
|
||||
or deactivate the selected feature(s) for the configure options.
|
||||
|
||||
This function works on all type of variants. For bool-valued variants
|
||||
it will return by default ``--with-{name}`` or ``--without-{name}``.
|
||||
For other kinds of variants it will cycle over the allowed values and
|
||||
return either ``--with-{value}`` or ``--without-{value}``.
|
||||
|
||||
If activation_value is given, then for each possible value of the
|
||||
variant, the option ``--with-{value}=activation_value(value)`` or
|
||||
``--without-{value}`` will be added depending on whether or not
|
||||
``variant=value`` is in the spec.
|
||||
|
||||
Args:
|
||||
name (str): name of a valid multi-valued variant
|
||||
activation_value (callable): callable that accepts a single
|
||||
value and returns the parameter to be used leading to an entry
|
||||
of the type ``--with-{name}={parameter}``.
|
||||
|
||||
The special value 'prefix' can also be assigned and will return
|
||||
``spec[name].prefix`` as activation parameter.
|
||||
|
||||
Returns:
|
||||
list of arguments to configure
|
||||
"""
|
||||
return self._activate_or_not(name, 'with', 'without', activation_value)
|
||||
|
||||
def enable_or_disable(self, name, activation_value=None):
|
||||
"""Same as :py:meth:`~.AutotoolsPackage.with_or_without` but substitute
|
||||
``with`` with ``enable`` and ``without`` with ``disable``.
|
||||
|
||||
Args:
|
||||
name (str): name of a valid multi-valued variant
|
||||
activation_value (callable): if present accepts a single value
|
||||
and returns the parameter to be used leading to an entry of the
|
||||
type ``--enable-{name}={parameter}``
|
||||
|
||||
The special value 'prefix' can also be assigned and will return
|
||||
``spec[name].prefix`` as activation parameter.
|
||||
|
||||
Returns:
|
||||
list of arguments to configure
|
||||
"""
|
||||
return self._activate_or_not(
|
||||
name, 'enable', 'disable', activation_value
|
||||
)
|
||||
|
||||
run_after('install')(PackageBase._run_default_install_time_test_callbacks)
|
||||
|
||||
def installcheck(self):
|
||||
"""Searches the Makefile for an ``installcheck`` target
|
||||
and runs it if found.
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
self._if_make_target_execute('installcheck')
|
||||
|
||||
# Check that self.prefix is there after installation
|
||||
run_after('install')(PackageBase.sanity_check_prefix)
|
@@ -1,224 +0,0 @@
|
||||
##############################################################################
|
||||
# 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/llnl/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
|
||||
##############################################################################
|
||||
|
||||
import inspect
|
||||
import os
|
||||
import platform
|
||||
|
||||
import spack.build_environment
|
||||
from llnl.util.filesystem import working_dir, join_path
|
||||
from spack.util.environment import filter_system_paths
|
||||
from spack.directives import depends_on, variant
|
||||
from spack.package import PackageBase, InstallError, run_after
|
||||
|
||||
|
||||
class CMakePackage(PackageBase):
|
||||
"""Specialized class for packages built using CMake
|
||||
|
||||
For more information on the CMake build system, see:
|
||||
https://cmake.org/cmake/help/latest/
|
||||
|
||||
This class provides three phases that can be overridden:
|
||||
|
||||
1. :py:meth:`~.CMakePackage.cmake`
|
||||
2. :py:meth:`~.CMakePackage.build`
|
||||
3. :py:meth:`~.CMakePackage.install`
|
||||
|
||||
They all have sensible defaults and for many packages the only thing
|
||||
necessary will be to override :py:meth:`~.CMakePackage.cmake_args`.
|
||||
For a finer tuning you may also override:
|
||||
|
||||
+-----------------------------------------------+--------------------+
|
||||
| **Method** | **Purpose** |
|
||||
+===============================================+====================+
|
||||
| :py:meth:`~.CMakePackage.root_cmakelists_dir` | Location of the |
|
||||
| | root CMakeLists.txt|
|
||||
+-----------------------------------------------+--------------------+
|
||||
| :py:meth:`~.CMakePackage.build_directory` | Directory where to |
|
||||
| | build the package |
|
||||
+-----------------------------------------------+--------------------+
|
||||
|
||||
|
||||
"""
|
||||
#: Phases of a CMake package
|
||||
phases = ['cmake', 'build', 'install']
|
||||
#: This attribute is used in UI queries that need to know the build
|
||||
#: system base class
|
||||
build_system_class = 'CMakePackage'
|
||||
|
||||
build_targets = []
|
||||
install_targets = ['install']
|
||||
|
||||
build_time_test_callbacks = ['check']
|
||||
|
||||
#: The build system generator to use.
|
||||
#:
|
||||
#: See ``cmake --help`` for a list of valid generators.
|
||||
#: Currently, "Unix Makefiles" and "Ninja" are the only generators
|
||||
#: that Spack supports. Defaults to "Unix Makefiles".
|
||||
#:
|
||||
#: See https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html
|
||||
#: for more information.
|
||||
generator = 'Unix Makefiles'
|
||||
|
||||
# https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html
|
||||
variant('build_type', default='RelWithDebInfo',
|
||||
description='CMake build type',
|
||||
values=('Debug', 'Release', 'RelWithDebInfo', 'MinSizeRel'))
|
||||
|
||||
depends_on('cmake', type='build')
|
||||
|
||||
@property
|
||||
def root_cmakelists_dir(self):
|
||||
"""The relative path to the directory containing CMakeLists.txt
|
||||
|
||||
This path is relative to the root of the extracted tarball,
|
||||
not to the ``build_directory``. Defaults to the current directory.
|
||||
|
||||
:return: directory containing CMakeLists.txt
|
||||
"""
|
||||
return self.stage.source_path
|
||||
|
||||
@property
|
||||
def std_cmake_args(self):
|
||||
"""Standard cmake arguments provided as a property for
|
||||
convenience of package writers
|
||||
|
||||
:return: standard cmake arguments
|
||||
"""
|
||||
# standard CMake arguments
|
||||
return CMakePackage._std_args(self)
|
||||
|
||||
@staticmethod
|
||||
def _std_args(pkg):
|
||||
"""Computes the standard cmake arguments for a generic package"""
|
||||
try:
|
||||
generator = pkg.generator
|
||||
except AttributeError:
|
||||
generator = 'Unix Makefiles'
|
||||
|
||||
# Make sure a valid generator was chosen
|
||||
valid_generators = ['Unix Makefiles', 'Ninja']
|
||||
if generator not in valid_generators:
|
||||
msg = "Invalid CMake generator: '{0}'\n".format(generator)
|
||||
msg += "CMakePackage currently supports the following "
|
||||
msg += "generators: '{0}'".format("', '".join(valid_generators))
|
||||
raise InstallError(msg)
|
||||
|
||||
try:
|
||||
build_type = pkg.spec.variants['build_type'].value
|
||||
except KeyError:
|
||||
build_type = 'RelWithDebInfo'
|
||||
|
||||
args = [
|
||||
'-G', generator,
|
||||
'-DCMAKE_INSTALL_PREFIX:PATH={0}'.format(pkg.prefix),
|
||||
'-DCMAKE_BUILD_TYPE:STRING={0}'.format(build_type),
|
||||
'-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON'
|
||||
]
|
||||
|
||||
if platform.mac_ver()[0]:
|
||||
args.append('-DCMAKE_FIND_FRAMEWORK:STRING=LAST')
|
||||
|
||||
# Set up CMake rpath
|
||||
args.append('-DCMAKE_INSTALL_RPATH_USE_LINK_PATH:BOOL=FALSE')
|
||||
rpaths = ':'.join(spack.build_environment.get_rpaths(pkg))
|
||||
args.append('-DCMAKE_INSTALL_RPATH:STRING={0}'.format(rpaths))
|
||||
# CMake's find_package() looks in CMAKE_PREFIX_PATH first, help CMake
|
||||
# to find immediate link dependencies in right places:
|
||||
deps = [d.prefix for d in
|
||||
pkg.spec.dependencies(deptype=('build', 'link'))]
|
||||
deps = filter_system_paths(deps)
|
||||
args.append('-DCMAKE_PREFIX_PATH:STRING={0}'.format(';'.join(deps)))
|
||||
return args
|
||||
|
||||
@property
|
||||
def build_directory(self):
|
||||
"""Returns the directory to use when building the package
|
||||
|
||||
:return: directory where to build the package
|
||||
"""
|
||||
return join_path(self.stage.source_path, 'spack-build')
|
||||
|
||||
def default_flag_handler(self, spack_env, flag_val):
|
||||
# Relies on being the first thing that can affect the spack_env
|
||||
# EnvironmentModification after it is instantiated or no other
|
||||
# method trying to affect these variables. Currently both are true
|
||||
# flag_val is a tuple (flag, value_list)
|
||||
spack_env.set(flag_val[0].upper(),
|
||||
' '.join(flag_val[1]))
|
||||
return []
|
||||
|
||||
def cmake_args(self):
|
||||
"""Produces a list containing all the arguments that must be passed to
|
||||
cmake, except:
|
||||
|
||||
* CMAKE_INSTALL_PREFIX
|
||||
* CMAKE_BUILD_TYPE
|
||||
|
||||
which will be set automatically.
|
||||
|
||||
:return: list of arguments for cmake
|
||||
"""
|
||||
return []
|
||||
|
||||
def cmake(self, spec, prefix):
|
||||
"""Runs ``cmake`` in the build directory"""
|
||||
options = [os.path.abspath(self.root_cmakelists_dir)]
|
||||
options += self.std_cmake_args
|
||||
options += self.cmake_args()
|
||||
with working_dir(self.build_directory, create=True):
|
||||
inspect.getmodule(self).cmake(*options)
|
||||
|
||||
def build(self, spec, prefix):
|
||||
"""Make the build targets"""
|
||||
with working_dir(self.build_directory):
|
||||
if self.generator == 'Unix Makefiles':
|
||||
inspect.getmodule(self).make(*self.build_targets)
|
||||
elif self.generator == 'Ninja':
|
||||
inspect.getmodule(self).ninja(*self.build_targets)
|
||||
|
||||
def install(self, spec, prefix):
|
||||
"""Make the install targets"""
|
||||
with working_dir(self.build_directory):
|
||||
if self.generator == 'Unix Makefiles':
|
||||
inspect.getmodule(self).make(*self.install_targets)
|
||||
elif self.generator == 'Ninja':
|
||||
inspect.getmodule(self).ninja(*self.install_targets)
|
||||
|
||||
run_after('build')(PackageBase._run_default_build_time_test_callbacks)
|
||||
|
||||
def check(self):
|
||||
"""Searches the CMake-generated Makefile for the target ``test``
|
||||
and runs it if found.
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
if self.generator == 'Unix Makefiles':
|
||||
self._if_make_target_execute('test')
|
||||
elif self.generator == 'Ninja':
|
||||
self._if_ninja_target_execute('test')
|
||||
|
||||
# Check that self.prefix is there after installation
|
||||
run_after('install')(PackageBase.sanity_check_prefix)
|
@@ -1,129 +0,0 @@
|
||||
##############################################################################
|
||||
# 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/llnl/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
|
||||
##############################################################################
|
||||
|
||||
import inspect
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import working_dir
|
||||
from spack.package import PackageBase, run_after
|
||||
|
||||
|
||||
class MakefilePackage(PackageBase):
|
||||
"""Specialized class for packages that are built using editable Makefiles
|
||||
|
||||
This class provides three phases that can be overridden:
|
||||
|
||||
1. :py:meth:`~.MakefilePackage.edit`
|
||||
2. :py:meth:`~.MakefilePackage.build`
|
||||
3. :py:meth:`~.MakefilePackage.install`
|
||||
|
||||
It is usually necessary to override the :py:meth:`~.MakefilePackage.edit`
|
||||
phase, while :py:meth:`~.MakefilePackage.build` and
|
||||
:py:meth:`~.MakefilePackage.install` have sensible defaults.
|
||||
For a finer tuning you may override:
|
||||
|
||||
+-----------------------------------------------+--------------------+
|
||||
| **Method** | **Purpose** |
|
||||
+===============================================+====================+
|
||||
| :py:attr:`~.MakefilePackage.build_targets` | Specify ``make`` |
|
||||
| | targets for the |
|
||||
| | build phase |
|
||||
+-----------------------------------------------+--------------------+
|
||||
| :py:attr:`~.MakefilePackage.install_targets` | Specify ``make`` |
|
||||
| | targets for the |
|
||||
| | install phase |
|
||||
+-----------------------------------------------+--------------------+
|
||||
| :py:meth:`~.MakefilePackage.build_directory` | Directory where the|
|
||||
| | Makefile is located|
|
||||
+-----------------------------------------------+--------------------+
|
||||
"""
|
||||
#: Phases of a package that is built with an hand-written Makefile
|
||||
phases = ['edit', 'build', 'install']
|
||||
#: This attribute is used in UI queries that need to know the build
|
||||
#: system base class
|
||||
build_system_class = 'MakefilePackage'
|
||||
|
||||
#: Targets for ``make`` during the :py:meth:`~.MakefilePackage.build`
|
||||
#: phase
|
||||
build_targets = []
|
||||
#: Targets for ``make`` during the :py:meth:`~.MakefilePackage.install`
|
||||
#: phase
|
||||
install_targets = ['install']
|
||||
|
||||
#: Callback names for build-time test
|
||||
build_time_test_callbacks = ['check']
|
||||
|
||||
#: Callback names for install-time test
|
||||
install_time_test_callbacks = ['installcheck']
|
||||
|
||||
@property
|
||||
def build_directory(self):
|
||||
"""Returns the directory containing the main Makefile
|
||||
|
||||
:return: build directory
|
||||
"""
|
||||
return self.stage.source_path
|
||||
|
||||
def edit(self, spec, prefix):
|
||||
"""Edits the Makefile before calling make. This phase cannot
|
||||
be defaulted.
|
||||
"""
|
||||
tty.msg('Using default implementation: skipping edit phase.')
|
||||
|
||||
def build(self, spec, prefix):
|
||||
"""Calls make, passing :py:attr:`~.MakefilePackage.build_targets`
|
||||
as targets.
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
inspect.getmodule(self).make(*self.build_targets)
|
||||
|
||||
def install(self, spec, prefix):
|
||||
"""Calls make, passing :py:attr:`~.MakefilePackage.install_targets`
|
||||
as targets.
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
inspect.getmodule(self).make(*self.install_targets)
|
||||
|
||||
run_after('build')(PackageBase._run_default_build_time_test_callbacks)
|
||||
|
||||
def check(self):
|
||||
"""Searches the Makefile for targets ``test`` and ``check``
|
||||
and runs them if found.
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
self._if_make_target_execute('test')
|
||||
self._if_make_target_execute('check')
|
||||
|
||||
run_after('install')(PackageBase._run_default_install_time_test_callbacks)
|
||||
|
||||
def installcheck(self):
|
||||
"""Searches the Makefile for an ``installcheck`` target
|
||||
and runs it if found.
|
||||
"""
|
||||
with working_dir(self.build_directory):
|
||||
self._if_make_target_execute('installcheck')
|
||||
|
||||
# Check that self.prefix is there after installation
|
||||
run_after('install')(PackageBase.sanity_check_prefix)
|
@@ -1,399 +0,0 @@
|
||||
##############################################################################
|
||||
# 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/llnl/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
|
||||
##############################################################################
|
||||
|
||||
import inspect
|
||||
import os
|
||||
|
||||
from spack.directives import depends_on, extends
|
||||
from spack.package import PackageBase, run_after
|
||||
|
||||
from llnl.util.filesystem import working_dir
|
||||
|
||||
|
||||
class PythonPackage(PackageBase):
|
||||
"""Specialized class for packages that are built using Python
|
||||
setup.py files
|
||||
|
||||
This class provides the following phases that can be overridden:
|
||||
|
||||
* build
|
||||
* build_py
|
||||
* build_ext
|
||||
* build_clib
|
||||
* build_scripts
|
||||
* clean
|
||||
* install
|
||||
* install_lib
|
||||
* install_headers
|
||||
* install_scripts
|
||||
* install_data
|
||||
* sdist
|
||||
* register
|
||||
* bdist
|
||||
* bdist_dumb
|
||||
* bdist_rpm
|
||||
* bdist_wininst
|
||||
* upload
|
||||
* check
|
||||
|
||||
These are all standard setup.py commands and can be found by running:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ python setup.py --help-commands
|
||||
|
||||
By default, only the 'build' and 'install' phases are run, but if you
|
||||
need to run more phases, simply modify your ``phases`` list like so:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
phases = ['build_ext', 'install', 'bdist']
|
||||
|
||||
Each phase provides a function <phase> that runs:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ python setup.py --no-user-cfg <phase>
|
||||
|
||||
Each phase also has a <phase_args> function that can pass arguments to
|
||||
this call. All of these functions are empty except for the ``install_args``
|
||||
function, which passes ``--prefix=/path/to/installation/directory``.
|
||||
|
||||
If you need to run a phase which is not a standard setup.py command,
|
||||
you'll need to define a function for it like so:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def configure(self, spec, prefix):
|
||||
self.setup_py('configure')
|
||||
"""
|
||||
# Default phases
|
||||
phases = ['build', 'install']
|
||||
|
||||
# Name of modules that the Python package provides
|
||||
# This is used to test whether or not the installation succeeded
|
||||
# These names generally come from running:
|
||||
#
|
||||
# >>> import setuptools
|
||||
# >>> setuptools.find_packages()
|
||||
#
|
||||
# in the source tarball directory
|
||||
import_modules = []
|
||||
|
||||
# To be used in UI queries that require to know which
|
||||
# build-system class we are using
|
||||
build_system_class = 'PythonPackage'
|
||||
|
||||
#: Callback names for build-time test
|
||||
build_time_test_callbacks = ['test']
|
||||
|
||||
#: Callback names for install-time test
|
||||
install_time_test_callbacks = ['import_module_test']
|
||||
|
||||
extends('python')
|
||||
|
||||
depends_on('python', type=('build', 'run'))
|
||||
|
||||
def setup_file(self):
|
||||
"""Returns the name of the setup file to use."""
|
||||
return 'setup.py'
|
||||
|
||||
@property
|
||||
def build_directory(self):
|
||||
"""The directory containing the ``setup.py`` file."""
|
||||
return self.stage.source_path
|
||||
|
||||
def python(self, *args, **kwargs):
|
||||
inspect.getmodule(self).python(*args, **kwargs)
|
||||
|
||||
def setup_py(self, *args, **kwargs):
|
||||
setup = self.setup_file()
|
||||
|
||||
with working_dir(self.build_directory):
|
||||
self.python(setup, '--no-user-cfg', *args, **kwargs)
|
||||
|
||||
def _setup_command_available(self, command):
|
||||
"""Determines whether or not a setup.py command exists.
|
||||
|
||||
Args:
|
||||
command (str): The command to look for
|
||||
|
||||
Returns:
|
||||
bool: True if the command is found, else False
|
||||
"""
|
||||
kwargs = {
|
||||
'output': os.devnull,
|
||||
'error': os.devnull,
|
||||
'fail_on_error': False
|
||||
}
|
||||
|
||||
python = inspect.getmodule(self).python
|
||||
setup = self.setup_file()
|
||||
|
||||
python(setup, '--no-user-cfg', command, '--help', **kwargs)
|
||||
return python.returncode == 0
|
||||
|
||||
# The following phases and their descriptions come from:
|
||||
# $ python setup.py --help-commands
|
||||
|
||||
# Standard commands
|
||||
|
||||
def build(self, spec, prefix):
|
||||
"""Build everything needed to install."""
|
||||
args = self.build_args(spec, prefix)
|
||||
|
||||
self.setup_py('build', *args)
|
||||
|
||||
def build_args(self, spec, prefix):
|
||||
"""Arguments to pass to build."""
|
||||
return []
|
||||
|
||||
def build_py(self, spec, prefix):
|
||||
'''"Build" pure Python modules (copy to build directory).'''
|
||||
args = self.build_py_args(spec, prefix)
|
||||
|
||||
self.setup_py('build_py', *args)
|
||||
|
||||
def build_py_args(self, spec, prefix):
|
||||
"""Arguments to pass to build_py."""
|
||||
return []
|
||||
|
||||
def build_ext(self, spec, prefix):
|
||||
"""Build C/C++ extensions (compile/link to build directory)."""
|
||||
args = self.build_ext_args(spec, prefix)
|
||||
|
||||
self.setup_py('build_ext', *args)
|
||||
|
||||
def build_ext_args(self, spec, prefix):
|
||||
"""Arguments to pass to build_ext."""
|
||||
return []
|
||||
|
||||
def build_clib(self, spec, prefix):
|
||||
"""Build C/C++ libraries used by Python extensions."""
|
||||
args = self.build_clib_args(spec, prefix)
|
||||
|
||||
self.setup_py('build_clib', *args)
|
||||
|
||||
def build_clib_args(self, spec, prefix):
|
||||
"""Arguments to pass to build_clib."""
|
||||
return []
|
||||
|
||||
def build_scripts(self, spec, prefix):
|
||||
'''"Build" scripts (copy and fixup #! line).'''
|
||||
args = self.build_scripts_args(spec, prefix)
|
||||
|
||||
self.setup_py('build_scripts', *args)
|
||||
|
||||
def clean(self, spec, prefix):
|
||||
"""Clean up temporary files from 'build' command."""
|
||||
args = self.clean_args(spec, prefix)
|
||||
|
||||
self.setup_py('clean', *args)
|
||||
|
||||
def clean_args(self, spec, prefix):
|
||||
"""Arguments to pass to clean."""
|
||||
return []
|
||||
|
||||
def install(self, spec, prefix):
|
||||
"""Install everything from build directory."""
|
||||
args = self.install_args(spec, prefix)
|
||||
|
||||
self.setup_py('install', *args)
|
||||
|
||||
def install_args(self, spec, prefix):
|
||||
"""Arguments to pass to install."""
|
||||
args = ['--prefix={0}'.format(prefix)]
|
||||
|
||||
# This option causes python packages (including setuptools) NOT
|
||||
# to create eggs or easy-install.pth files. Instead, they
|
||||
# install naturally into $prefix/pythonX.Y/site-packages.
|
||||
#
|
||||
# Eggs add an extra level of indirection to sys.path, slowing
|
||||
# down large HPC runs. They are also deprecated in favor of
|
||||
# wheels, which use a normal layout when installed.
|
||||
#
|
||||
# Spack manages the package directory on its own by symlinking
|
||||
# extensions into the site-packages directory, so we don't really
|
||||
# need the .pth files or egg directories, anyway.
|
||||
if ('py-setuptools' == spec.name or # this is setuptools, or
|
||||
'py-setuptools' in spec._dependencies): # it's an immediate dep
|
||||
args += ['--single-version-externally-managed', '--root=/']
|
||||
|
||||
return args
|
||||
|
||||
def install_lib(self, spec, prefix):
|
||||
"""Install all Python modules (extensions and pure Python)."""
|
||||
args = self.install_lib_args(spec, prefix)
|
||||
|
||||
self.setup_py('install_lib', *args)
|
||||
|
||||
def install_lib_args(self, spec, prefix):
|
||||
"""Arguments to pass to install_lib."""
|
||||
return []
|
||||
|
||||
def install_headers(self, spec, prefix):
|
||||
"""Install C/C++ header files."""
|
||||
args = self.install_headers_args(spec, prefix)
|
||||
|
||||
self.setup_py('install_headers', *args)
|
||||
|
||||
def install_headers_args(self, spec, prefix):
|
||||
"""Arguments to pass to install_headers."""
|
||||
return []
|
||||
|
||||
def install_scripts(self, spec, prefix):
|
||||
"""Install scripts (Python or otherwise)."""
|
||||
args = self.install_scripts_args(spec, prefix)
|
||||
|
||||
self.setup_py('install_scripts', *args)
|
||||
|
||||
def install_scripts_args(self, spec, prefix):
|
||||
"""Arguments to pass to install_scripts."""
|
||||
return []
|
||||
|
||||
def install_data(self, spec, prefix):
|
||||
"""Install data files."""
|
||||
args = self.install_data_args(spec, prefix)
|
||||
|
||||
self.setup_py('install_data', *args)
|
||||
|
||||
def install_data_args(self, spec, prefix):
|
||||
"""Arguments to pass to install_data."""
|
||||
return []
|
||||
|
||||
def sdist(self, spec, prefix):
|
||||
"""Create a source distribution (tarball, zip file, etc.)."""
|
||||
args = self.sdist_args(spec, prefix)
|
||||
|
||||
self.setup_py('sdist', *args)
|
||||
|
||||
def sdist_args(self, spec, prefix):
|
||||
"""Arguments to pass to sdist."""
|
||||
return []
|
||||
|
||||
def register(self, spec, prefix):
|
||||
"""Register the distribution with the Python package index."""
|
||||
args = self.register_args(spec, prefix)
|
||||
|
||||
self.setup_py('register', *args)
|
||||
|
||||
def register_args(self, spec, prefix):
|
||||
"""Arguments to pass to register."""
|
||||
return []
|
||||
|
||||
def bdist(self, spec, prefix):
|
||||
"""Create a built (binary) distribution."""
|
||||
args = self.bdist_args(spec, prefix)
|
||||
|
||||
self.setup_py('bdist', *args)
|
||||
|
||||
def bdist_args(self, spec, prefix):
|
||||
"""Arguments to pass to bdist."""
|
||||
return []
|
||||
|
||||
def bdist_dumb(self, spec, prefix):
|
||||
'''Create a "dumb" built distribution.'''
|
||||
args = self.bdist_dumb_args(spec, prefix)
|
||||
|
||||
self.setup_py('bdist_dumb', *args)
|
||||
|
||||
def bdist_dumb_args(self, spec, prefix):
|
||||
"""Arguments to pass to bdist_dumb."""
|
||||
return []
|
||||
|
||||
def bdist_rpm(self, spec, prefix):
|
||||
"""Create an RPM distribution."""
|
||||
args = self.bdist_rpm(spec, prefix)
|
||||
|
||||
self.setup_py('bdist_rpm', *args)
|
||||
|
||||
def bdist_rpm_args(self, spec, prefix):
|
||||
"""Arguments to pass to bdist_rpm."""
|
||||
return []
|
||||
|
||||
def bdist_wininst(self, spec, prefix):
|
||||
"""Create an executable installer for MS Windows."""
|
||||
args = self.bdist_wininst_args(spec, prefix)
|
||||
|
||||
self.setup_py('bdist_wininst', *args)
|
||||
|
||||
def bdist_wininst_args(self, spec, prefix):
|
||||
"""Arguments to pass to bdist_wininst."""
|
||||
return []
|
||||
|
||||
def upload(self, spec, prefix):
|
||||
"""Upload binary package to PyPI."""
|
||||
args = self.upload_args(spec, prefix)
|
||||
|
||||
self.setup_py('upload', *args)
|
||||
|
||||
def upload_args(self, spec, prefix):
|
||||
"""Arguments to pass to upload."""
|
||||
return []
|
||||
|
||||
def check(self, spec, prefix):
|
||||
"""Perform some checks on the package."""
|
||||
args = self.check_args(spec, prefix)
|
||||
|
||||
self.setup_py('check', *args)
|
||||
|
||||
def check_args(self, spec, prefix):
|
||||
"""Arguments to pass to check."""
|
||||
return []
|
||||
|
||||
# Testing
|
||||
|
||||
def test(self):
|
||||
"""Run unit tests after in-place build.
|
||||
|
||||
These tests are only run if the package actually has a 'test' command.
|
||||
"""
|
||||
if self._setup_command_available('test'):
|
||||
args = self.test_args(self.spec, self.prefix)
|
||||
|
||||
self.setup_py('test', *args)
|
||||
|
||||
def test_args(self, spec, prefix):
|
||||
"""Arguments to pass to test."""
|
||||
return []
|
||||
|
||||
run_after('build')(PackageBase._run_default_build_time_test_callbacks)
|
||||
|
||||
def import_module_test(self):
|
||||
"""Attempts to import the module that was just installed.
|
||||
|
||||
This test is only run if the package overrides
|
||||
:py:attr:`import_modules` with a list of module names."""
|
||||
|
||||
# Make sure we are importing the installed modules,
|
||||
# not the ones in the current directory
|
||||
with working_dir('..'):
|
||||
for module in self.import_modules:
|
||||
self.python('-c', 'import {0}'.format(module))
|
||||
|
||||
run_after('install')(PackageBase._run_default_install_time_test_callbacks)
|
||||
|
||||
# Check that self.prefix is there after installation
|
||||
run_after('install')(PackageBase.sanity_check_prefix)
|
@@ -103,7 +103,7 @@ This will open the :code:`AutotoolsPackage` file in your text editor.
|
||||
long examples. We only show what is relevant to the packager.
|
||||
|
||||
|
||||
.. literalinclude:: tutorial/examples/Autotools/autotools_class.py
|
||||
.. literalinclude:: ../../../lib/spack/spack/build_systems/autotools.py
|
||||
:language: python
|
||||
:emphasize-lines: 42,45,62
|
||||
:lines: 40-95,259-267
|
||||
@@ -202,7 +202,7 @@ Let's also take a look inside the :code:`MakefilePackage` class:
|
||||
Take note of the following:
|
||||
|
||||
|
||||
.. literalinclude:: tutorial/examples/Makefile/makefile_class.py
|
||||
.. literalinclude:: ../../../lib/spack/spack/build_systems/makefile.py
|
||||
:language: python
|
||||
:lines: 33-79,89-107
|
||||
:emphasize-lines: 48,54,61
|
||||
@@ -480,7 +480,7 @@ Let's look at these defaults in the :code:`CMakePackage` class:
|
||||
And go into a bit of detail on the highlighted sections:
|
||||
|
||||
|
||||
.. literalinclude:: tutorial/examples/Cmake/cmake_class.py
|
||||
.. literalinclude:: ../../../lib/spack/spack/build_systems/cmake.py
|
||||
:language: python
|
||||
:lines: 37-92, 94-155, 174-211
|
||||
:emphasize-lines: 57,68,86,94,96,99,100,101,102,111,117,135,136
|
||||
@@ -675,7 +675,7 @@ at the :code:`PythonPackage` class:
|
||||
We see the following:
|
||||
|
||||
|
||||
.. literalinclude:: tutorial/examples/PyPackage/python_package_class.py
|
||||
.. literalinclude:: ../../../lib/spack/spack/build_systems/python.py
|
||||
:language: python
|
||||
:lines: 35, 161-364
|
||||
:linenos:
|
||||
|
@@ -96,7 +96,7 @@
|
||||
# Initialize various data structures & objects at the core of Spack.
|
||||
#-----------------------------------------------------------------------------
|
||||
# Version information
|
||||
spack_version = Version("0.10.0")
|
||||
spack_version = Version("0.11.2")
|
||||
|
||||
|
||||
# Set up the default packages database.
|
||||
|
@@ -28,6 +28,7 @@
|
||||
import tarfile
|
||||
import yaml
|
||||
import shutil
|
||||
import platform
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from spack.util.gpg import Gpg
|
||||
@@ -95,7 +96,7 @@ def read_buildinfo_file(prefix):
|
||||
return buildinfo
|
||||
|
||||
|
||||
def write_buildinfo_file(prefix, rel=False):
|
||||
def write_buildinfo_file(prefix, workdir, rel=False):
|
||||
"""
|
||||
Create a cache file containing information
|
||||
required for the relocation
|
||||
@@ -103,6 +104,7 @@ def write_buildinfo_file(prefix, rel=False):
|
||||
text_to_relocate = []
|
||||
binary_to_relocate = []
|
||||
blacklist = (".spack", "man")
|
||||
os_id = platform.system()
|
||||
# Do this at during tarball creation to save time when tarball unpacked.
|
||||
# Used by make_package_relative to determine binaries to change.
|
||||
for root, dirs, files in os.walk(prefix, topdown=True):
|
||||
@@ -110,7 +112,7 @@ def write_buildinfo_file(prefix, rel=False):
|
||||
for filename in files:
|
||||
path_name = os.path.join(root, filename)
|
||||
filetype = relocate.get_filetype(path_name)
|
||||
if relocate.needs_binary_relocation(filetype):
|
||||
if relocate.needs_binary_relocation(filetype, os_id):
|
||||
rel_path_name = os.path.relpath(path_name, prefix)
|
||||
binary_to_relocate.append(rel_path_name)
|
||||
elif relocate.needs_text_relocation(filetype):
|
||||
@@ -123,7 +125,7 @@ def write_buildinfo_file(prefix, rel=False):
|
||||
buildinfo['buildpath'] = spack.store.layout.root
|
||||
buildinfo['relocate_textfiles'] = text_to_relocate
|
||||
buildinfo['relocate_binaries'] = binary_to_relocate
|
||||
filename = buildinfo_file_name(prefix)
|
||||
filename = buildinfo_file_name(workdir)
|
||||
with open(filename, 'w') as outfile:
|
||||
outfile.write(yaml.dump(buildinfo, default_flow_style=True))
|
||||
|
||||
@@ -247,7 +249,7 @@ def build_tarball(spec, outdir, force=False, rel=False, yes_to_all=False,
|
||||
install_tree(spec.prefix, workdir, symlinks=True)
|
||||
|
||||
# create info for later relocation and create tar
|
||||
write_buildinfo_file(workdir, rel=rel)
|
||||
write_buildinfo_file(spec.prefix, workdir, rel=rel)
|
||||
|
||||
# optinally make the paths in the binaries relative to each other
|
||||
# in the spack install tree before creating tarball
|
||||
@@ -359,7 +361,9 @@ def relocate_package(prefix):
|
||||
path_names = set()
|
||||
for filename in buildinfo['relocate_textfiles']:
|
||||
path_name = os.path.join(prefix, filename)
|
||||
path_names.add(path_name)
|
||||
# Don't add backup files generated by filter_file during install step.
|
||||
if not path_name.endswith('~'):
|
||||
path_names.add(path_name)
|
||||
relocate.relocate_text(path_names, old_path, new_path)
|
||||
# If the binary files in the package were not edited to use
|
||||
# relative RPATHs, then the RPATHs need to be relocated
|
||||
|
@@ -57,6 +57,7 @@
|
||||
import shutil
|
||||
import sys
|
||||
import traceback
|
||||
import types
|
||||
from six import iteritems
|
||||
from six import StringIO
|
||||
|
||||
@@ -128,7 +129,6 @@ def __call__(self, *args, **kwargs):
|
||||
def set_compiler_environment_variables(pkg, env):
|
||||
assert(pkg.spec.concrete)
|
||||
compiler = pkg.compiler
|
||||
flags = pkg.spec.compiler_flags
|
||||
|
||||
# Set compiler variables used by CMake and autotools
|
||||
assert all(key in compiler.link_paths for key in (
|
||||
@@ -160,11 +160,40 @@ def set_compiler_environment_variables(pkg, env):
|
||||
env.set('SPACK_F77_RPATH_ARG', compiler.f77_rpath_arg)
|
||||
env.set('SPACK_FC_RPATH_ARG', compiler.fc_rpath_arg)
|
||||
|
||||
# Add every valid compiler flag to the environment, prefixed with "SPACK_"
|
||||
# Trap spack-tracked compiler flags as appropriate.
|
||||
# env_flags are easy to accidentally override.
|
||||
inject_flags = {}
|
||||
env_flags = {}
|
||||
build_system_flags = {}
|
||||
for flag in spack.spec.FlagMap.valid_compiler_flags():
|
||||
# Always convert flag_handler to function type.
|
||||
# This avoids discrepencies in calling conventions between functions
|
||||
# and methods, or between bound and unbound methods in python 2.
|
||||
# We cannot effectively convert everything to a bound method, which
|
||||
# would be the simpler solution.
|
||||
if isinstance(pkg.flag_handler, types.FunctionType):
|
||||
handler = pkg.flag_handler
|
||||
else:
|
||||
if sys.version_info >= (3, 0):
|
||||
handler = pkg.flag_handler.__func__
|
||||
else:
|
||||
handler = pkg.flag_handler.im_func
|
||||
injf, envf, bsf = handler(pkg, flag, pkg.spec.compiler_flags[flag])
|
||||
inject_flags[flag] = injf or []
|
||||
env_flags[flag] = envf or []
|
||||
build_system_flags[flag] = bsf or []
|
||||
|
||||
# Place compiler flags as specified by flag_handler
|
||||
for flag in spack.spec.FlagMap.valid_compiler_flags():
|
||||
# Concreteness guarantees key safety here
|
||||
if flags[flag] != []:
|
||||
env.set('SPACK_' + flag.upper(), ' '.join(f for f in flags[flag]))
|
||||
if inject_flags[flag]:
|
||||
# variables SPACK_<FLAG> inject flags through wrapper
|
||||
var_name = 'SPACK_{0}'.format(flag.upper())
|
||||
env.set(var_name, ' '.join(f for f in inject_flags[flag]))
|
||||
if env_flags[flag]:
|
||||
# implicit variables
|
||||
env.set(flag.upper(), ' '.join(f for f in env_flags[flag]))
|
||||
pkg.flags_to_build_system_args(build_system_flags)
|
||||
|
||||
env.set('SPACK_COMPILER_SPEC', str(pkg.spec.compiler))
|
||||
|
||||
@@ -559,19 +588,6 @@ def setup_package(pkg, dirty):
|
||||
for s in pkg.spec.traverse():
|
||||
assert s.package.spec is s
|
||||
|
||||
# Trap spack-tracked compiler flags as appropriate.
|
||||
# Must be before set_compiler_environment_variables
|
||||
# Current implementation of default flag handler relies on this being
|
||||
# the first thing to affect the spack_env (so there is no appending), or
|
||||
# on no other build_environment methods trying to affect these variables
|
||||
# (CFLAGS, CXXFLAGS, etc). Currently both are true, either is sufficient.
|
||||
for flag in spack.spec.FlagMap.valid_compiler_flags():
|
||||
trap_func = getattr(pkg, flag + '_handler',
|
||||
getattr(pkg, 'default_flag_handler',
|
||||
lambda x, y: y[1]))
|
||||
flag_val = pkg.spec.compiler_flags[flag]
|
||||
pkg.spec.compiler_flags[flag] = trap_func(spack_env, (flag, flag_val))
|
||||
|
||||
set_compiler_environment_variables(pkg, spack_env)
|
||||
set_build_environment_variables(pkg, spack_env, dirty)
|
||||
pkg.architecture.platform.setup_platform_environment(pkg, spack_env)
|
||||
|
@@ -182,15 +182,6 @@ def build_directory(self):
|
||||
"""Override to provide another place to build the package"""
|
||||
return self.configure_directory
|
||||
|
||||
def default_flag_handler(self, spack_env, flag_val):
|
||||
# Relies on being the first thing that can affect the spack_env
|
||||
# EnvironmentModification after it is instantiated or no other
|
||||
# method trying to affect these variables. Currently both are true
|
||||
# flag_val is a tuple (flag, value_list).
|
||||
spack_env.set(flag_val[0].upper(),
|
||||
' '.join(flag_val[1]))
|
||||
return []
|
||||
|
||||
@run_before('autoreconf')
|
||||
def delete_configure_to_force_update(self):
|
||||
if self.force_autoreconf:
|
||||
@@ -256,12 +247,24 @@ def configure_args(self):
|
||||
"""
|
||||
return []
|
||||
|
||||
def flags_to_build_system_args(self, flags):
|
||||
"""Produces a list of all command line arguments to pass specified
|
||||
compiler flags to configure."""
|
||||
# Has to be dynamic attribute due to caching.
|
||||
setattr(self, 'configure_flag_args', [])
|
||||
for flag, values in flags.items():
|
||||
if values:
|
||||
values_str = '{0}={1}'.format(flag.upper(), ' '.join(values))
|
||||
self.configure_flag_args.append(values_str)
|
||||
|
||||
def configure(self, spec, prefix):
|
||||
"""Runs configure with the arguments specified in
|
||||
:py:meth:`~.AutotoolsPackage.configure_args`
|
||||
and an appropriately set prefix.
|
||||
"""
|
||||
options = ['--prefix={0}'.format(prefix)] + self.configure_args()
|
||||
options = getattr(self, 'configure_flag_args', [])
|
||||
options += ['--prefix={0}'.format(prefix)]
|
||||
options += self.configure_args()
|
||||
|
||||
with working_dir(self.build_directory, create=True):
|
||||
inspect.getmodule(self).configure(*options)
|
||||
|
@@ -109,7 +109,9 @@ def std_cmake_args(self):
|
||||
:return: standard cmake arguments
|
||||
"""
|
||||
# standard CMake arguments
|
||||
return CMakePackage._std_args(self)
|
||||
std_cmake_args = CMakePackage._std_args(self)
|
||||
std_cmake_args += getattr(self, 'cmake_flag_args', [])
|
||||
return std_cmake_args
|
||||
|
||||
@staticmethod
|
||||
def _std_args(pkg):
|
||||
@@ -154,6 +156,44 @@ def _std_args(pkg):
|
||||
args.append('-DCMAKE_PREFIX_PATH:STRING={0}'.format(';'.join(deps)))
|
||||
return args
|
||||
|
||||
def flags_to_build_system_args(self, flags):
|
||||
"""Produces a list of all command line arguments to pass the specified
|
||||
compiler flags to cmake. Note CMAKE does not have a cppflags option,
|
||||
so cppflags will be added to cflags, cxxflags, and fflags to mimic the
|
||||
behavior in other tools."""
|
||||
# Has to be dynamic attribute due to caching
|
||||
setattr(self, 'cmake_flag_args', [])
|
||||
|
||||
flag_string = '-DCMAKE_{0}_FLAGS={1}'
|
||||
langs = {'C': 'c', 'CXX': 'cxx', 'Fortran': 'f'}
|
||||
|
||||
# Handle language compiler flags
|
||||
for lang, pre in langs.items():
|
||||
flag = pre + 'flags'
|
||||
# cmake has no explicit cppflags support -> add it to all langs
|
||||
lang_flags = ' '.join(flags.get(flag, []) + flags.get('cppflags',
|
||||
[]))
|
||||
if lang_flags:
|
||||
self.cmake_flag_args.append(flag_string.format(lang,
|
||||
lang_flags))
|
||||
|
||||
# Cmake has different linker arguments for different build types.
|
||||
# We specify for each of them.
|
||||
if flags['ldflags']:
|
||||
ldflags = ' '.join(flags['ldflags'])
|
||||
ld_string = '-DCMAKE_{0}_LINKER_FLAGS={1}'
|
||||
# cmake has separate linker arguments for types of builds.
|
||||
for type in ['EXE', 'MODULE', 'SHARED', 'STATIC']:
|
||||
self.cmake_flag_args.append(ld_string.format(type, ldflags))
|
||||
|
||||
# CMake has libs options separated by language. Apply ours to each.
|
||||
if flags['ldlibs']:
|
||||
libs_flags = ' '.join(flags['ldlibs'])
|
||||
libs_string = '-DCMAKE_{0}_STANDARD_LIBRARIES={1}'
|
||||
for lang in langs:
|
||||
self.cmake_flag_args.append(libs_string.format(lang,
|
||||
libs_flags))
|
||||
|
||||
@property
|
||||
def build_directory(self):
|
||||
"""Returns the directory to use when building the package
|
||||
@@ -162,15 +202,6 @@ def build_directory(self):
|
||||
"""
|
||||
return join_path(self.stage.source_path, 'spack-build')
|
||||
|
||||
def default_flag_handler(self, spack_env, flag_val):
|
||||
# Relies on being the first thing that can affect the spack_env
|
||||
# EnvironmentModification after it is instantiated or no other
|
||||
# method trying to affect these variables. Currently both are true
|
||||
# flag_val is a tuple (flag, value_list)
|
||||
spack_env.set(flag_val[0].upper(),
|
||||
' '.join(flag_val[1]))
|
||||
return []
|
||||
|
||||
def cmake_args(self):
|
||||
"""Produces a list containing all the arguments that must be passed to
|
||||
cmake, except:
|
||||
|
@@ -126,14 +126,14 @@ def pic_flag(self):
|
||||
|
||||
@classmethod
|
||||
def default_version(cls, comp):
|
||||
"""The '--version' option works for clang compilers.
|
||||
"""The ``--version`` option works for clang compilers.
|
||||
On most platforms, output looks like this::
|
||||
|
||||
clang version 3.1 (trunk 149096)
|
||||
Target: x86_64-unknown-linux-gnu
|
||||
Thread model: posix
|
||||
|
||||
On Mac OS X, it looks like this::
|
||||
On macOS, it looks like this::
|
||||
|
||||
Apple LLVM version 7.0.2 (clang-700.1.81)
|
||||
Target: x86_64-apple-darwin15.2.0
|
||||
|
@@ -91,6 +91,21 @@ def pic_flag(self):
|
||||
|
||||
@classmethod
|
||||
def default_version(cls, cc):
|
||||
"""Older versions of gcc use the ``-dumpversion`` option.
|
||||
Output looks like this::
|
||||
|
||||
4.4.7
|
||||
|
||||
In GCC 7, this option was changed to only return the major
|
||||
version of the compiler::
|
||||
|
||||
7
|
||||
|
||||
A new ``-dumpfullversion`` option was added that gives us
|
||||
what we want::
|
||||
|
||||
7.2.0
|
||||
"""
|
||||
# Skip any gcc versions that are actually clang, like Apple's gcc.
|
||||
# Returning "unknown" makes them not detected by default.
|
||||
# Users can add these manually to compilers.yaml at their own risk.
|
||||
@@ -104,10 +119,32 @@ def default_version(cls, cc):
|
||||
|
||||
@classmethod
|
||||
def fc_version(cls, fc):
|
||||
return get_compiler_version(
|
||||
"""Older versions of gfortran use the ``-dumpversion`` option.
|
||||
Output looks like this::
|
||||
|
||||
GNU Fortran (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18)
|
||||
Copyright (C) 2010 Free Software Foundation, Inc.
|
||||
|
||||
or::
|
||||
|
||||
4.8.5
|
||||
|
||||
In GCC 7, this option was changed to only return the major
|
||||
version of the compiler::
|
||||
|
||||
7
|
||||
|
||||
A new ``-dumpfullversion`` option was added that gives us
|
||||
what we want::
|
||||
|
||||
7.2.0
|
||||
"""
|
||||
version = get_compiler_version(
|
||||
fc, '-dumpversion',
|
||||
# older gfortran versions don't have simple dumpversion output.
|
||||
r'(?:GNU Fortran \(GCC\))?(\d+\.\d+(?:\.\d+)?)')
|
||||
r'(?:GNU Fortran \(GCC\) )?([\d.]+)')
|
||||
if version in ['7']:
|
||||
version = get_compiler_version(fc, '-dumpfullversion')
|
||||
return version
|
||||
|
||||
@classmethod
|
||||
def f77_version(cls, f77):
|
||||
|
@@ -82,7 +82,7 @@ def pic_flag(self):
|
||||
|
||||
@classmethod
|
||||
def default_version(cls, comp):
|
||||
"""The '--version' option seems to be the most consistent one
|
||||
"""The ``--version`` option seems to be the most consistent one
|
||||
for intel compilers. Output looks like this::
|
||||
|
||||
icpc (ICC) 12.1.5 20120612
|
||||
|
@@ -73,7 +73,7 @@ def fc_rpath_arg(self):
|
||||
|
||||
@classmethod
|
||||
def default_version(self, comp):
|
||||
"""The '-V' option works for nag compilers.
|
||||
"""The ``-V`` option works for nag compilers.
|
||||
Output looks like this::
|
||||
|
||||
NAG Fortran Compiler Release 6.0(Hibiya) Build 1037
|
||||
|
@@ -505,7 +505,7 @@ def configure_options(self):
|
||||
try:
|
||||
configure_args = getattr(pkg, attr)()
|
||||
return ' '.join(configure_args)
|
||||
except (AttributeError, IOError, KeyError):
|
||||
except (AttributeError, IOError, KeyError, NameError):
|
||||
# The method doesn't exist in the current spec,
|
||||
# or it's not usable
|
||||
pass
|
||||
|
@@ -1707,6 +1707,47 @@ def setup_dependent_package(self, module, dependent_spec):
|
||||
"""
|
||||
pass
|
||||
|
||||
def inject_flags(self, name, flags):
|
||||
"""
|
||||
flag_handler that injects all flags through the compiler wrapper.
|
||||
"""
|
||||
return (flags, None, None)
|
||||
|
||||
def env_flags(self, name, flags):
|
||||
"""
|
||||
flag_handler that adds all flags to canonical environment variables.
|
||||
"""
|
||||
return (None, flags, None)
|
||||
|
||||
def build_system_flags(self, name, flags):
|
||||
"""
|
||||
flag_handler that passes flags to the build system arguments. Any
|
||||
package using `build_system_flags` must also implement
|
||||
`flags_to_build_system_args`, or derive from a class that
|
||||
implements it. Currently, AutotoolsPackage and CMakePackage
|
||||
implement it.
|
||||
"""
|
||||
return (None, None, flags)
|
||||
|
||||
flag_handler = inject_flags
|
||||
# The flag handler method is called for each of the allowed compiler flags.
|
||||
# It returns a triple of inject_flags, env_flags, build_system_flags.
|
||||
# The flags returned as inject_flags are injected through the spack
|
||||
# compiler wrappers.
|
||||
# The flags returned as env_flags are passed to the build system through
|
||||
# the environment variables of the same name.
|
||||
# The flags returned as build_system_flags are passed to the build system
|
||||
# package subclass to be turned into the appropriate part of the standard
|
||||
# arguments. This is implemented for build system classes where
|
||||
# appropriate and will otherwise raise a NotImplementedError.
|
||||
|
||||
def flags_to_build_system_args(self, flags):
|
||||
# Takes flags as a dict name: list of values
|
||||
if any(v for v in flags.values()):
|
||||
msg = 'The {0} build system'.format(self.__class__.__name__)
|
||||
msg += ' cannot take command line arguments for compiler flags'
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
@staticmethod
|
||||
def uninstall_by_spec(spec, force=False):
|
||||
if not os.path.isdir(spec.prefix):
|
||||
|
@@ -210,21 +210,21 @@ def modify_elf_object(path_name, orig_rpath, new_rpath):
|
||||
tty.die('relocation not supported for this platform')
|
||||
|
||||
|
||||
def needs_binary_relocation(filetype):
|
||||
def needs_binary_relocation(filetype, os_id=None):
|
||||
"""
|
||||
Check whether the given filetype is a binary that may need relocation.
|
||||
"""
|
||||
retval = False
|
||||
if "relocatable" in filetype:
|
||||
return False
|
||||
if "link" in filetype:
|
||||
if "link to" in filetype:
|
||||
return False
|
||||
if platform.system() == 'Darwin':
|
||||
return ('Mach-O' in filetype)
|
||||
elif platform.system() == 'Linux':
|
||||
return ('ELF' in filetype)
|
||||
if os_id == 'Darwin':
|
||||
return ("Mach-O" in filetype)
|
||||
elif os_id == 'Linux':
|
||||
return ("ELF" in filetype)
|
||||
else:
|
||||
tty.die("Relocation not implemented for %s" % platform.system())
|
||||
tty.die("Relocation not implemented for %s" % os_id)
|
||||
return retval
|
||||
|
||||
|
||||
@@ -232,7 +232,7 @@ def needs_text_relocation(filetype):
|
||||
"""
|
||||
Check whether the given filetype is text that may need relocation.
|
||||
"""
|
||||
if "link" in filetype:
|
||||
if "link to" in filetype:
|
||||
return False
|
||||
return ("text" in filetype)
|
||||
|
||||
@@ -289,7 +289,7 @@ def relocate_text(path_names, old_dir, new_dir):
|
||||
"""
|
||||
Replace old path with new path in text file path_name
|
||||
"""
|
||||
filter_file("r'%s'" % old_dir, "r'%s'" % new_dir,
|
||||
filter_file('%s' % old_dir, '%s' % new_dir,
|
||||
*path_names, backup=False)
|
||||
|
||||
|
||||
|
@@ -211,8 +211,12 @@ def test_flags(self):
|
||||
' '.join(test_command) + ' ' +
|
||||
'-lfoo')
|
||||
|
||||
os.environ['SPACK_LDFLAGS'] = ''
|
||||
os.environ['SPACK_LDLIBS'] = ''
|
||||
del os.environ['SPACK_CFLAGS']
|
||||
del os.environ['SPACK_CXXFLAGS']
|
||||
del os.environ['SPACK_FFLAGS']
|
||||
del os.environ['SPACK_CPPFLAGS']
|
||||
del os.environ['SPACK_LDFLAGS']
|
||||
del os.environ['SPACK_LDLIBS']
|
||||
|
||||
def test_dep_rpath(self):
|
||||
"""Ensure RPATHs for root package are added."""
|
||||
|
188
lib/spack/spack/test/flag_handlers.py
Normal file
188
lib/spack/spack/test/flag_handlers.py
Normal file
@@ -0,0 +1,188 @@
|
||||
##############################################################################
|
||||
# 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
|
||||
##############################################################################
|
||||
import pytest
|
||||
import os
|
||||
|
||||
import spack.spec
|
||||
import spack.build_environment
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def temp_env():
|
||||
old_env = os.environ.copy()
|
||||
yield
|
||||
os.environ = old_env
|
||||
|
||||
|
||||
def add_O3_to_build_system_cflags(pkg, name, flags):
|
||||
build_system_flags = []
|
||||
if name == 'cflags':
|
||||
build_system_flags.append('-O3')
|
||||
return (flags, None, build_system_flags)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('config')
|
||||
class TestFlagHandlers(object):
|
||||
def test_no_build_system_flags(self, temp_env):
|
||||
# Test that both autotools and cmake work getting no build_system flags
|
||||
s1 = spack.spec.Spec('callpath')
|
||||
s1.concretize()
|
||||
pkg1 = spack.repo.get(s1)
|
||||
spack.build_environment.setup_package(pkg1, False)
|
||||
|
||||
s2 = spack.spec.Spec('libelf')
|
||||
s2.concretize()
|
||||
pkg2 = spack.repo.get(s2)
|
||||
spack.build_environment.setup_package(pkg2, False)
|
||||
|
||||
# Use cppflags as a canary
|
||||
assert 'SPACK_CPPFLAGS' not in os.environ
|
||||
assert 'CPPFLAGS' not in os.environ
|
||||
|
||||
def test_unbound_method(self, temp_env):
|
||||
# Other tests test flag_handlers set as bound methods and functions.
|
||||
# This tests an unbound method in python2 (no change in python3).
|
||||
s = spack.spec.Spec('mpileaks cppflags=-g')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = pkg.__class__.inject_flags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert os.environ['SPACK_CPPFLAGS'] == '-g'
|
||||
assert 'CPPFLAGS' not in os.environ
|
||||
|
||||
def test_inject_flags(self, temp_env):
|
||||
s = spack.spec.Spec('mpileaks cppflags=-g')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = pkg.inject_flags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert os.environ['SPACK_CPPFLAGS'] == '-g'
|
||||
assert 'CPPFLAGS' not in os.environ
|
||||
|
||||
def test_env_flags(self, temp_env):
|
||||
s = spack.spec.Spec('mpileaks cppflags=-g')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = pkg.env_flags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert os.environ['CPPFLAGS'] == '-g'
|
||||
assert 'SPACK_CPPFLAGS' not in os.environ
|
||||
|
||||
def test_build_system_flags_cmake(self, temp_env):
|
||||
s = spack.spec.Spec('callpath cppflags=-g')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = pkg.build_system_flags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert 'SPACK_CPPFLAGS' not in os.environ
|
||||
assert 'CPPFLAGS' not in os.environ
|
||||
|
||||
expected = set(['-DCMAKE_C_FLAGS=-g', '-DCMAKE_CXX_FLAGS=-g',
|
||||
'-DCMAKE_Fortran_FLAGS=-g'])
|
||||
assert set(pkg.cmake_flag_args) == expected
|
||||
|
||||
def test_build_system_flags_autotools(self, temp_env):
|
||||
s = spack.spec.Spec('libelf cppflags=-g')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = pkg.build_system_flags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert 'SPACK_CPPFLAGS' not in os.environ
|
||||
assert 'CPPFLAGS' not in os.environ
|
||||
|
||||
assert 'CPPFLAGS=-g' in pkg.configure_flag_args
|
||||
|
||||
def test_build_system_flags_not_implemented(self, temp_env):
|
||||
s = spack.spec.Spec('mpileaks cppflags=-g')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = pkg.build_system_flags
|
||||
|
||||
# Test the command line flags method raises a NotImplementedError
|
||||
try:
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
assert False
|
||||
except NotImplementedError:
|
||||
assert True
|
||||
|
||||
def test_add_build_system_flags_autotools(self, temp_env):
|
||||
s = spack.spec.Spec('libelf cppflags=-g')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = add_O3_to_build_system_cflags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert '-g' in os.environ['SPACK_CPPFLAGS']
|
||||
assert 'CPPFLAGS' not in os.environ
|
||||
|
||||
assert pkg.configure_flag_args == ['CFLAGS=-O3']
|
||||
|
||||
def test_add_build_system_flags_cmake(self, temp_env):
|
||||
s = spack.spec.Spec('callpath cppflags=-g')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = add_O3_to_build_system_cflags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert '-g' in os.environ['SPACK_CPPFLAGS']
|
||||
assert 'CPPFLAGS' not in os.environ
|
||||
|
||||
assert pkg.cmake_flag_args == ['-DCMAKE_C_FLAGS=-O3']
|
||||
|
||||
def test_ld_flags_cmake(self, temp_env):
|
||||
s = spack.spec.Spec('callpath ldflags=-mthreads')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = pkg.build_system_flags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert 'SPACK_LDFLAGS' not in os.environ
|
||||
assert 'LDFLAGS' not in os.environ
|
||||
|
||||
expected = set(['-DCMAKE_EXE_LINKER_FLAGS=-mthreads',
|
||||
'-DCMAKE_MODULE_LINKER_FLAGS=-mthreads',
|
||||
'-DCMAKE_SHARED_LINKER_FLAGS=-mthreads',
|
||||
'-DCMAKE_STATIC_LINKER_FLAGS=-mthreads'])
|
||||
assert set(pkg.cmake_flag_args) == expected
|
||||
|
||||
def test_ld_libs_cmake(self, temp_env):
|
||||
s = spack.spec.Spec('callpath ldlibs=-lfoo')
|
||||
s.concretize()
|
||||
pkg = spack.repo.get(s)
|
||||
pkg.flag_handler = pkg.build_system_flags
|
||||
spack.build_environment.setup_package(pkg, False)
|
||||
|
||||
assert 'SPACK_LDLIBS' not in os.environ
|
||||
assert 'LDLIBS' not in os.environ
|
||||
|
||||
expected = set(['-DCMAKE_C_STANDARD_LIBRARIES=-lfoo',
|
||||
'-DCMAKE_CXX_STANDARD_LIBRARIES=-lfoo',
|
||||
'-DCMAKE_Fortran_STANDARD_LIBRARIES=-lfoo'])
|
||||
assert set(pkg.cmake_flag_args) == expected
|
@@ -42,7 +42,7 @@
|
||||
from spack.fetch_strategy import URLFetchStrategy, FetchStrategyComposite
|
||||
from spack.util.executable import ProcessError
|
||||
from spack.relocate import needs_binary_relocation, needs_text_relocation
|
||||
from spack.relocate import get_patchelf
|
||||
from spack.relocate import get_patchelf, relocate_text
|
||||
from spack.relocate import substitute_rpath, get_relative_rpaths
|
||||
from spack.relocate import macho_replace_paths, macho_make_paths_relative
|
||||
from spack.relocate import modify_macho_object, macho_get_paths
|
||||
@@ -217,10 +217,43 @@ def test_packaging(mock_archive, tmpdir):
|
||||
stage.destroy()
|
||||
|
||||
|
||||
def test_relocate():
|
||||
assert (needs_binary_relocation('relocatable') is False)
|
||||
assert (needs_binary_relocation('link') is False)
|
||||
assert (needs_text_relocation('link') is False)
|
||||
def test_relocate_text():
|
||||
# Validate the text path replacement
|
||||
old_dir = '/home/spack/opt/spack'
|
||||
filename = 'dummy.txt'
|
||||
with open(filename, "w") as script:
|
||||
script.write(old_dir)
|
||||
script.close()
|
||||
|
||||
filenames = [filename]
|
||||
new_dir = '/opt/rh/devtoolset/'
|
||||
relocate_text(filenames, old_dir, new_dir)
|
||||
|
||||
with open(filename, "r")as script:
|
||||
for line in script:
|
||||
assert(new_dir in line)
|
||||
|
||||
|
||||
def test_needs_relocation():
|
||||
binary_type = (
|
||||
'ELF 64-bit LSB executable, x86-64, version 1 (SYSV),'
|
||||
' dynamically linked (uses shared libs),'
|
||||
' for GNU/Linux x.y.z, stripped')
|
||||
|
||||
assert needs_binary_relocation(binary_type, os_id='Linux')
|
||||
assert not needs_binary_relocation('relocatable',
|
||||
os_id='Linux')
|
||||
assert not needs_binary_relocation('symbolic link to `foo\'',
|
||||
os_id='Linux')
|
||||
|
||||
assert needs_text_relocation('ASCII text')
|
||||
assert not needs_text_relocation('symbolic link to `foo.text\'')
|
||||
|
||||
macho_type = 'Mach-O 64-bit executable x86_64'
|
||||
assert needs_binary_relocation(macho_type, os_id='Darwin')
|
||||
|
||||
|
||||
def test_macho_paths():
|
||||
|
||||
out = macho_make_paths_relative('/Users/Shares/spack/pkgC/lib/libC.dylib',
|
||||
'/Users/Shared/spack',
|
||||
@@ -289,6 +322,8 @@ def test_relocate():
|
||||
'/usr/local/lib/libloco.dylib'],
|
||||
None)
|
||||
|
||||
|
||||
def test_elf_paths():
|
||||
out = get_relative_rpaths(
|
||||
'/usr/bin/test', '/usr',
|
||||
('/usr/lib', '/usr/lib64', '/opt/local/lib'))
|
||||
@@ -303,8 +338,8 @@ def test_relocate():
|
||||
reason="only works with Mach-o objects")
|
||||
def test_relocate_macho(tmpdir):
|
||||
with tmpdir.as_cwd():
|
||||
get_patchelf()
|
||||
assert (needs_binary_relocation('Mach-O'))
|
||||
|
||||
get_patchelf() # this does nothing on Darwin
|
||||
|
||||
rpaths, deps, idpath = macho_get_paths('/bin/bash')
|
||||
nrpaths, ndeps, nid = macho_make_paths_relative('/bin/bash', '/usr',
|
||||
@@ -341,9 +376,3 @@ def test_relocate_macho(tmpdir):
|
||||
'libncurses.5.4.dylib',
|
||||
rpaths, deps, idpath,
|
||||
nrpaths, ndeps, nid)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform != 'linux2',
|
||||
reason="only works with Elf objects")
|
||||
def test_relocate_elf():
|
||||
assert (needs_binary_relocation('ELF'))
|
||||
|
@@ -54,6 +54,13 @@ class Parmetis(Package):
|
||||
# https://bitbucket.org/petsc/pkg-parmetis/commits/82409d68aa1d6cbc70740d0f35024aae17f7d5cb/raw/ # NOQA: E501
|
||||
patch('pkg-parmetis-82409d68aa1d6cbc70740d0f35024aae17f7d5cb.patch')
|
||||
|
||||
def flag_handler(self, name, flags):
|
||||
if name == 'cflags':
|
||||
if '%pgi' in self.spec:
|
||||
my_flags = flags + ['-c11']
|
||||
return (None, None, my_flags)
|
||||
return (None, None, flags)
|
||||
|
||||
def url_for_version(self, version):
|
||||
url = 'http://glaros.dtc.umn.edu/gkhome/fetch/sw/parmetis'
|
||||
if version < Version('3.2.0'):
|
||||
@@ -70,9 +77,7 @@ def install(self, spec, prefix):
|
||||
'-DGKLIB_PATH:PATH=%s/GKlib' % spec['metis'].prefix.include,
|
||||
'-DMETIS_PATH:PATH=%s' % spec['metis'].prefix,
|
||||
'-DCMAKE_C_COMPILER:STRING=%s' % spec['mpi'].mpicc,
|
||||
'-DCMAKE_CXX_COMPILER:STRING=%s' % spec['mpi'].mpicxx,
|
||||
'-DCMAKE_C_FLAGS:STRING=%s' % (
|
||||
'-c11' if '%pgi' in spec else ''),
|
||||
'-DCMAKE_CXX_COMPILER:STRING=%s' % spec['mpi'].mpicxx
|
||||
])
|
||||
|
||||
if '+shared' in spec:
|
||||
|
@@ -32,6 +32,6 @@ class RDbi(RPackage):
|
||||
|
||||
homepage = "http://rstats-db.github.io/DBI"
|
||||
url = "https://cran.rstudio.com/src/contrib/DBI_0.7.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/DBI"
|
||||
version('0.4-1', 'c7ee8f1c5037c2284e99c62698d0f087')
|
||||
version('0.7', '66065dd687d758b72d638adb6a8cab2e')
|
||||
|
@@ -36,7 +36,7 @@ class RDorng(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/doRNG/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/doRNG_1.6.6.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/doRNG"
|
||||
|
||||
version('1.6.6', 'ffb26024c58c8c99229470293fbf35cf')
|
||||
|
||||
|
@@ -35,7 +35,7 @@ class RDownloader(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/downloader/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/downloader_0.4.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/downloader"
|
||||
|
||||
version('0.4', 'f26daf8fbeb29a1882bf102f62008594')
|
||||
|
||||
|
@@ -31,7 +31,7 @@ class RDplyr(RPackage):
|
||||
|
||||
homepage = "https://github.com/hadley/dplyr"
|
||||
url = "https://cran.rstudio.com/src/contrib/dplyr_0.7.3.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/dplyr"
|
||||
|
||||
version('0.7.3', 'f9760b796917747e9dcd927ebb531c7d')
|
||||
version('0.5.0', '1fcafcacca70806eea2e6d465cdb94ef')
|
||||
|
@@ -32,7 +32,7 @@ class RFutileLogger(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/futile.logger/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/futile.logger_1.4.3.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/futile.logger"
|
||||
|
||||
version('1.4.3', 'ba0e8d2dfb5a970b51c21907bbf8bfc2')
|
||||
|
||||
|
@@ -33,7 +33,7 @@ class RGetoptlong(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/GetoptLong/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/GetoptLong_0.1.6.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/GetoptLong"
|
||||
|
||||
version('0.1.6', 'e4b964d0817cb6c6a707297b21405749')
|
||||
|
||||
|
@@ -32,7 +32,7 @@ class RGgvis(RPackage):
|
||||
|
||||
homepage = "http://ggvis.rstudio.com/"
|
||||
url = "https://cran.rstudio.com/src/contrib/ggvis_0.4.3.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/ggvis"
|
||||
|
||||
version('0.4.3', '30297d464278a7974fb125bcc7d84e77')
|
||||
version('0.4.2', '039f45e5c7f1e0652779163d7d99f922')
|
||||
|
@@ -35,7 +35,7 @@ class RGlmnet(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/glmnet/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/glmnet_2.0-13.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/glmnet"
|
||||
version('2.0-13', '1dd5636388df5c3a29207d0bf1253343')
|
||||
version('2.0-5', '049b18caa29529614cd684db3beaec2a')
|
||||
|
||||
|
@@ -31,5 +31,6 @@ class RHms(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/hms/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/hms_0.3.tar.gz"
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/hms"
|
||||
|
||||
version('0.3', '92c4a0cf0c402a35145b5bb57212873e')
|
||||
|
@@ -30,7 +30,7 @@ class RHtmltools(RPackage):
|
||||
|
||||
homepage = "https://github.com/rstudio/htmltools"
|
||||
url = "https://cran.rstudio.com/src/contrib/htmltools_0.3.6.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/htmltools"
|
||||
|
||||
version('0.3.6', '336419c2143f958862e01ef1bbc9c253')
|
||||
version('0.3.5', '5f001aff4a39e329f7342dcec5139724')
|
||||
|
@@ -36,7 +36,7 @@ class RHttpuv(RPackage):
|
||||
|
||||
homepage = "https://github.com/rstudio/httpuv"
|
||||
url = "https://cran.rstudio.com/src/contrib/httpuv_1.3.5.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/httpuv"
|
||||
|
||||
version('1.3.5', '48d894ff0067148f41a651634fbb2012')
|
||||
version('1.3.3', 'c78ae068cf59e949b9791be987bb4489')
|
||||
|
@@ -31,5 +31,5 @@ class RHwriter(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/hwriter/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/hwriter_1.3.2.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/hwriter"
|
||||
version('1.3.2', '9eef49df2eb68bbf3a16b5860d933517')
|
||||
|
@@ -39,7 +39,7 @@ class RJsonlite(RPackage):
|
||||
|
||||
homepage = "https://github.com/jeroenooms/jsonlite"
|
||||
url = "https://cran.rstudio.com/src/contrib/jsonlite_1.5.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/jsonlite"
|
||||
|
||||
version('1.5', '2a81c261a702fccbbd5d2b32df108f76')
|
||||
version('1.2', '80cd2678ae77254be470f5931db71c51')
|
||||
|
@@ -33,7 +33,7 @@ class RLattice(RPackage):
|
||||
|
||||
homepage = "http://lattice.r-forge.r-project.org/"
|
||||
url = "https://cran.rstudio.com/src/contrib/lattice_0.20-35.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/lattice"
|
||||
|
||||
version('0.20-35', '07f1814623b3da6278ca61554ff7bfe6')
|
||||
version('0.20-34', 'c2a648b22d4206ae7526fb70b8e90fed')
|
||||
|
@@ -30,7 +30,7 @@ class RLocfit(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/locfit/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/locfit_1.5-9.1.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/locfit"
|
||||
|
||||
version('1.5-9.1', '38af7791c9cda78e2804020e65ac7fb4')
|
||||
|
||||
|
@@ -31,7 +31,7 @@ class RMatrix(RPackage):
|
||||
|
||||
homepage = "http://matrix.r-forge.r-project.org/"
|
||||
url = "https://cran.rstudio.com/src/contrib/Matrix_1.2-11.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/Matrix"
|
||||
version('1.2-11', 'a8c1a893f36d7ea918ddbf8cb8d10b43')
|
||||
version('1.2-8', '4a6406666bf97d3ec6b698eea5d9c0f5')
|
||||
version('1.2-6', 'f545307fb1284861e9266c4e9712c55e')
|
||||
|
@@ -35,6 +35,6 @@ class RMatrixstats(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/matrixStats/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/matrixStats_0.52.2.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/matrixStats"
|
||||
|
||||
version('0.52.2', '41b987d3ae96ee6895875c413adcba3c')
|
||||
|
@@ -31,7 +31,7 @@ class RMemoise(RPackage):
|
||||
|
||||
homepage = "https://github.com/hadley/memoise"
|
||||
url = "https://cran.rstudio.com/src/contrib/memoise_1.1.0.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/memoise"
|
||||
version('1.1.0', '493209ee04673f0fcab473c3dd80fb8c')
|
||||
version('1.0.0', 'd31145292e2a88ae9a504cab1602e4ac')
|
||||
|
||||
|
@@ -32,7 +32,7 @@ class RMpm(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/mpm/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/mpm_1.0-22.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/mpm"
|
||||
version('1.0-22', '91885c421cafd89ce8893ccf827165a2')
|
||||
|
||||
depends_on('r-kernsmooth', type=('build', 'run'))
|
||||
|
@@ -34,6 +34,6 @@ class RNor1mix(RPackage):
|
||||
|
||||
homepage = "https://CRAN.R-project.org/package=nor1mix"
|
||||
url = "https://cran.rstudio.com/src/contrib/nor1mix_1.2-3.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/nor1mix"
|
||||
|
||||
version('1.2-3', '60eb5cc1ea6b366f53042087a080b105')
|
||||
|
@@ -32,5 +32,5 @@ class RPkgconfig(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/pkgconfig/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/pkgconfig_2.0.1.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/pkgconfig"
|
||||
version('2.0.1', 'a20fd9588e37995995fa62dc4828002e')
|
||||
|
@@ -35,7 +35,7 @@ class RR6(RPackage):
|
||||
|
||||
homepage = "https://github.com/wch/R6/"
|
||||
url = "https://cran.rstudio.com/src/contrib/R6_2.2.2.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/R6"
|
||||
|
||||
version('2.2.2', '635b58c65bff624a1fab69c6b1989801')
|
||||
version('2.2.0', '659d83b2d3f7a308a48332b4cfbdab49')
|
||||
|
@@ -38,8 +38,9 @@ class RRcpp(RPackage):
|
||||
|
||||
homepage = "http://dirk.eddelbuettel.com/code/rcpp.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/Rcpp_0.12.13.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.rstudio.com/src/contrib/Archive/Rcpp"
|
||||
|
||||
version('0.12.14', '89a3dbad0aa3e345b9d0b862fa1fc56a')
|
||||
version('0.12.13', '5186d119132bfe07f66da74c50b190a4')
|
||||
version('0.12.12', '97b36a3b567e3438067c4a7d0075fd90')
|
||||
version('0.12.11', 'ea1710213cbb1d91b1d0318e6fa9aa37')
|
||||
|
@@ -22,21 +22,6 @@
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
#
|
||||
# This is a template package file for Spack. We've put "FIXME"
|
||||
# next to all the things you'll want to change. Once you've handled
|
||||
# them, you can save this file and test your package like this:
|
||||
#
|
||||
# spack install r-rcurl
|
||||
#
|
||||
# You can edit this file again by typing:
|
||||
#
|
||||
# spack edit r-rcurl
|
||||
#
|
||||
# See the Spack documentation for more information on packaging.
|
||||
# If you submit this package back to Spack as a pull request,
|
||||
# please first remove this boilerplate and all FIXME comments.
|
||||
#
|
||||
from spack import *
|
||||
|
||||
|
||||
@@ -54,7 +39,7 @@ class RRcurl(RPackage):
|
||||
|
||||
homepage = "https://cran.rstudio.com/web/packages/RCurl/index.html"
|
||||
url = "https://cran.rstudio.com/src/contrib/RCurl_1.95-4.8.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/RCurl"
|
||||
|
||||
version('1.95-4.8', '9c8aaff986eb2792c89dd3ae54d21580')
|
||||
|
||||
|
@@ -33,7 +33,7 @@ class RShiny(RPackage):
|
||||
|
||||
homepage = "http://shiny.rstudio.com/"
|
||||
url = "https://cran.rstudio.com/src/contrib/shiny_1.0.5.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/shiny"
|
||||
|
||||
version('1.0.5', '419dd5d3ea0bd87a07f8f0b1ef14fc13')
|
||||
version('0.13.2', 'cb5bff7a28ad59ec2883cd0912ca9611')
|
||||
|
@@ -31,7 +31,7 @@ class RTibble(RPackage):
|
||||
|
||||
homepage = "https://github.com/tidyverse/tibble"
|
||||
url = "https://cran.rstudio.com/src/contrib/tibble_1.3.4.tar.gz"
|
||||
list_url = homepage
|
||||
list_url = "https://cran.r-project.org/src/contrib/Archive/tibble"
|
||||
version('1.3.4', '298e81546f999fb0968625698511b8d3')
|
||||
version('1.2', 'bdbc3d67aa16860741add6d6ec20ea13')
|
||||
version('1.1', '2fe9f806109d0b7fadafb1ffafea4cb8')
|
||||
|
Reference in New Issue
Block a user