Merge pull request #1186 from epfl-scitas/features/install_with_phases
do_install : allow for an arbitrary number of phases
This commit is contained in:
@@ -24,11 +24,11 @@
|
|||||||
##############################################################################
|
##############################################################################
|
||||||
"""Utility classes for logging the output of blocks of code.
|
"""Utility classes for logging the output of blocks of code.
|
||||||
"""
|
"""
|
||||||
import sys
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import select
|
import select
|
||||||
import inspect
|
import sys
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
import llnl.util.tty.color as color
|
import llnl.util.tty.color as color
|
||||||
@@ -100,25 +100,29 @@ def __exit__(self, exc_type, exception, traceback):
|
|||||||
|
|
||||||
|
|
||||||
class log_output(object):
|
class log_output(object):
|
||||||
"""Redirects output and error of enclosed block to a file.
|
"""Spawns a daemon that reads from a pipe and writes to a file
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
with log_output(open('logfile.txt', 'w')):
|
# Spawns the daemon
|
||||||
# do things ... output will be logged.
|
with log_output('logfile.txt', 'w') as log_redirection:
|
||||||
|
# do things ... output is not redirected
|
||||||
|
with log_redirection:
|
||||||
|
# do things ... output will be logged
|
||||||
|
|
||||||
or:
|
or:
|
||||||
with log_output(open('logfile.txt', 'w'), echo=True):
|
with log_output('logfile.txt', echo=True) as log_redirection:
|
||||||
# do things ... output will be logged
|
# do things ... output is not redirected
|
||||||
# and also printed to stdout.
|
with log_redirection:
|
||||||
|
# do things ... output will be logged
|
||||||
|
# and also printed to stdout.
|
||||||
|
|
||||||
Closes the provided stream when done with the block.
|
Opens a stream in 'w' mode at daemon spawning and closes it at
|
||||||
If echo is True, also prints the output to stdout.
|
daemon joining. If echo is True, also prints the output to stdout.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, stream, echo=False, force_color=False, debug=False):
|
def __init__(self, filename, echo=False, force_color=False, debug=False):
|
||||||
self.stream = stream
|
self.filename = filename
|
||||||
|
# Various output options
|
||||||
# various output options
|
|
||||||
self.echo = echo
|
self.echo = echo
|
||||||
self.force_color = force_color
|
self.force_color = force_color
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
@@ -126,70 +130,81 @@ def __init__(self, stream, echo=False, force_color=False, debug=False):
|
|||||||
# Default is to try file-descriptor reassignment unless the system
|
# Default is to try file-descriptor reassignment unless the system
|
||||||
# out/err streams do not have an associated file descriptor
|
# out/err streams do not have an associated file descriptor
|
||||||
self.directAssignment = False
|
self.directAssignment = False
|
||||||
|
self.read, self.write = os.pipe()
|
||||||
|
|
||||||
def trace(self, frame, event, arg):
|
# Sets a daemon that writes to file what it reads from a pipe
|
||||||
"""Jumps to __exit__ on the child process."""
|
self.p = multiprocessing.Process(
|
||||||
raise _SkipWithBlock()
|
target=self._spawn_writing_daemon,
|
||||||
|
args=(self.read,),
|
||||||
|
name='logger_daemon'
|
||||||
|
)
|
||||||
|
self.p.daemon = True
|
||||||
|
# Needed to un-summon the daemon
|
||||||
|
self.parent_pipe, self.child_pipe = multiprocessing.Pipe()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
"""Redirect output from the with block to a file.
|
self.p.start()
|
||||||
|
return log_output.OutputRedirection(self)
|
||||||
|
|
||||||
This forks the with block as a separate process, with stdout
|
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||||
and stderr redirected back to the parent via a pipe. If
|
self.parent_pipe.send(True)
|
||||||
echo is set, also writes to standard out.
|
self.p.join(60.0) # 1 minute to join the child
|
||||||
|
|
||||||
"""
|
def _spawn_writing_daemon(self, read):
|
||||||
# remember these values for later.
|
# Parent: read from child, skip the with block.
|
||||||
self._force_color = color._force_color
|
read_file = os.fdopen(read, 'r', 0)
|
||||||
self._debug = tty._debug
|
with open(self.filename, 'w') as log_file:
|
||||||
|
with keyboard_input(sys.stdin):
|
||||||
|
while True:
|
||||||
|
rlist, _, _ = select.select([read_file, sys.stdin], [], [])
|
||||||
|
if not rlist:
|
||||||
|
break
|
||||||
|
|
||||||
read, write = os.pipe()
|
# Allow user to toggle echo with 'v' key.
|
||||||
|
# Currently ignores other chars.
|
||||||
|
if sys.stdin in rlist:
|
||||||
|
if sys.stdin.read(1) == 'v':
|
||||||
|
self.echo = not self.echo
|
||||||
|
|
||||||
self.pid = os.fork()
|
# Handle output from the with block process.
|
||||||
if self.pid:
|
if read_file in rlist:
|
||||||
# Parent: read from child, skip the with block.
|
line = read_file.readline()
|
||||||
os.close(write)
|
if not line:
|
||||||
|
# For some reason we never reach this point...
|
||||||
read_file = os.fdopen(read, 'r', 0)
|
|
||||||
with self.stream as log_file:
|
|
||||||
with keyboard_input(sys.stdin):
|
|
||||||
while True:
|
|
||||||
rlist, w, x = select.select(
|
|
||||||
[read_file, sys.stdin], [], [])
|
|
||||||
if not rlist:
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# Allow user to toggle echo with 'v' key.
|
# Echo to stdout if requested.
|
||||||
# Currently ignores other chars.
|
if self.echo:
|
||||||
if sys.stdin in rlist:
|
sys.stdout.write(line)
|
||||||
if sys.stdin.read(1) == 'v':
|
|
||||||
self.echo = not self.echo
|
|
||||||
|
|
||||||
# handle output from the with block process.
|
# Stripped output to log file.
|
||||||
if read_file in rlist:
|
log_file.write(_strip(line))
|
||||||
line = read_file.readline()
|
log_file.flush()
|
||||||
if not line:
|
|
||||||
break
|
|
||||||
|
|
||||||
# Echo to stdout if requested.
|
if self.child_pipe.poll():
|
||||||
if self.echo:
|
break
|
||||||
sys.stdout.write(line)
|
|
||||||
|
|
||||||
# Stripped output to log file.
|
def __del__(self):
|
||||||
log_file.write(_strip(line))
|
"""Closes the pipes"""
|
||||||
|
os.close(self.write)
|
||||||
|
os.close(self.read)
|
||||||
|
|
||||||
read_file.flush()
|
class OutputRedirection(object):
|
||||||
read_file.close()
|
|
||||||
|
|
||||||
# Set a trace function to skip the with block.
|
def __init__(self, other):
|
||||||
sys.settrace(lambda *args, **keys: None)
|
self.__dict__.update(other.__dict__)
|
||||||
frame = inspect.currentframe(1)
|
|
||||||
frame.f_trace = self.trace
|
|
||||||
|
|
||||||
else:
|
def __enter__(self):
|
||||||
# Child: redirect output, execute the with block.
|
"""Redirect output from the with block to a file.
|
||||||
os.close(read)
|
|
||||||
|
|
||||||
|
Hijacks stdout / stderr and writes to the pipe
|
||||||
|
connected to the logger daemon
|
||||||
|
"""
|
||||||
|
# remember these values for later.
|
||||||
|
self._force_color = color._force_color
|
||||||
|
self._debug = tty._debug
|
||||||
|
# Redirect this output to a pipe
|
||||||
|
write = self.write
|
||||||
try:
|
try:
|
||||||
# Save old stdout and stderr
|
# Save old stdout and stderr
|
||||||
self._stdout = os.dup(sys.stdout.fileno())
|
self._stdout = os.dup(sys.stdout.fileno())
|
||||||
@@ -205,53 +220,26 @@ def __enter__(self):
|
|||||||
output_redirect = os.fdopen(write, 'w')
|
output_redirect = os.fdopen(write, 'w')
|
||||||
sys.stdout = output_redirect
|
sys.stdout = output_redirect
|
||||||
sys.stderr = output_redirect
|
sys.stderr = output_redirect
|
||||||
|
|
||||||
if self.force_color:
|
if self.force_color:
|
||||||
color._force_color = True
|
color._force_color = True
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
tty._debug = True
|
tty._debug = True
|
||||||
|
|
||||||
def __exit__(self, exc_type, exception, traceback):
|
def __exit__(self, exc_type, exception, traceback):
|
||||||
"""Exits on child, handles skipping the with block on parent."""
|
"""Plugs back the original file descriptors
|
||||||
# Child should just exit here.
|
for stdout and stderr
|
||||||
if self.pid == 0:
|
"""
|
||||||
# Flush the log to disk.
|
# Flush the log to disk.
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
sys.stderr.flush()
|
sys.stderr.flush()
|
||||||
|
if self.directAssignment:
|
||||||
if exception:
|
# We seem to need this only to pass test/install.py
|
||||||
# Restore stdout on the child if there's an exception,
|
sys.stdout = self._stdout
|
||||||
# and let it be raised normally.
|
sys.stderr = self._stderr
|
||||||
#
|
|
||||||
# This assumes that even if the exception is caught,
|
|
||||||
# the child will exit with a nonzero return code. If
|
|
||||||
# it doesn't, the child process will continue running.
|
|
||||||
#
|
|
||||||
# TODO: think about how this works outside install.
|
|
||||||
# TODO: ideally would propagate exception to parent...
|
|
||||||
if self.directAssignment:
|
|
||||||
sys.stdout = self._stdout
|
|
||||||
sys.stderr = self._stderr
|
|
||||||
else:
|
|
||||||
os.dup2(self._stdout, sys.stdout.fileno())
|
|
||||||
os.dup2(self._stderr, sys.stderr.fileno())
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Die quietly if there was no exception.
|
os.dup2(self._stdout, sys.stdout.fileno())
|
||||||
os._exit(0)
|
os.dup2(self._stderr, sys.stderr.fileno())
|
||||||
|
|
||||||
else:
|
# restore output options.
|
||||||
# If the child exited badly, parent also should exit.
|
color._force_color = self._force_color
|
||||||
pid, returncode = os.waitpid(self.pid, 0)
|
tty._debug = self._debug
|
||||||
if returncode != 0:
|
|
||||||
os._exit(1)
|
|
||||||
|
|
||||||
# restore output options.
|
|
||||||
color._force_color = self._force_color
|
|
||||||
tty._debug = self._debug
|
|
||||||
|
|
||||||
# Suppresses exception if it's our own.
|
|
||||||
return exc_type is _SkipWithBlock
|
|
||||||
|
@@ -186,10 +186,19 @@
|
|||||||
# packages should live. This file is overloaded for spack core vs.
|
# packages should live. This file is overloaded for spack core vs.
|
||||||
# for packages.
|
# for packages.
|
||||||
#
|
#
|
||||||
__all__ = ['Package', 'StagedPackage', 'CMakePackage',
|
__all__ = ['Package',
|
||||||
'Version', 'when', 'ver', 'alldeps', 'nolink']
|
'CMakePackage',
|
||||||
|
'AutotoolsPackage',
|
||||||
|
'MakefilePackage',
|
||||||
|
'Version',
|
||||||
|
'when',
|
||||||
|
'ver',
|
||||||
|
'alldeps',
|
||||||
|
'nolink']
|
||||||
from spack.package import Package, ExtensionConflictError
|
from spack.package import Package, ExtensionConflictError
|
||||||
from spack.package import StagedPackage, CMakePackage
|
from spack.build_systems.makefile import MakefilePackage
|
||||||
|
from spack.build_systems.autotools import AutotoolsPackage
|
||||||
|
from spack.build_systems.cmake import CMakePackage
|
||||||
from spack.version import Version, ver
|
from spack.version import Version, ver
|
||||||
from spack.spec import DependencySpec, alldeps, nolink
|
from spack.spec import DependencySpec, alldeps, nolink
|
||||||
from spack.multimethod import when
|
from spack.multimethod import when
|
||||||
|
@@ -51,16 +51,14 @@
|
|||||||
Skimming this module is a nice way to get acquainted with the types of
|
Skimming this module is a nice way to get acquainted with the types of
|
||||||
calls you can make from within the install() function.
|
calls you can make from within the install() function.
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import shutil
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import platform
|
import os
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.filesystem import *
|
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
|
from llnl.util.filesystem import *
|
||||||
from spack.environment import EnvironmentModifications, validate
|
from spack.environment import EnvironmentModifications, validate
|
||||||
from spack.util.environment import *
|
from spack.util.environment import *
|
||||||
from spack.util.executable import Executable, which
|
from spack.util.executable import Executable, which
|
||||||
@@ -351,8 +349,8 @@ def set_module_variables_for_package(pkg, module):
|
|||||||
m.cmake = Executable('cmake')
|
m.cmake = Executable('cmake')
|
||||||
m.ctest = Executable('ctest')
|
m.ctest = Executable('ctest')
|
||||||
|
|
||||||
# standard CMake arguments
|
# Standard CMake arguments
|
||||||
m.std_cmake_args = get_std_cmake_args(pkg)
|
m.std_cmake_args = spack.CMakePackage._std_args(pkg)
|
||||||
|
|
||||||
# Put spack compiler paths in module scope.
|
# Put spack compiler paths in module scope.
|
||||||
link_dir = spack.build_env_path
|
link_dir = spack.build_env_path
|
||||||
@@ -522,41 +520,26 @@ def child_fun():
|
|||||||
carries on.
|
carries on.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
def child_execution(child_connection):
|
||||||
pid = os.fork()
|
|
||||||
except OSError as e:
|
|
||||||
raise InstallError("Unable to fork build process: %s" % e)
|
|
||||||
|
|
||||||
if pid == 0:
|
|
||||||
# Give the child process the package's build environment.
|
|
||||||
setup_package(pkg, dirty=dirty)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# call the forked function.
|
setup_package(pkg, dirty=dirty)
|
||||||
function()
|
function()
|
||||||
|
child_connection.send([None, None, None])
|
||||||
|
except Exception as e:
|
||||||
|
child_connection.send([type(e), e, None])
|
||||||
|
finally:
|
||||||
|
child_connection.close()
|
||||||
|
|
||||||
# Use os._exit here to avoid raising a SystemExit exception,
|
parent_connection, child_connection = multiprocessing.Pipe()
|
||||||
# which interferes with unit tests.
|
p = multiprocessing.Process(
|
||||||
os._exit(0)
|
target=child_execution,
|
||||||
|
args=(child_connection,)
|
||||||
except spack.error.SpackError as e:
|
)
|
||||||
e.die()
|
p.start()
|
||||||
|
exc_type, exception, traceback = parent_connection.recv()
|
||||||
except:
|
p.join()
|
||||||
# Child doesn't raise or return to main spack code.
|
if exception is not None:
|
||||||
# Just runs default exception handler and exits.
|
raise exception
|
||||||
sys.excepthook(*sys.exc_info())
|
|
||||||
os._exit(1)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# Parent process just waits for the child to complete. If the
|
|
||||||
# child exited badly, assume it already printed an appropriate
|
|
||||||
# message. Just make the parent exit with an error code.
|
|
||||||
pid, returncode = os.waitpid(pid, 0)
|
|
||||||
if returncode != 0:
|
|
||||||
message = "Installation process had nonzero exit code : {code}"
|
|
||||||
strcode = str(returncode)
|
|
||||||
raise InstallError(message.format(code=strcode))
|
|
||||||
|
|
||||||
|
|
||||||
class InstallError(spack.error.SpackError):
|
class InstallError(spack.error.SpackError):
|
||||||
|
0
lib/spack/spack/build_systems/__init__.py
Normal file
0
lib/spack/spack/build_systems/__init__.py
Normal file
106
lib/spack/spack/build_systems/autotools.py
Normal file
106
lib/spack/spack/build_systems/autotools.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2016, 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 LICENSE file 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.path
|
||||||
|
|
||||||
|
import llnl.util.tty as tty
|
||||||
|
from spack.package import PackageBase
|
||||||
|
|
||||||
|
|
||||||
|
class AutotoolsPackage(PackageBase):
|
||||||
|
"""Specialized class for packages that are built using GNU Autotools
|
||||||
|
|
||||||
|
This class provides four phases that can be overridden:
|
||||||
|
- autoreconf
|
||||||
|
- configure
|
||||||
|
- build
|
||||||
|
- install
|
||||||
|
|
||||||
|
They all have sensible defaults and for many packages the only thing
|
||||||
|
necessary will be to override `configure_args`
|
||||||
|
"""
|
||||||
|
phases = ['autoreconf', 'configure', 'build', 'install']
|
||||||
|
# To be used in UI queries that require to know which
|
||||||
|
# build-system class we are using
|
||||||
|
build_system_class = 'AutotoolsPackage'
|
||||||
|
|
||||||
|
def autoreconf(self, spec, prefix):
|
||||||
|
"""Not needed usually, configure should be already there"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@PackageBase.sanity_check('autoreconf')
|
||||||
|
def is_configure_or_die(self):
|
||||||
|
"""Checks the presence of a `configure` file after the
|
||||||
|
autoreconf phase"""
|
||||||
|
if not os.path.exists('configure'):
|
||||||
|
raise RuntimeError(
|
||||||
|
'configure script not found in {0}'.format(os.getcwd()))
|
||||||
|
|
||||||
|
def configure_args(self):
|
||||||
|
"""Method to be overridden. Should return an iterable containing
|
||||||
|
all the arguments that must be passed to configure, except --prefix
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def configure(self, spec, prefix):
|
||||||
|
"""Runs configure with the arguments specified in `configure_args`
|
||||||
|
and an appropriately set prefix
|
||||||
|
"""
|
||||||
|
options = ['--prefix={0}'.format(prefix)] + self.configure_args()
|
||||||
|
inspect.getmodule(self).configure(*options)
|
||||||
|
|
||||||
|
def build(self, spec, prefix):
|
||||||
|
"""The usual `make` after configure"""
|
||||||
|
inspect.getmodule(self).make()
|
||||||
|
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
"""...and the final `make install` after configure"""
|
||||||
|
inspect.getmodule(self).make('install')
|
||||||
|
|
||||||
|
@PackageBase.sanity_check('build')
|
||||||
|
@PackageBase.on_package_attributes(run_tests=True)
|
||||||
|
def _run_default_function(self):
|
||||||
|
"""This function is run after build if self.run_tests == True
|
||||||
|
|
||||||
|
It will search for a method named `check` and run it. A sensible
|
||||||
|
default is provided in the base class.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
fn = getattr(self, 'check')
|
||||||
|
tty.msg('Trying default sanity checks [check]')
|
||||||
|
fn()
|
||||||
|
except AttributeError:
|
||||||
|
tty.msg('Skipping default sanity checks [method `check` not implemented]') # NOQA: ignore=E501
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
"""Default test : search the Makefile for targets `test` and `check`
|
||||||
|
and run them if found.
|
||||||
|
"""
|
||||||
|
self._if_make_target_execute('test')
|
||||||
|
self._if_make_target_execute('check')
|
||||||
|
|
||||||
|
# Check that self.prefix is there after installation
|
||||||
|
PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
|
143
lib/spack/spack/build_systems/cmake.py
Normal file
143
lib/spack/spack/build_systems/cmake.py
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2016, 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 LICENSE file 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 llnl.util.tty as tty
|
||||||
|
import spack.build_environment
|
||||||
|
from llnl.util.filesystem import working_dir, join_path
|
||||||
|
from spack.package import PackageBase
|
||||||
|
|
||||||
|
|
||||||
|
class CMakePackage(PackageBase):
|
||||||
|
"""Specialized class for packages that are built using cmake
|
||||||
|
|
||||||
|
This class provides three phases that can be overridden:
|
||||||
|
- cmake
|
||||||
|
- build
|
||||||
|
- install
|
||||||
|
|
||||||
|
They all have sensible defaults and for many packages the only thing
|
||||||
|
necessary will be to override `cmake_args`
|
||||||
|
"""
|
||||||
|
phases = ['cmake', 'build', 'install']
|
||||||
|
# To be used in UI queries that require to know which
|
||||||
|
# build-system class we are using
|
||||||
|
build_system_class = 'CMakePackage'
|
||||||
|
|
||||||
|
def build_type(self):
|
||||||
|
"""Override to provide the correct build_type in case a complex
|
||||||
|
logic is needed
|
||||||
|
"""
|
||||||
|
return 'RelWithDebInfo'
|
||||||
|
|
||||||
|
def root_cmakelists_dir(self):
|
||||||
|
"""Directory where to find the root 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
|
||||||
|
"""
|
||||||
|
# standard CMake arguments
|
||||||
|
return CMakePackage._std_args(self)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _std_args(pkg):
|
||||||
|
"""Computes the standard cmake arguments for a generic package"""
|
||||||
|
try:
|
||||||
|
build_type = pkg.build_type()
|
||||||
|
except AttributeError:
|
||||||
|
build_type = 'RelWithDebInfo'
|
||||||
|
|
||||||
|
args = ['-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))
|
||||||
|
return args
|
||||||
|
|
||||||
|
def build_directory(self):
|
||||||
|
"""Override to provide another place to build the package"""
|
||||||
|
return join_path(self.stage.source_path, 'spack-build')
|
||||||
|
|
||||||
|
def cmake_args(self):
|
||||||
|
"""Method to be overridden. Should return an iterable containing
|
||||||
|
all the arguments that must be passed to configure, except:
|
||||||
|
- CMAKE_INSTALL_PREFIX
|
||||||
|
- CMAKE_BUILD_TYPE
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def cmake(self, spec, prefix):
|
||||||
|
"""Run cmake in the build directory"""
|
||||||
|
options = [self.root_cmakelists_dir()] + self.std_cmake_args + \
|
||||||
|
self.cmake_args()
|
||||||
|
create = not os.path.exists(self.build_directory())
|
||||||
|
with working_dir(self.build_directory(), create=create):
|
||||||
|
inspect.getmodule(self).cmake(*options)
|
||||||
|
|
||||||
|
def build(self, spec, prefix):
|
||||||
|
"""The usual `make` after cmake"""
|
||||||
|
with working_dir(self.build_directory()):
|
||||||
|
inspect.getmodule(self).make()
|
||||||
|
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
"""...and the final `make install` after cmake"""
|
||||||
|
with working_dir(self.build_directory()):
|
||||||
|
inspect.getmodule(self).make('install')
|
||||||
|
|
||||||
|
@PackageBase.sanity_check('build')
|
||||||
|
@PackageBase.on_package_attributes(run_tests=True)
|
||||||
|
def _run_default_function(self):
|
||||||
|
"""This function is run after build if self.run_tests == True
|
||||||
|
|
||||||
|
It will search for a method named `check` and run it. A sensible
|
||||||
|
default is provided in the base class.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
fn = getattr(self, 'check')
|
||||||
|
tty.msg('Trying default build sanity checks [check]')
|
||||||
|
fn()
|
||||||
|
except AttributeError:
|
||||||
|
tty.msg('Skipping default build sanity checks [method `check` not implemented]') # NOQA: ignore=E501
|
||||||
|
|
||||||
|
def check(self):
|
||||||
|
"""Default test : search the Makefile for the target `test`
|
||||||
|
and run them if found.
|
||||||
|
"""
|
||||||
|
with working_dir(self.build_directory()):
|
||||||
|
self._if_make_target_execute('test')
|
||||||
|
|
||||||
|
# Check that self.prefix is there after installation
|
||||||
|
PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
|
77
lib/spack/spack/build_systems/makefile.py
Normal file
77
lib/spack/spack/build_systems/makefile.py
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2016, 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 LICENSE file 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
|
||||||
|
|
||||||
|
from llnl.util.filesystem import working_dir
|
||||||
|
from spack.package import PackageBase
|
||||||
|
|
||||||
|
|
||||||
|
class MakefilePackage(PackageBase):
|
||||||
|
"""Specialized class for packages that are built using editable Makefiles
|
||||||
|
|
||||||
|
This class provides three phases that can be overridden:
|
||||||
|
- edit
|
||||||
|
- build
|
||||||
|
- install
|
||||||
|
|
||||||
|
It is necessary to override the 'edit' phase, while 'build' and 'install'
|
||||||
|
have sensible defaults.
|
||||||
|
"""
|
||||||
|
phases = ['edit', 'build', 'install']
|
||||||
|
# To be used in UI queries that require to know which
|
||||||
|
# build-system class we are using
|
||||||
|
build_system_class = 'MakefilePackage'
|
||||||
|
|
||||||
|
def build_directory(self):
|
||||||
|
"""Directory where the main Makefile is located"""
|
||||||
|
return self.stage.source_path
|
||||||
|
|
||||||
|
def build_args(self):
|
||||||
|
"""List of arguments that should be passed to make at build time"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def install_args(self):
|
||||||
|
"""List of arguments that should be passed to make at install time"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def edit(self, spec, prefix):
|
||||||
|
"""This phase cannot be defaulted for obvious reasons..."""
|
||||||
|
raise NotImplementedError('\'edit\' function not implemented')
|
||||||
|
|
||||||
|
def build(self, spec, prefix):
|
||||||
|
"""Default build phase : call make passing build_args"""
|
||||||
|
args = self.build_args()
|
||||||
|
with working_dir(self.build_directory()):
|
||||||
|
inspect.getmodule(self).make(*args)
|
||||||
|
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
"""Default install phase : call make passing install_args"""
|
||||||
|
args = self.install_args() + ['install']
|
||||||
|
with working_dir(self.build_directory()):
|
||||||
|
inspect.getmodule(self).make(*args)
|
||||||
|
|
||||||
|
# Check that self.prefix is there after installation
|
||||||
|
PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
|
43
lib/spack/spack/cmd/build.py
Normal file
43
lib/spack/spack/cmd/build.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2016, 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 LICENSE file 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 spack.cmd.configure as cfg
|
||||||
|
|
||||||
|
from spack import *
|
||||||
|
|
||||||
|
description = 'Stops at build stage when installing a package, if possible'
|
||||||
|
|
||||||
|
build_system_to_phase = {
|
||||||
|
CMakePackage: 'build',
|
||||||
|
AutotoolsPackage: 'build'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def setup_parser(subparser):
|
||||||
|
cfg.setup_parser(subparser)
|
||||||
|
|
||||||
|
|
||||||
|
def build(parser, args):
|
||||||
|
cfg._stop_at_phase_during_install(args, build, build_system_to_phase)
|
90
lib/spack/spack/cmd/configure.py
Normal file
90
lib/spack/spack/cmd/configure.py
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
##############################################################################
|
||||||
|
# Copyright (c) 2013-2016, 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 LICENSE file 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 argparse
|
||||||
|
|
||||||
|
import llnl.util.tty as tty
|
||||||
|
import spack.cmd
|
||||||
|
import spack.cmd.install as inst
|
||||||
|
|
||||||
|
from spack import *
|
||||||
|
|
||||||
|
description = 'Stops at configuration stage when installing a package, if possible' # NOQA: ignore=E501
|
||||||
|
|
||||||
|
|
||||||
|
build_system_to_phase = {
|
||||||
|
CMakePackage: 'cmake',
|
||||||
|
AutotoolsPackage: 'configure'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def setup_parser(subparser):
|
||||||
|
subparser.add_argument(
|
||||||
|
'package',
|
||||||
|
nargs=argparse.REMAINDER,
|
||||||
|
help="spec of the package to install"
|
||||||
|
)
|
||||||
|
subparser.add_argument(
|
||||||
|
'-v', '--verbose',
|
||||||
|
action='store_true',
|
||||||
|
help="Print additional output during builds"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _stop_at_phase_during_install(args, calling_fn, phase_mapping):
|
||||||
|
if not args.package:
|
||||||
|
tty.die("configure requires at least one package argument")
|
||||||
|
|
||||||
|
# TODO: to be refactored with code in install
|
||||||
|
specs = spack.cmd.parse_specs(args.package, concretize=True)
|
||||||
|
if len(specs) != 1:
|
||||||
|
tty.error('only one spec can be installed at a time.')
|
||||||
|
spec = specs.pop()
|
||||||
|
pkg = spec.package
|
||||||
|
try:
|
||||||
|
key = [cls for cls in phase_mapping if isinstance(pkg, cls)].pop()
|
||||||
|
phase = phase_mapping[key]
|
||||||
|
# Install package dependencies if needed
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
inst.setup_parser(parser)
|
||||||
|
tty.msg('Checking dependencies for {0}'.format(args.package))
|
||||||
|
cli_args = ['-v'] if args.verbose else []
|
||||||
|
install_args = parser.parse_args(cli_args + ['--only=dependencies'])
|
||||||
|
install_args.package = args.package
|
||||||
|
inst.install(parser, install_args)
|
||||||
|
# Install package and stop at the given phase
|
||||||
|
cli_args = ['-v'] if args.verbose else []
|
||||||
|
install_args = parser.parse_args(cli_args + ['--only=package'])
|
||||||
|
install_args.package = args.package
|
||||||
|
inst.install(parser, install_args, stop_at=phase)
|
||||||
|
except IndexError:
|
||||||
|
tty.error(
|
||||||
|
'Package {0} has no {1} phase, or its {1} phase is not separated from install'.format( # NOQA: ignore=E501
|
||||||
|
spec.name, calling_fn.__name__)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def configure(parser, args):
|
||||||
|
_stop_at_phase_during_install(args, configure, build_system_to_phase)
|
@@ -22,25 +22,24 @@
|
|||||||
# License along with this program; if not, write to the Free Software
|
# License along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
import string
|
from __future__ import print_function
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import string
|
||||||
|
|
||||||
from ordereddict_backport import OrderedDict
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.filesystem import mkdirp
|
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
import spack.cmd.checksum
|
import spack.cmd.checksum
|
||||||
import spack.url
|
import spack.url
|
||||||
import spack.util.web
|
import spack.util.web
|
||||||
from spack.spec import Spec
|
from llnl.util.filesystem import mkdirp
|
||||||
from spack.util.naming import *
|
from ordereddict_backport import OrderedDict
|
||||||
from spack.repository import Repo, RepoError
|
from spack.repository import Repo, RepoError
|
||||||
|
from spack.spec import Spec
|
||||||
from spack.util.executable import which
|
from spack.util.executable import which
|
||||||
|
from spack.util.naming import *
|
||||||
|
|
||||||
description = "Create a new package file from an archive URL"
|
description = "Create a new package file from an archive URL"
|
||||||
|
|
||||||
@@ -87,7 +86,7 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class ${class_name}(Package):
|
class ${class_name}(${base_class_name}):
|
||||||
""\"FIXME: Put a proper description of your package here.""\"
|
""\"FIXME: Put a proper description of your package here.""\"
|
||||||
|
|
||||||
# FIXME: Add a proper url for your package's homepage here.
|
# FIXME: Add a proper url for your package's homepage here.
|
||||||
@@ -98,109 +97,160 @@ class ${class_name}(Package):
|
|||||||
|
|
||||||
${dependencies}
|
${dependencies}
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
${body}
|
||||||
${install}
|
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# Build dependencies and extensions
|
|
||||||
dependencies_dict = {
|
class DefaultGuess(object):
|
||||||
'autotools': """\
|
"""Provides the default values to be used for the package file template"""
|
||||||
|
base_class_name = 'Package'
|
||||||
|
|
||||||
|
dependencies = """\
|
||||||
# FIXME: Add dependencies if required.
|
# FIXME: Add dependencies if required.
|
||||||
# depends_on('foo')""",
|
# depends_on('foo')"""
|
||||||
|
|
||||||
'cmake': """\
|
body = """\
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
# FIXME: Unknown build system
|
||||||
|
make()
|
||||||
|
make('install')"""
|
||||||
|
|
||||||
|
def __init__(self, name, url, version_hash_tuples):
|
||||||
|
self.name = name
|
||||||
|
self.class_name = mod_to_class(name)
|
||||||
|
self.url = url
|
||||||
|
self.version_hash_tuples = version_hash_tuples
|
||||||
|
|
||||||
|
@property
|
||||||
|
def versions(self):
|
||||||
|
"""Adds a version() call to the package for each version found."""
|
||||||
|
max_len = max(len(str(v)) for v, h in self.version_hash_tuples)
|
||||||
|
format = " version(%%-%ds, '%%s')" % (max_len + 2)
|
||||||
|
return '\n'.join(
|
||||||
|
format % ("'%s'" % v, h) for v, h in self.version_hash_tuples
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class AutotoolsGuess(DefaultGuess):
|
||||||
|
"""Provides appropriate overrides for autotools-based packages"""
|
||||||
|
base_class_name = 'AutotoolsPackage'
|
||||||
|
|
||||||
|
dependencies = """\
|
||||||
|
# FIXME: Add dependencies if required.
|
||||||
|
# depends_on('m4', type='build')
|
||||||
|
# depends_on('autoconf', type='build')
|
||||||
|
# depends_on('automake', type='build')
|
||||||
|
# depends_on('libtool', type='build')
|
||||||
|
# depends_on('foo')"""
|
||||||
|
|
||||||
|
body = """\
|
||||||
|
def configure_args(self):
|
||||||
|
# FIXME: Add arguments other than --prefix
|
||||||
|
# FIXME: If not needed delete the function
|
||||||
|
args = []
|
||||||
|
return args"""
|
||||||
|
|
||||||
|
|
||||||
|
class CMakeGuess(DefaultGuess):
|
||||||
|
"""Provides appropriate overrides for cmake-based packages"""
|
||||||
|
base_class_name = 'CMakePackage'
|
||||||
|
|
||||||
|
dependencies = """\
|
||||||
# FIXME: Add additional dependencies if required.
|
# FIXME: Add additional dependencies if required.
|
||||||
depends_on('cmake', type='build')""",
|
depends_on('cmake', type='build')"""
|
||||||
|
|
||||||
'scons': """\
|
body = """\
|
||||||
|
def cmake_args(self):
|
||||||
|
# FIXME: Add arguments other than
|
||||||
|
# FIXME: CMAKE_INSTALL_PREFIX and CMAKE_BUILD_TYPE
|
||||||
|
# FIXME: If not needed delete the function
|
||||||
|
args = []
|
||||||
|
return args"""
|
||||||
|
|
||||||
|
|
||||||
|
class SconsGuess(DefaultGuess):
|
||||||
|
"""Provides appropriate overrides for scons-based packages"""
|
||||||
|
dependencies = """\
|
||||||
# FIXME: Add additional dependencies if required.
|
# FIXME: Add additional dependencies if required.
|
||||||
depends_on('scons', type='build')""",
|
depends_on('scons', type='build')"""
|
||||||
|
|
||||||
'bazel': """\
|
body = """\
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
# FIXME: Add logic to build and install here.
|
||||||
|
scons('prefix={0}'.format(prefix))
|
||||||
|
scons('install')"""
|
||||||
|
|
||||||
|
|
||||||
|
class BazelGuess(DefaultGuess):
|
||||||
|
"""Provides appropriate overrides for bazel-based packages"""
|
||||||
|
dependencies = """\
|
||||||
# FIXME: Add additional dependencies if required.
|
# FIXME: Add additional dependencies if required.
|
||||||
depends_on('bazel', type='build')""",
|
depends_on('bazel', type='build')"""
|
||||||
|
|
||||||
'python': """\
|
body = """\
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
# FIXME: Add logic to build and install here.
|
||||||
|
bazel()"""
|
||||||
|
|
||||||
|
|
||||||
|
class PythonGuess(DefaultGuess):
|
||||||
|
"""Provides appropriate overrides for python extensions"""
|
||||||
|
dependencies = """\
|
||||||
extends('python')
|
extends('python')
|
||||||
|
|
||||||
# FIXME: Add additional dependencies if required.
|
# FIXME: Add additional dependencies if required.
|
||||||
# depends_on('py-setuptools', type='build')
|
# depends_on('py-setuptools', type='build')
|
||||||
# depends_on('py-foo', type=nolink)""",
|
# depends_on('py-foo', type=nolink)"""
|
||||||
|
|
||||||
'R': """\
|
body = """\
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
# FIXME: Add logic to build and install here.
|
||||||
|
setup_py('install', '--prefix={0}'.format(prefix))"""
|
||||||
|
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
name = 'py-{0}'.format(name)
|
||||||
|
super(PythonGuess, self).__init__(name, *args)
|
||||||
|
|
||||||
|
|
||||||
|
class RGuess(DefaultGuess):
|
||||||
|
"""Provides appropriate overrides for R extensions"""
|
||||||
|
dependencies = """\
|
||||||
extends('R')
|
extends('R')
|
||||||
|
|
||||||
# FIXME: Add additional dependencies if required.
|
# FIXME: Add additional dependencies if required.
|
||||||
# depends_on('r-foo', type=nolink)""",
|
# depends_on('r-foo', type=nolink)"""
|
||||||
|
|
||||||
'octave': """\
|
body = """\
|
||||||
|
def install(self, spec, prefix):
|
||||||
|
# FIXME: Add logic to build and install here.
|
||||||
|
R('CMD', 'INSTALL', '--library={0}'.format(self.module.r_lib_dir),
|
||||||
|
self.stage.source_path)"""
|
||||||
|
|
||||||
|
def __init__(self, name, *args):
|
||||||
|
name = 'r-{0}'.format(name)
|
||||||
|
super(RGuess, self).__init__(name, *args)
|
||||||
|
|
||||||
|
|
||||||
|
class OctaveGuess(DefaultGuess):
|
||||||
|
"""Provides appropriate overrides for octave packages"""
|
||||||
|
dependencies = """\
|
||||||
extends('octave')
|
extends('octave')
|
||||||
|
|
||||||
# FIXME: Add additional dependencies if required.
|
# FIXME: Add additional dependencies if required.
|
||||||
# depends_on('octave-foo', type=nolink)""",
|
# depends_on('octave-foo', type=nolink)"""
|
||||||
|
|
||||||
'unknown': """\
|
body = """\
|
||||||
# FIXME: Add dependencies if required.
|
def install(self, spec, prefix):
|
||||||
# depends_on('foo')"""
|
|
||||||
}
|
|
||||||
|
|
||||||
# Default installation instructions
|
|
||||||
install_dict = {
|
|
||||||
'autotools': """\
|
|
||||||
# FIXME: Modify the configure line to suit your build system here.
|
|
||||||
configure('--prefix={0}'.format(prefix))
|
|
||||||
|
|
||||||
# FIXME: Add logic to build and install here.
|
|
||||||
make()
|
|
||||||
make('install')""",
|
|
||||||
|
|
||||||
'cmake': """\
|
|
||||||
with working_dir('spack-build', create=True):
|
|
||||||
# FIXME: Modify the cmake line to suit your build system here.
|
|
||||||
cmake('..', *std_cmake_args)
|
|
||||||
|
|
||||||
# FIXME: Add logic to build and install here.
|
|
||||||
make()
|
|
||||||
make('install')""",
|
|
||||||
|
|
||||||
'scons': """\
|
|
||||||
# FIXME: Add logic to build and install here.
|
|
||||||
scons('prefix={0}'.format(prefix))
|
|
||||||
scons('install')""",
|
|
||||||
|
|
||||||
'bazel': """\
|
|
||||||
# FIXME: Add logic to build and install here.
|
|
||||||
bazel()""",
|
|
||||||
|
|
||||||
'python': """\
|
|
||||||
# FIXME: Add logic to build and install here.
|
|
||||||
setup_py('install', '--prefix={0}'.format(prefix))""",
|
|
||||||
|
|
||||||
'R': """\
|
|
||||||
# FIXME: Add logic to build and install here.
|
|
||||||
R('CMD', 'INSTALL', '--library={0}'.format(self.module.r_lib_dir),
|
|
||||||
self.stage.source_path)""",
|
|
||||||
|
|
||||||
'octave': """\
|
|
||||||
# FIXME: Add logic to build and install here.
|
# FIXME: Add logic to build and install here.
|
||||||
octave('--quiet', '--norc',
|
octave('--quiet', '--norc',
|
||||||
'--built-in-docstrings-file=/dev/null',
|
'--built-in-docstrings-file=/dev/null',
|
||||||
'--texi-macros-file=/dev/null',
|
'--texi-macros-file=/dev/null',
|
||||||
'--eval', 'pkg prefix {0}; pkg install {1}'.format(
|
'--eval', 'pkg prefix {0}; pkg install {1}'.format(
|
||||||
prefix, self.stage.archive_file))""",
|
prefix, self.stage.archive_file))"""
|
||||||
|
|
||||||
'unknown': """\
|
def __init__(self, name, *args):
|
||||||
# FIXME: Unknown build system
|
name = 'octave-{0}'.format(name)
|
||||||
make()
|
super(OctaveGuess, self).__init__(name, *args)
|
||||||
make('install')"""
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def make_version_calls(ver_hash_tuples):
|
|
||||||
"""Adds a version() call to the package for each version found."""
|
|
||||||
max_len = max(len(str(v)) for v, h in ver_hash_tuples)
|
|
||||||
format = " version(%%-%ds, '%%s')" % (max_len + 2)
|
|
||||||
return '\n'.join(format % ("'%s'" % v, h) for v, h in ver_hash_tuples)
|
|
||||||
|
|
||||||
|
|
||||||
def setup_parser(subparser):
|
def setup_parser(subparser):
|
||||||
@@ -227,6 +277,16 @@ def setup_parser(subparser):
|
|||||||
|
|
||||||
class BuildSystemGuesser(object):
|
class BuildSystemGuesser(object):
|
||||||
|
|
||||||
|
_choices = {
|
||||||
|
'autotools': AutotoolsGuess,
|
||||||
|
'cmake': CMakeGuess,
|
||||||
|
'scons': SconsGuess,
|
||||||
|
'bazel': BazelGuess,
|
||||||
|
'python': PythonGuess,
|
||||||
|
'R': RGuess,
|
||||||
|
'octave': OctaveGuess
|
||||||
|
}
|
||||||
|
|
||||||
def __call__(self, stage, url):
|
def __call__(self, stage, url):
|
||||||
"""Try to guess the type of build system used by a project based on
|
"""Try to guess the type of build system used by a project based on
|
||||||
the contents of its archive or the URL it was downloaded from."""
|
the contents of its archive or the URL it was downloaded from."""
|
||||||
@@ -275,6 +335,10 @@ def __call__(self, stage, url):
|
|||||||
|
|
||||||
self.build_system = build_system
|
self.build_system = build_system
|
||||||
|
|
||||||
|
def make_guess(self, name, url, ver_hash_tuples):
|
||||||
|
cls = self._choiches.get(self.build_system, DefaultGuess)
|
||||||
|
return cls(name, url, ver_hash_tuples)
|
||||||
|
|
||||||
|
|
||||||
def guess_name_and_version(url, args):
|
def guess_name_and_version(url, args):
|
||||||
# Try to deduce name and version of the new package from the URL
|
# Try to deduce name and version of the new package from the URL
|
||||||
@@ -348,7 +412,7 @@ def fetch_tarballs(url, name, version):
|
|||||||
tty.msg("Found %s versions of %s:" % (len(versions), name),
|
tty.msg("Found %s versions of %s:" % (len(versions), name),
|
||||||
*spack.cmd.elide_list(
|
*spack.cmd.elide_list(
|
||||||
["%-10s%s" % (v, u) for v, u in versions.iteritems()]))
|
["%-10s%s" % (v, u) for v, u in versions.iteritems()]))
|
||||||
print
|
print('')
|
||||||
archives_to_fetch = tty.get_number(
|
archives_to_fetch = tty.get_number(
|
||||||
"Include how many checksums in the package file?",
|
"Include how many checksums in the package file?",
|
||||||
default=5, abort='q')
|
default=5, abort='q')
|
||||||
@@ -389,16 +453,10 @@ def create(parser, args):
|
|||||||
if not ver_hash_tuples:
|
if not ver_hash_tuples:
|
||||||
tty.die("Could not fetch any tarballs for %s" % name)
|
tty.die("Could not fetch any tarballs for %s" % name)
|
||||||
|
|
||||||
# Add prefix to package name if it is an extension.
|
guess = guesser.make_guess(name, url, ver_hash_tuples)
|
||||||
if guesser.build_system == 'python':
|
|
||||||
name = 'py-{0}'.format(name)
|
|
||||||
if guesser.build_system == 'R':
|
|
||||||
name = 'r-{0}'.format(name)
|
|
||||||
if guesser.build_system == 'octave':
|
|
||||||
name = 'octave-{0}'.format(name)
|
|
||||||
|
|
||||||
# Create a directory for the new package.
|
# Create a directory for the new package.
|
||||||
pkg_path = repo.filename_for_package_name(name)
|
pkg_path = repo.filename_for_package_name(guess.name)
|
||||||
if os.path.exists(pkg_path) and not args.force:
|
if os.path.exists(pkg_path) and not args.force:
|
||||||
tty.die("%s already exists." % pkg_path)
|
tty.die("%s already exists." % pkg_path)
|
||||||
else:
|
else:
|
||||||
@@ -408,12 +466,15 @@ def create(parser, args):
|
|||||||
with open(pkg_path, "w") as pkg_file:
|
with open(pkg_path, "w") as pkg_file:
|
||||||
pkg_file.write(
|
pkg_file.write(
|
||||||
package_template.substitute(
|
package_template.substitute(
|
||||||
name=name,
|
name=guess.name,
|
||||||
class_name=mod_to_class(name),
|
class_name=guess.class_name,
|
||||||
url=url,
|
base_class_name=guess.base_class_name,
|
||||||
versions=make_version_calls(ver_hash_tuples),
|
url=guess.url,
|
||||||
dependencies=dependencies_dict[guesser.build_system],
|
versions=guess.versions,
|
||||||
install=install_dict[guesser.build_system]))
|
dependencies=guess.dependencies,
|
||||||
|
body=guess.body
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# If everything checks out, go ahead and edit.
|
# If everything checks out, go ahead and edit.
|
||||||
spack.editor(pkg_path)
|
spack.editor(pkg_path)
|
||||||
|
@@ -48,8 +48,11 @@ def setup_parser(subparser):
|
|||||||
|
|
||||||
def print_text_info(pkg):
|
def print_text_info(pkg):
|
||||||
"""Print out a plain text description of a package."""
|
"""Print out a plain text description of a package."""
|
||||||
print "Package: ", pkg.name
|
header = "{0}: ".format(pkg.build_system_class)
|
||||||
print "Homepage: ", pkg.homepage
|
|
||||||
|
print header, pkg.name
|
||||||
|
whitespaces = ''.join([' '] * (len(header) - len("Homepage: ")))
|
||||||
|
print "Homepage:", whitespaces, pkg.homepage
|
||||||
|
|
||||||
print
|
print
|
||||||
print "Safe versions: "
|
print "Safe versions: "
|
||||||
@@ -84,6 +87,13 @@ def print_text_info(pkg):
|
|||||||
|
|
||||||
print " " + fmt % (name, default, desc)
|
print " " + fmt % (name, default, desc)
|
||||||
|
|
||||||
|
print
|
||||||
|
print "Installation Phases:"
|
||||||
|
phase_str = ''
|
||||||
|
for phase in pkg.phases:
|
||||||
|
phase_str += " {0}".format(phase)
|
||||||
|
print phase_str
|
||||||
|
|
||||||
for deptype in ('build', 'link', 'run'):
|
for deptype in ('build', 'link', 'run'):
|
||||||
print
|
print
|
||||||
print "%s Dependencies:" % deptype.capitalize()
|
print "%s Dependencies:" % deptype.capitalize()
|
||||||
@@ -94,7 +104,7 @@ def print_text_info(pkg):
|
|||||||
print " None"
|
print " None"
|
||||||
|
|
||||||
print
|
print
|
||||||
print "Virtual packages: "
|
print "Virtual Packages: "
|
||||||
if pkg.provided:
|
if pkg.provided:
|
||||||
for spec, when in pkg.provided.items():
|
for spec, when in pkg.provided.items():
|
||||||
print " %s provides %s" % (when, spec)
|
print " %s provides %s" % (when, spec)
|
||||||
|
@@ -22,7 +22,6 @@
|
|||||||
# License along with this program; if not, write to the Free Software
|
# License along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
from __future__ import print_function
|
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
@@ -75,7 +74,7 @@ def setup_parser(subparser):
|
|||||||
help="Run tests during installation of a package.")
|
help="Run tests during installation of a package.")
|
||||||
|
|
||||||
|
|
||||||
def install(parser, args):
|
def install(parser, args, **kwargs):
|
||||||
if not args.package:
|
if not args.package:
|
||||||
tty.die("install requires at least one package argument")
|
tty.die("install requires at least one package argument")
|
||||||
|
|
||||||
@@ -88,7 +87,7 @@ def install(parser, args):
|
|||||||
|
|
||||||
# Parse cli arguments and construct a dictionary
|
# Parse cli arguments and construct a dictionary
|
||||||
# that will be passed to Package.do_install API
|
# that will be passed to Package.do_install API
|
||||||
kwargs = {
|
kwargs.update({
|
||||||
'keep_prefix': args.keep_prefix,
|
'keep_prefix': args.keep_prefix,
|
||||||
'keep_stage': args.keep_stage,
|
'keep_stage': args.keep_stage,
|
||||||
'install_deps': 'dependencies' in args.things_to_install,
|
'install_deps': 'dependencies' in args.things_to_install,
|
||||||
@@ -97,7 +96,7 @@ def install(parser, args):
|
|||||||
'verbose': args.verbose,
|
'verbose': args.verbose,
|
||||||
'fake': args.fake,
|
'fake': args.fake,
|
||||||
'dirty': args.dirty
|
'dirty': args.dirty
|
||||||
}
|
})
|
||||||
|
|
||||||
# Spec from cli
|
# Spec from cli
|
||||||
specs = spack.cmd.parse_specs(args.package, concretize=True)
|
specs = spack.cmd.parse_specs(args.package, concretize=True)
|
||||||
|
@@ -22,16 +22,18 @@
|
|||||||
# along with this program; if not, write to the Free Software Foundation,
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
##############################################################################
|
##############################################################################
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import os
|
||||||
|
import string
|
||||||
|
import sys
|
||||||
|
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.cmd
|
import spack.cmd
|
||||||
|
from spack import which
|
||||||
from spack.cmd.edit import edit_package
|
from spack.cmd.edit import edit_package
|
||||||
from spack.stage import DIYStage
|
from spack.stage import DIYStage
|
||||||
|
from llnl.util.filesystem import set_executable
|
||||||
|
|
||||||
description = "Create a configuration script and module, but don't build."
|
description = "Create a configuration script and module, but don't build."
|
||||||
|
|
||||||
@@ -51,6 +53,72 @@ def setup_parser(subparser):
|
|||||||
help="Install a package *without* cleaning the environment.")
|
help="Install a package *without* cleaning the environment.")
|
||||||
|
|
||||||
|
|
||||||
|
def spack_transitive_include_path():
|
||||||
|
return ';'.join(
|
||||||
|
os.path.join(dep, 'include')
|
||||||
|
for dep in os.environ['SPACK_DEPENDENCIES'].split(os.pathsep)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def write_spconfig(package):
|
||||||
|
# Set-up the environment
|
||||||
|
spack.build_environment.setup_package(package)
|
||||||
|
|
||||||
|
cmd = [str(which('cmake'))] + package.std_cmake_args + package.cmake_args()
|
||||||
|
|
||||||
|
env = dict()
|
||||||
|
|
||||||
|
paths = os.environ['PATH'].split(':')
|
||||||
|
paths = [item for item in paths if 'spack/env' not in item]
|
||||||
|
env['PATH'] = ':'.join(paths)
|
||||||
|
env['SPACK_TRANSITIVE_INCLUDE_PATH'] = spack_transitive_include_path()
|
||||||
|
env['CMAKE_PREFIX_PATH'] = os.environ['CMAKE_PREFIX_PATH']
|
||||||
|
env['CC'] = os.environ['SPACK_CC']
|
||||||
|
env['CXX'] = os.environ['SPACK_CXX']
|
||||||
|
env['FC'] = os.environ['SPACK_FC']
|
||||||
|
|
||||||
|
setup_fname = 'spconfig.py'
|
||||||
|
with open(setup_fname, 'w') as fout:
|
||||||
|
fout.write(
|
||||||
|
r"""#!%s
|
||||||
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
def cmdlist(str):
|
||||||
|
return list(x.strip().replace("'",'') for x in str.split('\n') if x)
|
||||||
|
env = dict(os.environ)
|
||||||
|
""" % sys.executable)
|
||||||
|
|
||||||
|
env_vars = sorted(list(env.keys()))
|
||||||
|
for name in env_vars:
|
||||||
|
val = env[name]
|
||||||
|
if string.find(name, 'PATH') < 0:
|
||||||
|
fout.write('env[%s] = %s\n' % (repr(name), repr(val)))
|
||||||
|
else:
|
||||||
|
if name == 'SPACK_TRANSITIVE_INCLUDE_PATH':
|
||||||
|
sep = ';'
|
||||||
|
else:
|
||||||
|
sep = ':'
|
||||||
|
|
||||||
|
fout.write(
|
||||||
|
'env[%s] = "%s".join(cmdlist("""\n' % (repr(name), sep))
|
||||||
|
for part in string.split(val, sep):
|
||||||
|
fout.write(' %s\n' % part)
|
||||||
|
fout.write('"""))\n')
|
||||||
|
|
||||||
|
fout.write("env['CMAKE_TRANSITIVE_INCLUDE_PATH'] = env['SPACK_TRANSITIVE_INCLUDE_PATH'] # Deprecated\n") # NOQA: ignore=E501
|
||||||
|
fout.write('\ncmd = cmdlist("""\n')
|
||||||
|
fout.write('%s\n' % cmd[0])
|
||||||
|
for arg in cmd[1:]:
|
||||||
|
fout.write(' %s\n' % arg)
|
||||||
|
fout.write('""") + sys.argv[1:]\n')
|
||||||
|
fout.write('\nproc = subprocess.Popen(cmd, env=env)\nproc.wait()\n')
|
||||||
|
set_executable(setup_fname)
|
||||||
|
|
||||||
|
|
||||||
def setup(self, args):
|
def setup(self, args):
|
||||||
if not args.spec:
|
if not args.spec:
|
||||||
tty.die("spack setup requires a package spec argument.")
|
tty.die("spack setup requires a package spec argument.")
|
||||||
@@ -80,6 +148,12 @@ def setup(self, args):
|
|||||||
|
|
||||||
spec.concretize()
|
spec.concretize()
|
||||||
package = spack.repo.get(spec)
|
package = spack.repo.get(spec)
|
||||||
|
if not isinstance(package, spack.CMakePackage):
|
||||||
|
tty.die(
|
||||||
|
'Support for {0} derived packages not yet implemented'.format(
|
||||||
|
package.build_system_class
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# It's OK if the package is already installed.
|
# It's OK if the package is already installed.
|
||||||
|
|
||||||
@@ -89,10 +163,4 @@ def setup(self, args):
|
|||||||
# TODO: make this an argument, not a global.
|
# TODO: make this an argument, not a global.
|
||||||
spack.do_checksum = False
|
spack.do_checksum = False
|
||||||
|
|
||||||
package.do_install(
|
write_spconfig(package)
|
||||||
keep_prefix=True, # Don't remove install directory
|
|
||||||
install_deps=not args.ignore_deps,
|
|
||||||
verbose=args.verbose,
|
|
||||||
keep_stage=True, # don't remove source dir for SETUP.
|
|
||||||
install_phases=set(['setup', 'provenance']),
|
|
||||||
dirty=args.dirty)
|
|
||||||
|
@@ -26,6 +26,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
import spack
|
import spack
|
||||||
|
import inspect
|
||||||
|
|
||||||
|
|
||||||
class SpackError(Exception):
|
class SpackError(Exception):
|
||||||
@@ -49,7 +50,7 @@ def die(self):
|
|||||||
else:
|
else:
|
||||||
tty.error(self.message)
|
tty.error(self.message)
|
||||||
if self.long_message:
|
if self.long_message:
|
||||||
print self.long_message
|
print(self.long_message)
|
||||||
os._exit(1)
|
os._exit(1)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
@@ -58,6 +59,16 @@ def __str__(self):
|
|||||||
msg += "\n %s" % self._long_message
|
msg += "\n %s" % self._long_message
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
args = [repr(self.message), repr(self.long_message)]
|
||||||
|
args = ','.join(args)
|
||||||
|
qualified_name = inspect.getmodule(
|
||||||
|
self).__name__ + '.' + type(self).__name__
|
||||||
|
return qualified_name + '(' + args + ')'
|
||||||
|
|
||||||
|
def __reduce__(self):
|
||||||
|
return type(self), (self.message, self.long_message)
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedPlatformError(SpackError):
|
class UnsupportedPlatformError(SpackError):
|
||||||
"""Raised by packages when a platform is not supported"""
|
"""Raised by packages when a platform is not supported"""
|
||||||
|
@@ -33,24 +33,20 @@
|
|||||||
rundown on spack and how it differs from homebrew, look at the
|
rundown on spack and how it differs from homebrew, look at the
|
||||||
README.
|
README.
|
||||||
"""
|
"""
|
||||||
|
import contextlib
|
||||||
|
import copy
|
||||||
|
import functools
|
||||||
|
import inspect
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import re
|
import re
|
||||||
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import time
|
import time
|
||||||
import string
|
|
||||||
import contextlib
|
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
import llnl.util.lock
|
import llnl.util.lock
|
||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
from llnl.util.filesystem import *
|
|
||||||
from llnl.util.lang import *
|
|
||||||
from llnl.util.link_tree import LinkTree
|
|
||||||
from llnl.util.tty.log import log_output
|
|
||||||
|
|
||||||
import spack
|
import spack
|
||||||
import spack.build_environment
|
|
||||||
import spack.compilers
|
import spack.compilers
|
||||||
import spack.directives
|
import spack.directives
|
||||||
import spack.error
|
import spack.error
|
||||||
@@ -60,20 +56,188 @@
|
|||||||
import spack.repository
|
import spack.repository
|
||||||
import spack.url
|
import spack.url
|
||||||
import spack.util.web
|
import spack.util.web
|
||||||
|
from llnl.util.filesystem import *
|
||||||
|
from llnl.util.lang import *
|
||||||
|
from llnl.util.link_tree import LinkTree
|
||||||
|
from llnl.util.tty.log import log_output
|
||||||
|
from spack import directory_layout
|
||||||
from spack.stage import Stage, ResourceStage, StageComposite
|
from spack.stage import Stage, ResourceStage, StageComposite
|
||||||
from spack.util.crypto import bit_length
|
from spack.util.crypto import bit_length
|
||||||
from spack.util.environment import dump_environment
|
from spack.util.environment import dump_environment
|
||||||
from spack.util.executable import ProcessError, which
|
from spack.util.executable import ProcessError
|
||||||
from spack.version import *
|
from spack.version import *
|
||||||
from spack import directory_layout
|
|
||||||
|
|
||||||
|
|
||||||
"""Allowed URL schemes for spack packages."""
|
"""Allowed URL schemes for spack packages."""
|
||||||
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"]
|
_ALLOWED_URL_SCHEMES = ["http", "https", "ftp", "file", "git"]
|
||||||
|
|
||||||
|
|
||||||
class Package(object):
|
class InstallPhase(object):
|
||||||
|
"""Manages a single phase of the installation
|
||||||
|
|
||||||
|
This descriptor stores at creation time the name of the method it should
|
||||||
|
search for execution. The method is retrieved at __get__ time, so that
|
||||||
|
it can be overridden by subclasses of whatever class declared the phases.
|
||||||
|
|
||||||
|
It also provides hooks to execute prerequisite and sanity checks.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
self.preconditions = []
|
||||||
|
self.sanity_checks = []
|
||||||
|
|
||||||
|
def __get__(self, instance, owner):
|
||||||
|
# The caller is a class that is trying to customize
|
||||||
|
# my behavior adding something
|
||||||
|
if instance is None:
|
||||||
|
return self
|
||||||
|
# If instance is there the caller wants to execute the
|
||||||
|
# install phase, thus return a properly set wrapper
|
||||||
|
phase = getattr(instance, self.name)
|
||||||
|
|
||||||
|
@functools.wraps(phase)
|
||||||
|
def phase_wrapper(spec, prefix):
|
||||||
|
# Check instance attributes at the beginning of a phase
|
||||||
|
self._on_phase_start(instance)
|
||||||
|
# Execute phase pre-conditions,
|
||||||
|
# and give them the chance to fail
|
||||||
|
for check in self.preconditions:
|
||||||
|
# Do something sensible at some point
|
||||||
|
check(instance)
|
||||||
|
phase(spec, prefix)
|
||||||
|
# Execute phase sanity_checks,
|
||||||
|
# and give them the chance to fail
|
||||||
|
for check in self.sanity_checks:
|
||||||
|
check(instance)
|
||||||
|
# Check instance attributes at the end of a phase
|
||||||
|
self._on_phase_exit(instance)
|
||||||
|
return phase_wrapper
|
||||||
|
|
||||||
|
def _on_phase_start(self, instance):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _on_phase_exit(self, instance):
|
||||||
|
# If a phase has a matching last_phase attribute,
|
||||||
|
# stop the installation process raising a StopIteration
|
||||||
|
if getattr(instance, 'last_phase', None) == self.name:
|
||||||
|
raise StopIteration('Stopping at \'{0}\' phase'.format(self.name))
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
try:
|
||||||
|
return copy.deepcopy(self)
|
||||||
|
except TypeError:
|
||||||
|
# This bug-fix was not back-ported in Python 2.6
|
||||||
|
# http://bugs.python.org/issue1515
|
||||||
|
other = InstallPhase(self.name)
|
||||||
|
other.preconditions.extend(self.preconditions)
|
||||||
|
other.sanity_checks.extend(self.sanity_checks)
|
||||||
|
return other
|
||||||
|
|
||||||
|
|
||||||
|
class PackageMeta(type):
|
||||||
|
"""Conveniently transforms attributes to permit extensible phases
|
||||||
|
|
||||||
|
Iterates over the attribute 'phases' and creates / updates private
|
||||||
|
InstallPhase attributes in the class that is being initialized
|
||||||
|
"""
|
||||||
|
phase_fmt = '_InstallPhase_{0}'
|
||||||
|
|
||||||
|
_InstallPhase_sanity_checks = {}
|
||||||
|
_InstallPhase_preconditions = {}
|
||||||
|
|
||||||
|
def __new__(meta, name, bases, attr_dict):
|
||||||
|
# Check if phases is in attr dict, then set
|
||||||
|
# install phases wrappers
|
||||||
|
if 'phases' in attr_dict:
|
||||||
|
_InstallPhase_phases = [PackageMeta.phase_fmt.format(x) for x in attr_dict['phases']] # NOQA: ignore=E501
|
||||||
|
for phase_name, callback_name in zip(_InstallPhase_phases, attr_dict['phases']): # NOQA: ignore=E501
|
||||||
|
attr_dict[phase_name] = InstallPhase(callback_name)
|
||||||
|
attr_dict['_InstallPhase_phases'] = _InstallPhase_phases
|
||||||
|
|
||||||
|
def _append_checks(check_name):
|
||||||
|
# Name of the attribute I am going to check it exists
|
||||||
|
attr_name = PackageMeta.phase_fmt.format(check_name)
|
||||||
|
checks = getattr(meta, attr_name)
|
||||||
|
if checks:
|
||||||
|
for phase_name, funcs in checks.items():
|
||||||
|
try:
|
||||||
|
# Search for the phase in the attribute dictionary
|
||||||
|
phase = attr_dict[
|
||||||
|
PackageMeta.phase_fmt.format(phase_name)]
|
||||||
|
except KeyError:
|
||||||
|
# If it is not there it's in the bases
|
||||||
|
# and we added a check. We need to copy
|
||||||
|
# and extend
|
||||||
|
for base in bases:
|
||||||
|
phase = getattr(
|
||||||
|
base,
|
||||||
|
PackageMeta.phase_fmt.format(phase_name),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
attr_dict[PackageMeta.phase_fmt.format(
|
||||||
|
phase_name)] = phase.copy()
|
||||||
|
phase = attr_dict[
|
||||||
|
PackageMeta.phase_fmt.format(phase_name)]
|
||||||
|
getattr(phase, check_name).extend(funcs)
|
||||||
|
# Clear the attribute for the next class
|
||||||
|
setattr(meta, attr_name, {})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _register_checks(cls, check_type, *args):
|
||||||
|
def _register_sanity_checks(func):
|
||||||
|
attr_name = PackageMeta.phase_fmt.format(check_type)
|
||||||
|
check_list = getattr(meta, attr_name)
|
||||||
|
for item in args:
|
||||||
|
checks = check_list.setdefault(item, [])
|
||||||
|
checks.append(func)
|
||||||
|
setattr(meta, attr_name, check_list)
|
||||||
|
return func
|
||||||
|
return _register_sanity_checks
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def on_package_attributes(**attrs):
|
||||||
|
def _execute_under_condition(func):
|
||||||
|
@functools.wraps(func)
|
||||||
|
def _wrapper(instance):
|
||||||
|
# If all the attributes have the value we require, then
|
||||||
|
# execute
|
||||||
|
if all([getattr(instance, key, None) == value for key, value in attrs.items()]): # NOQA: ignore=E501
|
||||||
|
func(instance)
|
||||||
|
return _wrapper
|
||||||
|
return _execute_under_condition
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def precondition(cls, *args):
|
||||||
|
return cls._register_checks('preconditions', *args)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def sanity_check(cls, *args):
|
||||||
|
return cls._register_checks('sanity_checks', *args)
|
||||||
|
|
||||||
|
if all([not hasattr(x, '_register_checks') for x in bases]):
|
||||||
|
attr_dict['_register_checks'] = _register_checks
|
||||||
|
|
||||||
|
if all([not hasattr(x, 'sanity_check') for x in bases]):
|
||||||
|
attr_dict['sanity_check'] = sanity_check
|
||||||
|
|
||||||
|
if all([not hasattr(x, 'precondition') for x in bases]):
|
||||||
|
attr_dict['precondition'] = precondition
|
||||||
|
|
||||||
|
if all([not hasattr(x, 'on_package_attributes') for x in bases]):
|
||||||
|
attr_dict['on_package_attributes'] = on_package_attributes
|
||||||
|
|
||||||
|
# Preconditions
|
||||||
|
_append_checks('preconditions')
|
||||||
|
# Sanity checks
|
||||||
|
_append_checks('sanity_checks')
|
||||||
|
return super(PackageMeta, meta).__new__(meta, name, bases, attr_dict)
|
||||||
|
|
||||||
|
def __init__(cls, name, bases, dict):
|
||||||
|
type.__init__(cls, name, bases, dict)
|
||||||
|
spack.directives.ensure_dicts(cls)
|
||||||
|
|
||||||
|
|
||||||
|
class PackageBase(object):
|
||||||
"""This is the superclass for all spack packages.
|
"""This is the superclass for all spack packages.
|
||||||
|
|
||||||
***The Package class***
|
***The Package class***
|
||||||
@@ -309,7 +473,7 @@ class SomePackage(Package):
|
|||||||
Package creators override functions like install() (all of them do this),
|
Package creators override functions like install() (all of them do this),
|
||||||
clean() (some of them do this), and others to provide custom behavior.
|
clean() (some of them do this), and others to provide custom behavior.
|
||||||
"""
|
"""
|
||||||
|
__metaclass__ = PackageMeta
|
||||||
#
|
#
|
||||||
# These are default values for instance variables.
|
# These are default values for instance variables.
|
||||||
#
|
#
|
||||||
@@ -344,12 +508,6 @@ class SomePackage(Package):
|
|||||||
"""Per-process lock objects for each install prefix."""
|
"""Per-process lock objects for each install prefix."""
|
||||||
prefix_locks = {}
|
prefix_locks = {}
|
||||||
|
|
||||||
class __metaclass__(type):
|
|
||||||
"""Ensure attributes required by Spack directives are present."""
|
|
||||||
def __init__(cls, name, bases, dict):
|
|
||||||
type.__init__(cls, name, bases, dict)
|
|
||||||
spack.directives.ensure_dicts(cls)
|
|
||||||
|
|
||||||
def __init__(self, spec):
|
def __init__(self, spec):
|
||||||
# this determines how the package should be built.
|
# this determines how the package should be built.
|
||||||
self.spec = spec
|
self.spec = spec
|
||||||
@@ -429,6 +587,8 @@ def __init__(self, spec):
|
|||||||
if self.is_extension:
|
if self.is_extension:
|
||||||
spack.repo.get(self.extendee_spec)._check_extendable()
|
spack.repo.get(self.extendee_spec)._check_extendable()
|
||||||
|
|
||||||
|
self.extra_args = {}
|
||||||
|
|
||||||
def possible_dependencies(self, visited=None):
|
def possible_dependencies(self, visited=None):
|
||||||
"""Return set of possible transitive dependencies of this package."""
|
"""Return set of possible transitive dependencies of this package."""
|
||||||
if visited is None:
|
if visited is None:
|
||||||
@@ -886,12 +1046,34 @@ def namespace(self):
|
|||||||
return namespace
|
return namespace
|
||||||
|
|
||||||
def do_fake_install(self):
|
def do_fake_install(self):
|
||||||
"""Make a fake install directory contaiing a 'fake' file in bin."""
|
"""Make a fake install directory containing a 'fake' file in bin."""
|
||||||
|
# FIXME : Make this part of the 'install' behavior ?
|
||||||
mkdirp(self.prefix.bin)
|
mkdirp(self.prefix.bin)
|
||||||
touch(join_path(self.prefix.bin, 'fake'))
|
touch(join_path(self.prefix.bin, 'fake'))
|
||||||
mkdirp(self.prefix.lib)
|
mkdirp(self.prefix.lib)
|
||||||
mkdirp(self.prefix.man1)
|
mkdirp(self.prefix.man1)
|
||||||
|
|
||||||
|
def _if_make_target_execute(self, target):
|
||||||
|
try:
|
||||||
|
# Check if we have a makefile
|
||||||
|
file = [x for x in ('Makefile', 'makefile') if os.path.exists(x)]
|
||||||
|
file = file.pop()
|
||||||
|
except IndexError:
|
||||||
|
tty.msg('No Makefile found in the build directory')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if 'target' is in the makefile
|
||||||
|
regex = re.compile('^' + target + ':')
|
||||||
|
with open(file, 'r') as f:
|
||||||
|
matches = [line for line in f.readlines() if regex.match(line)]
|
||||||
|
|
||||||
|
if not matches:
|
||||||
|
tty.msg('Target \'' + target + ':\' not found in Makefile')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Execute target
|
||||||
|
inspect.getmodule(self).make(target)
|
||||||
|
|
||||||
def _get_needed_resources(self):
|
def _get_needed_resources(self):
|
||||||
resources = []
|
resources = []
|
||||||
# Select the resources that are needed for this build
|
# Select the resources that are needed for this build
|
||||||
@@ -925,13 +1107,10 @@ def _prefix_write_lock(self):
|
|||||||
finally:
|
finally:
|
||||||
self.prefix_lock.release_write()
|
self.prefix_lock.release_write()
|
||||||
|
|
||||||
install_phases = set(['configure', 'build', 'install', 'provenance'])
|
|
||||||
|
|
||||||
def do_install(self,
|
def do_install(self,
|
||||||
keep_prefix=False,
|
keep_prefix=False,
|
||||||
keep_stage=False,
|
keep_stage=False,
|
||||||
install_deps=True,
|
install_deps=True,
|
||||||
install_self=True,
|
|
||||||
skip_patch=False,
|
skip_patch=False,
|
||||||
verbose=False,
|
verbose=False,
|
||||||
make_jobs=None,
|
make_jobs=None,
|
||||||
@@ -939,7 +1118,7 @@ def do_install(self,
|
|||||||
fake=False,
|
fake=False,
|
||||||
explicit=False,
|
explicit=False,
|
||||||
dirty=False,
|
dirty=False,
|
||||||
install_phases=install_phases):
|
**kwargs):
|
||||||
"""Called by commands to install a package and its dependencies.
|
"""Called by commands to install a package and its dependencies.
|
||||||
|
|
||||||
Package implementations should override install() to describe
|
Package implementations should override install() to describe
|
||||||
@@ -975,9 +1154,7 @@ def do_install(self,
|
|||||||
# Ensure package is not already installed
|
# Ensure package is not already installed
|
||||||
layout = spack.install_layout
|
layout = spack.install_layout
|
||||||
with self._prefix_read_lock():
|
with self._prefix_read_lock():
|
||||||
if ('install' in install_phases and
|
if layout.check_installed(self.spec):
|
||||||
layout.check_installed(self.spec)):
|
|
||||||
|
|
||||||
tty.msg(
|
tty.msg(
|
||||||
"%s is already installed in %s" % (self.name, self.prefix))
|
"%s is already installed in %s" % (self.name, self.prefix))
|
||||||
rec = spack.installed_db.get_record(self.spec)
|
rec = spack.installed_db.get_record(self.spec)
|
||||||
@@ -987,6 +1164,8 @@ def do_install(self,
|
|||||||
rec.explicit = True
|
rec.explicit = True
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self._do_install_pop_kwargs(kwargs)
|
||||||
|
|
||||||
tty.msg("Installing %s" % self.name)
|
tty.msg("Installing %s" % self.name)
|
||||||
|
|
||||||
# First, install dependencies recursively.
|
# First, install dependencies recursively.
|
||||||
@@ -1009,7 +1188,6 @@ def do_install(self,
|
|||||||
# Set parallelism before starting build.
|
# Set parallelism before starting build.
|
||||||
self.make_jobs = make_jobs
|
self.make_jobs = make_jobs
|
||||||
|
|
||||||
# ------------------- BEGIN def build_process()
|
|
||||||
# Then install the package itself.
|
# Then install the package itself.
|
||||||
def build_process():
|
def build_process():
|
||||||
"""Forked for each build. Has its own process and python
|
"""Forked for each build. Has its own process and python
|
||||||
@@ -1022,112 +1200,129 @@ def build_process():
|
|||||||
else:
|
else:
|
||||||
self.do_stage()
|
self.do_stage()
|
||||||
|
|
||||||
tty.msg("Building %s" % self.name)
|
tty.msg(
|
||||||
|
'Building {0} [{1}]'.format(self.name, self.build_system_class)
|
||||||
|
)
|
||||||
|
|
||||||
self.stage.keep = keep_stage
|
self.stage.keep = keep_stage
|
||||||
self.install_phases = install_phases
|
|
||||||
self.build_directory = join_path(self.stage.path, 'spack-build')
|
|
||||||
self.source_directory = self.stage.source_path
|
|
||||||
|
|
||||||
with contextlib.nested(self.stage, self._prefix_write_lock()):
|
try:
|
||||||
# Run the pre-install hook in the child process after
|
with contextlib.nested(self.stage, self._prefix_write_lock()):
|
||||||
# the directory is created.
|
# Run the pre-install hook in the child process after
|
||||||
spack.hooks.pre_install(self)
|
# the directory is created.
|
||||||
|
spack.hooks.pre_install(self)
|
||||||
if fake:
|
if fake:
|
||||||
self.do_fake_install()
|
self.do_fake_install()
|
||||||
else:
|
else:
|
||||||
# Do the real install in the source directory.
|
# Do the real install in the source directory.
|
||||||
self.stage.chdir_to_source()
|
self.stage.chdir_to_source()
|
||||||
|
# Save the build environment in a file before building.
|
||||||
# Save the build environment in a file before building.
|
env_path = join_path(os.getcwd(), 'spack-build.env')
|
||||||
env_path = join_path(os.getcwd(), 'spack-build.env')
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Redirect I/O to a build log (and optionally to
|
# Redirect I/O to a build log (and optionally to
|
||||||
# the terminal)
|
# the terminal)
|
||||||
log_path = join_path(os.getcwd(), 'spack-build.out')
|
log_path = join_path(os.getcwd(), 'spack-build.out')
|
||||||
log_file = open(log_path, 'w')
|
# FIXME : refactor this assignment
|
||||||
with log_output(log_file, verbose, sys.stdout.isatty(),
|
self.log_path = log_path
|
||||||
True):
|
self.env_path = env_path
|
||||||
dump_environment(env_path)
|
dump_environment(env_path)
|
||||||
self.install(self.spec, self.prefix)
|
# Spawn a daemon that reads from a pipe and redirects
|
||||||
|
# everything to log_path
|
||||||
|
redirection_context = log_output(
|
||||||
|
log_path, verbose,
|
||||||
|
sys.stdout.isatty(),
|
||||||
|
True
|
||||||
|
)
|
||||||
|
with redirection_context as log_redirection:
|
||||||
|
for phase_name, phase in zip(self.phases, self._InstallPhase_phases): # NOQA: ignore=E501
|
||||||
|
tty.msg(
|
||||||
|
'Executing phase : \'{0}\''.format(phase_name) # NOQA: ignore=E501
|
||||||
|
)
|
||||||
|
# Redirect stdout and stderr to daemon pipe
|
||||||
|
with log_redirection:
|
||||||
|
getattr(self, phase)(
|
||||||
|
self.spec, self.prefix)
|
||||||
|
self.log()
|
||||||
|
# Run post install hooks before build stage is removed.
|
||||||
|
spack.hooks.post_install(self)
|
||||||
|
|
||||||
except ProcessError as e:
|
# Stop timer.
|
||||||
# Annotate ProcessErrors with the location of
|
self._total_time = time.time() - start_time
|
||||||
# the build log
|
build_time = self._total_time - self._fetch_time
|
||||||
e.build_log = log_path
|
|
||||||
raise e
|
|
||||||
|
|
||||||
# Ensure that something was actually installed.
|
tty.msg("Successfully installed %s" % self.name,
|
||||||
if 'install' in self.install_phases:
|
"Fetch: %s. Build: %s. Total: %s." %
|
||||||
self.sanity_check_prefix()
|
(_hms(self._fetch_time), _hms(build_time),
|
||||||
|
_hms(self._total_time)))
|
||||||
|
print_pkg(self.prefix)
|
||||||
|
|
||||||
# Copy provenance into the install directory on success
|
except ProcessError as e:
|
||||||
if 'provenance' in self.install_phases:
|
# Annotate ProcessErrors with the location of
|
||||||
log_install_path = layout.build_log_path(self.spec)
|
# the build log
|
||||||
env_install_path = layout.build_env_path(self.spec)
|
e.build_log = log_path
|
||||||
packages_dir = layout.build_packages_path(self.spec)
|
raise e
|
||||||
|
|
||||||
# Remove first if we're overwriting another build
|
|
||||||
# (can happen with spack setup)
|
|
||||||
try:
|
|
||||||
# log_install_path and env_install_path are here
|
|
||||||
shutil.rmtree(packages_dir)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
install(log_path, log_install_path)
|
|
||||||
install(env_path, env_install_path)
|
|
||||||
dump_packages(self.spec, packages_dir)
|
|
||||||
|
|
||||||
# Run post install hooks before build stage is removed.
|
|
||||||
spack.hooks.post_install(self)
|
|
||||||
|
|
||||||
# Stop timer.
|
|
||||||
self._total_time = time.time() - start_time
|
|
||||||
build_time = self._total_time - self._fetch_time
|
|
||||||
|
|
||||||
tty.msg("Successfully installed %s" % self.name,
|
|
||||||
"Fetch: %s. Build: %s. Total: %s." %
|
|
||||||
(_hms(self._fetch_time), _hms(build_time),
|
|
||||||
_hms(self._total_time)))
|
|
||||||
print_pkg(self.prefix)
|
|
||||||
# ------------------- END def build_process()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Create the install prefix and fork the build process.
|
# Create the install prefix and fork the build process.
|
||||||
spack.install_layout.create_install_directory(self.spec)
|
spack.install_layout.create_install_directory(self.spec)
|
||||||
except directory_layout.InstallDirectoryAlreadyExistsError:
|
# Fork a child to do the actual installation
|
||||||
if 'install' in install_phases:
|
|
||||||
# Abort install if install directory exists.
|
|
||||||
# But do NOT remove it (you'd be overwriting someone's data)
|
|
||||||
tty.warn("Keeping existing install prefix in place.")
|
|
||||||
raise
|
|
||||||
else:
|
|
||||||
# We're not installing anyway, so don't worry if someone
|
|
||||||
# else has already written in the install directory
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
spack.build_environment.fork(self, build_process, dirty=dirty)
|
spack.build_environment.fork(self, build_process, dirty=dirty)
|
||||||
except:
|
# If we installed then we should keep the prefix
|
||||||
# remove the install prefix if anything went wrong during install.
|
keep_prefix = True if self.last_phase is None else keep_prefix
|
||||||
|
# note: PARENT of the build process adds the new package to
|
||||||
|
# the database, so that we don't need to re-read from file.
|
||||||
|
spack.installed_db.add(
|
||||||
|
self.spec, spack.install_layout, explicit=explicit
|
||||||
|
)
|
||||||
|
except directory_layout.InstallDirectoryAlreadyExistsError:
|
||||||
|
# Abort install if install directory exists.
|
||||||
|
# But do NOT remove it (you'd be overwriting someone else's stuff)
|
||||||
|
tty.warn("Keeping existing install prefix in place.")
|
||||||
|
raise
|
||||||
|
except StopIteration as e:
|
||||||
|
# A StopIteration exception means that do_install
|
||||||
|
# was asked to stop early from clients
|
||||||
|
tty.msg(e.message)
|
||||||
|
tty.msg(
|
||||||
|
'Package stage directory : {0}'.format(self.stage.source_path)
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
# Remove the install prefix if anything went wrong during install.
|
||||||
if not keep_prefix:
|
if not keep_prefix:
|
||||||
self.remove_prefix()
|
self.remove_prefix()
|
||||||
else:
|
|
||||||
tty.warn("Keeping install prefix in place despite error.",
|
|
||||||
"Spack will think this package is installed. " +
|
|
||||||
"Manually remove this directory to fix:",
|
|
||||||
self.prefix,
|
|
||||||
wrap=False)
|
|
||||||
raise
|
|
||||||
|
|
||||||
# Parent of the build process adds the new package to
|
def _do_install_pop_kwargs(self, kwargs):
|
||||||
# the database, so that we don't need to re-read from file.
|
"""Pops kwargs from do_install before starting the installation
|
||||||
# NOTE: add() implicitly acquires a write-lock
|
|
||||||
spack.installed_db.add(
|
Args:
|
||||||
self.spec, spack.install_layout, explicit=explicit)
|
kwargs:
|
||||||
|
'stop_at': last installation phase to be executed (or None)
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.last_phase = kwargs.pop('stop_at', None)
|
||||||
|
if self.last_phase is not None and self.last_phase not in self.phases:
|
||||||
|
tty.die('\'{0.last_phase}\' is not among the allowed phases for package {0.name}'.format(self)) # NOQA: ignore=E501
|
||||||
|
|
||||||
|
def log(self):
|
||||||
|
# Copy provenance into the install directory on success
|
||||||
|
log_install_path = spack.install_layout.build_log_path(
|
||||||
|
self.spec)
|
||||||
|
env_install_path = spack.install_layout.build_env_path(
|
||||||
|
self.spec)
|
||||||
|
packages_dir = spack.install_layout.build_packages_path(
|
||||||
|
self.spec)
|
||||||
|
|
||||||
|
# Remove first if we're overwriting another build
|
||||||
|
# (can happen with spack setup)
|
||||||
|
try:
|
||||||
|
# log_install_path and env_install_path are inside this
|
||||||
|
shutil.rmtree(packages_dir)
|
||||||
|
except Exception:
|
||||||
|
# FIXME : this potentially catches too many things...
|
||||||
|
pass
|
||||||
|
|
||||||
|
install(self.log_path, log_install_path)
|
||||||
|
install(self.env_path, env_install_path)
|
||||||
|
dump_packages(self.spec, packages_dir)
|
||||||
|
|
||||||
def sanity_check_prefix(self):
|
def sanity_check_prefix(self):
|
||||||
"""This function checks whether install succeeded."""
|
"""This function checks whether install succeeded."""
|
||||||
@@ -1281,13 +1476,6 @@ def setup_dependent_package(self, module, dependent_spec):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
|
||||||
"""
|
|
||||||
Package implementations override this with their own configuration
|
|
||||||
"""
|
|
||||||
raise InstallError("Package %s provides no install method!" %
|
|
||||||
self.name)
|
|
||||||
|
|
||||||
def do_uninstall(self, force=False):
|
def do_uninstall(self, force=False):
|
||||||
if not self.installed:
|
if not self.installed:
|
||||||
# prefix may not exist, but DB may be inconsistent. Try to fix by
|
# prefix may not exist, but DB may be inconsistent. Try to fix by
|
||||||
@@ -1498,6 +1686,16 @@ def rpath_args(self):
|
|||||||
return " ".join("-Wl,-rpath,%s" % p for p in self.rpath)
|
return " ".join("-Wl,-rpath,%s" % p for p in self.rpath)
|
||||||
|
|
||||||
|
|
||||||
|
class Package(PackageBase):
|
||||||
|
phases = ['install']
|
||||||
|
# To be used in UI queries that require to know which
|
||||||
|
# build-system class we are using
|
||||||
|
build_system_class = 'Package'
|
||||||
|
# This will be used as a registration decorator in user
|
||||||
|
# packages, if need be
|
||||||
|
PackageBase.sanity_check('install')(PackageBase.sanity_check_prefix)
|
||||||
|
|
||||||
|
|
||||||
def install_dependency_symlinks(pkg, spec, prefix):
|
def install_dependency_symlinks(pkg, spec, prefix):
|
||||||
"""Execute a dummy install and flatten dependencies"""
|
"""Execute a dummy install and flatten dependencies"""
|
||||||
flatten_dependencies(spec, prefix)
|
flatten_dependencies(spec, prefix)
|
||||||
@@ -1598,166 +1796,6 @@ def _hms(seconds):
|
|||||||
return ' '.join(parts)
|
return ' '.join(parts)
|
||||||
|
|
||||||
|
|
||||||
class StagedPackage(Package):
|
|
||||||
"""A Package subclass where the install() is split up into stages."""
|
|
||||||
|
|
||||||
def install_setup(self):
|
|
||||||
"""Creates a spack_setup.py script to configure the package later."""
|
|
||||||
raise InstallError(
|
|
||||||
"Package %s provides no install_setup() method!" % self.name)
|
|
||||||
|
|
||||||
def install_configure(self):
|
|
||||||
"""Runs the configure process."""
|
|
||||||
raise InstallError(
|
|
||||||
"Package %s provides no install_configure() method!" % self.name)
|
|
||||||
|
|
||||||
def install_build(self):
|
|
||||||
"""Runs the build process."""
|
|
||||||
raise InstallError(
|
|
||||||
"Package %s provides no install_build() method!" % self.name)
|
|
||||||
|
|
||||||
def install_install(self):
|
|
||||||
"""Runs the install process."""
|
|
||||||
raise InstallError(
|
|
||||||
"Package %s provides no install_install() method!" % self.name)
|
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
|
||||||
if 'setup' in self.install_phases:
|
|
||||||
self.install_setup()
|
|
||||||
|
|
||||||
if 'configure' in self.install_phases:
|
|
||||||
self.install_configure()
|
|
||||||
|
|
||||||
if 'build' in self.install_phases:
|
|
||||||
self.install_build()
|
|
||||||
|
|
||||||
if 'install' in self.install_phases:
|
|
||||||
self.install_install()
|
|
||||||
else:
|
|
||||||
# Create a dummy file so the build doesn't fail.
|
|
||||||
# That way, the module file will also be created.
|
|
||||||
with open(os.path.join(prefix, 'dummy'), 'w'):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# stackoverflow.com/questions/12791997/how-do-you-do-a-simple-chmod-x-from-within-python
|
|
||||||
def make_executable(path):
|
|
||||||
mode = os.stat(path).st_mode
|
|
||||||
mode |= (mode & 0o444) >> 2 # copy R bits to X
|
|
||||||
os.chmod(path, mode)
|
|
||||||
|
|
||||||
|
|
||||||
class CMakePackage(StagedPackage):
|
|
||||||
|
|
||||||
def make_make(self):
|
|
||||||
import multiprocessing
|
|
||||||
# number of jobs spack will to build with.
|
|
||||||
jobs = multiprocessing.cpu_count()
|
|
||||||
if not self.parallel:
|
|
||||||
jobs = 1
|
|
||||||
elif self.make_jobs:
|
|
||||||
jobs = self.make_jobs
|
|
||||||
|
|
||||||
make = spack.build_environment.MakeExecutable('make', jobs)
|
|
||||||
return make
|
|
||||||
|
|
||||||
def configure_args(self):
|
|
||||||
"""Returns package-specific arguments to be provided to
|
|
||||||
the configure command.
|
|
||||||
"""
|
|
||||||
return list()
|
|
||||||
|
|
||||||
def configure_env(self):
|
|
||||||
"""Returns package-specific environment under which the
|
|
||||||
configure command should be run.
|
|
||||||
"""
|
|
||||||
return dict()
|
|
||||||
|
|
||||||
def transitive_inc_path(self):
|
|
||||||
return ';'.join(
|
|
||||||
os.path.join(dep, 'include')
|
|
||||||
for dep in os.environ['SPACK_DEPENDENCIES'].split(os.pathsep)
|
|
||||||
)
|
|
||||||
|
|
||||||
def install_setup(self):
|
|
||||||
cmd = [str(which('cmake'))]
|
|
||||||
cmd += spack.build_environment.get_std_cmake_args(self)
|
|
||||||
cmd += ['-DCMAKE_INSTALL_PREFIX=%s' % os.environ['SPACK_PREFIX'],
|
|
||||||
'-DCMAKE_C_COMPILER=%s' % os.environ['SPACK_CC'],
|
|
||||||
'-DCMAKE_CXX_COMPILER=%s' % os.environ['SPACK_CXX'],
|
|
||||||
'-DCMAKE_Fortran_COMPILER=%s' % os.environ['SPACK_FC']]
|
|
||||||
cmd += self.configure_args()
|
|
||||||
|
|
||||||
env = {
|
|
||||||
'PATH': os.environ['PATH'],
|
|
||||||
'SPACK_TRANSITIVE_INCLUDE_PATH': self.transitive_inc_path(),
|
|
||||||
'CMAKE_PREFIX_PATH': os.environ['CMAKE_PREFIX_PATH']
|
|
||||||
}
|
|
||||||
|
|
||||||
setup_fname = 'spconfig.py'
|
|
||||||
with open(setup_fname, 'w') as fout:
|
|
||||||
fout.write(r"""#!%s
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
def cmdlist(str):
|
|
||||||
return list(x.strip().replace("'",'') for x in str.split('\n') if x)
|
|
||||||
env = dict(os.environ)
|
|
||||||
""" % sys.executable)
|
|
||||||
|
|
||||||
env_vars = sorted(list(env.keys()))
|
|
||||||
for name in env_vars:
|
|
||||||
val = env[name]
|
|
||||||
if string.find(name, 'PATH') < 0:
|
|
||||||
fout.write('env[%s] = %s\n' % (repr(name), repr(val)))
|
|
||||||
else:
|
|
||||||
if name == 'SPACK_TRANSITIVE_INCLUDE_PATH':
|
|
||||||
sep = ';'
|
|
||||||
else:
|
|
||||||
sep = ':'
|
|
||||||
|
|
||||||
fout.write('env[%s] = "%s".join(cmdlist("""\n'
|
|
||||||
% (repr(name), sep))
|
|
||||||
for part in string.split(val, sep):
|
|
||||||
fout.write(' %s\n' % part)
|
|
||||||
fout.write('"""))\n')
|
|
||||||
|
|
||||||
fout.write("env['CMAKE_TRANSITIVE_INCLUDE_PATH'] = "
|
|
||||||
"env['SPACK_TRANSITIVE_INCLUDE_PATH'] # Deprecated\n")
|
|
||||||
fout.write('\ncmd = cmdlist("""\n')
|
|
||||||
fout.write('%s\n' % cmd[0])
|
|
||||||
for arg in cmd[1:]:
|
|
||||||
fout.write(' %s\n' % arg)
|
|
||||||
fout.write('""") + sys.argv[1:]\n')
|
|
||||||
fout.write('\nproc = subprocess.Popen(cmd, env=env)\n')
|
|
||||||
fout.write('proc.wait()\n')
|
|
||||||
make_executable(setup_fname)
|
|
||||||
|
|
||||||
def install_configure(self):
|
|
||||||
cmake = which('cmake')
|
|
||||||
with working_dir(self.build_directory, create=True):
|
|
||||||
env = os.environ
|
|
||||||
env.update(self.configure_env())
|
|
||||||
env['SPACK_TRANSITIVE_INCLUDE_PATH'] = self.transitive_inc_path()
|
|
||||||
|
|
||||||
options = self.configure_args()
|
|
||||||
options += spack.build_environment.get_std_cmake_args(self)
|
|
||||||
cmake(self.source_directory, *options)
|
|
||||||
|
|
||||||
def install_build(self):
|
|
||||||
make = self.make_make()
|
|
||||||
with working_dir(self.build_directory, create=False):
|
|
||||||
make()
|
|
||||||
|
|
||||||
def install_install(self):
|
|
||||||
make = self.make_make()
|
|
||||||
with working_dir(self.build_directory, create=False):
|
|
||||||
make('install')
|
|
||||||
|
|
||||||
|
|
||||||
class FetchError(spack.error.SpackError):
|
class FetchError(spack.error.SpackError):
|
||||||
"""Raised when something goes wrong during fetch."""
|
"""Raised when something goes wrong during fetch."""
|
||||||
|
|
||||||
|
@@ -25,28 +25,24 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class Astyle(Package):
|
class Astyle(MakefilePackage):
|
||||||
"""A Free, Fast, and Small Automatic Formatter for C, C++, C++/CLI,
|
"""A Free, Fast, and Small Automatic Formatter for C, C++, C++/CLI,
|
||||||
Objective-C, C#, and Java Source Code.
|
Objective-C, C#, and Java Source Code.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
homepage = "http://astyle.sourceforge.net/"
|
homepage = "http://astyle.sourceforge.net/"
|
||||||
url = "http://downloads.sourceforge.net/project/astyle/astyle/astyle%202.04/astyle_2.04_linux.tar.gz"
|
url = "http://downloads.sourceforge.net/project/astyle/astyle/astyle%202.04/astyle_2.04_linux.tar.gz"
|
||||||
|
|
||||||
version('2.04', '30b1193a758b0909d06e7ee8dd9627f6')
|
version('2.04', '30b1193a758b0909d06e7ee8dd9627f6')
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
parallel = False
|
||||||
|
|
||||||
with working_dir('src'):
|
def build_directory(self):
|
||||||
# we need to edit the makefile in place to set compiler:
|
return join_path(self.stage.source_path, 'build', self.compiler.name)
|
||||||
make_file = join_path(self.stage.source_path,
|
|
||||||
'build', 'gcc', 'Makefile')
|
|
||||||
filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, make_file)
|
|
||||||
|
|
||||||
make('-f',
|
def edit(self, spec, prefix):
|
||||||
make_file,
|
makefile = join_path(self.build_directory(), 'Makefile')
|
||||||
parallel=False)
|
filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, makefile)
|
||||||
|
|
||||||
mkdirp(self.prefix.bin)
|
def install_args(self):
|
||||||
install(join_path(self.stage.source_path, 'src', 'bin', 'astyle'),
|
return ['prefix={0}'.format(prefix)]
|
||||||
self.prefix.bin)
|
|
||||||
|
@@ -25,10 +25,8 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class Autoconf(Package):
|
class Autoconf(AutotoolsPackage):
|
||||||
"""
|
"""Autoconf -- system configuration part of autotools"""
|
||||||
Autoconf -- system configuration part of autotools
|
|
||||||
"""
|
|
||||||
homepage = 'https://www.gnu.org/software/autoconf/'
|
homepage = 'https://www.gnu.org/software/autoconf/'
|
||||||
url = 'http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz'
|
url = 'http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz'
|
||||||
|
|
||||||
@@ -54,8 +52,3 @@ def setup_dependent_package(self, module, dependent_spec):
|
|||||||
'ifnames']
|
'ifnames']
|
||||||
for name in executables:
|
for name in executables:
|
||||||
setattr(module, name, self._make_executable(name))
|
setattr(module, name, self._make_executable(name))
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
|
||||||
configure("--prefix=%s" % prefix)
|
|
||||||
make()
|
|
||||||
make("install")
|
|
||||||
|
@@ -25,16 +25,9 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class Blitz(Package):
|
class Blitz(AutotoolsPackage):
|
||||||
"""N-dimensional arrays for C++"""
|
"""N-dimensional arrays for C++"""
|
||||||
homepage = "http://github.com/blitzpp/blitz"
|
homepage = "http://github.com/blitzpp/blitz"
|
||||||
url = "https://github.com/blitzpp/blitz/tarball/1.0.0"
|
url = "https://github.com/blitzpp/blitz/tarball/1.0.0"
|
||||||
|
|
||||||
version('1.0.0', '9f040b9827fe22228a892603671a77af')
|
version('1.0.0', '9f040b9827fe22228a892603671a77af')
|
||||||
|
|
||||||
# No dependencies
|
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
|
||||||
configure('--prefix=%s' % prefix)
|
|
||||||
make()
|
|
||||||
make("install")
|
|
||||||
|
@@ -25,12 +25,12 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class Gmp(Package):
|
class Gmp(AutotoolsPackage):
|
||||||
"""GMP is a free library for arbitrary precision arithmetic, operating
|
"""GMP is a free library for arbitrary precision arithmetic,
|
||||||
on signed integers, rational numbers, and floating-point numbers."""
|
operating on signed integers, rational numbers, and
|
||||||
|
floating-point numbers."""
|
||||||
homepage = "https://gmplib.org"
|
homepage = "https://gmplib.org"
|
||||||
url = "https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2"
|
url = "https://gmplib.org/download/gmp/gmp-6.0.0a.tar.bz2"
|
||||||
|
|
||||||
version('6.1.1', '4c175f86e11eb32d8bf9872ca3a8e11d')
|
version('6.1.1', '4c175f86e11eb32d8bf9872ca3a8e11d')
|
||||||
version('6.1.0', '86ee6e54ebfc4a90b643a65e402c4048')
|
version('6.1.0', '86ee6e54ebfc4a90b643a65e402c4048')
|
||||||
@@ -39,16 +39,10 @@ class Gmp(Package):
|
|||||||
|
|
||||||
depends_on('m4', type='build')
|
depends_on('m4', type='build')
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
def configure_args(self):
|
||||||
config_args = ['--prefix=' + prefix,
|
args = ['--enable-cxx']
|
||||||
'--enable-cxx']
|
|
||||||
|
|
||||||
# We need this flag if we want all the following checks to pass.
|
# We need this flag if we want all the following checks to pass.
|
||||||
if spec.compiler.name == 'intel':
|
if spec.compiler.name == 'intel':
|
||||||
config_args.append('CXXFLAGS=-no-ftz')
|
args.append('CXXFLAGS=-no-ftz')
|
||||||
|
|
||||||
configure(*config_args)
|
return args
|
||||||
|
|
||||||
make()
|
|
||||||
make('check')
|
|
||||||
make('install')
|
|
||||||
|
@@ -27,10 +27,10 @@
|
|||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
|
|
||||||
class Hdf5(Package):
|
class Hdf5(AutotoolsPackage):
|
||||||
"""HDF5 is a data model, library, and file format for storing and managing
|
"""HDF5 is a data model, library, and file format for storing and managing
|
||||||
data. It supports an unlimited variety of datatypes, and is designed for
|
data. It supports an unlimited variety of datatypes, and is designed for
|
||||||
flexible and efficient I/O and for high volume and complex data.
|
flexible and efficient I/O and for high volume and complex data.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
homepage = "http://www.hdfgroup.org/HDF5/"
|
homepage = "http://www.hdfgroup.org/HDF5/"
|
||||||
@@ -58,17 +58,19 @@ class Hdf5(Package):
|
|||||||
variant('threadsafe', default=False,
|
variant('threadsafe', default=False,
|
||||||
description='Enable thread-safe capabilities')
|
description='Enable thread-safe capabilities')
|
||||||
|
|
||||||
depends_on("mpi", when='+mpi')
|
depends_on('mpi', when='+mpi')
|
||||||
depends_on("szip", when='+szip')
|
depends_on('szip', when='+szip')
|
||||||
depends_on("zlib@1.1.2:")
|
depends_on('zlib@1.1.2:')
|
||||||
|
|
||||||
def validate(self, spec):
|
@AutotoolsPackage.precondition('configure')
|
||||||
|
def validate(self):
|
||||||
"""
|
"""
|
||||||
Checks if incompatible variants have been activated at the same time
|
Checks if incompatible variants have been activated at the same time
|
||||||
|
|
||||||
:param spec: spec of the package
|
:param spec: spec of the package
|
||||||
:raises RuntimeError: in case of inconsistencies
|
:raises RuntimeError: in case of inconsistencies
|
||||||
"""
|
"""
|
||||||
|
spec = self.spec
|
||||||
if '+fortran' in spec and not self.compiler.fc:
|
if '+fortran' in spec and not self.compiler.fc:
|
||||||
msg = 'cannot build a fortran variant without a fortran compiler'
|
msg = 'cannot build a fortran variant without a fortran compiler'
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
@@ -77,8 +79,8 @@ def validate(self, spec):
|
|||||||
msg = 'cannot use variant +threadsafe with either +cxx or +fortran'
|
msg = 'cannot use variant +threadsafe with either +cxx or +fortran'
|
||||||
raise RuntimeError(msg)
|
raise RuntimeError(msg)
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
def configure_args(self):
|
||||||
self.validate(spec)
|
spec = self.spec
|
||||||
# Handle compilation after spec validation
|
# Handle compilation after spec validation
|
||||||
extra_args = []
|
extra_args = []
|
||||||
|
|
||||||
@@ -139,21 +141,13 @@ def install(self, spec, prefix):
|
|||||||
'--disable-hl',
|
'--disable-hl',
|
||||||
])
|
])
|
||||||
|
|
||||||
configure(
|
return ["--with-zlib=%s" % spec['zlib'].prefix] + extra_args
|
||||||
"--prefix=%s" % prefix,
|
|
||||||
"--with-zlib=%s" % spec['zlib'].prefix,
|
|
||||||
*extra_args)
|
|
||||||
make()
|
|
||||||
|
|
||||||
if self.run_tests:
|
def check(self):
|
||||||
make("check")
|
super(Hdf5, self).check()
|
||||||
|
# Build and run a small program to test the installed HDF5 library
|
||||||
make("install")
|
spec = self.spec
|
||||||
self.check_install(spec)
|
print("Checking HDF5 installation...")
|
||||||
|
|
||||||
def check_install(self, spec):
|
|
||||||
"Build and run a small program to test the installed HDF5 library"
|
|
||||||
print "Checking HDF5 installation..."
|
|
||||||
checkdir = "spack-check"
|
checkdir = "spack-check"
|
||||||
with working_dir(checkdir, create=True):
|
with working_dir(checkdir, create=True):
|
||||||
source = r"""
|
source = r"""
|
||||||
@@ -190,15 +184,15 @@ def check_install(self, spec):
|
|||||||
output = ""
|
output = ""
|
||||||
success = output == expected
|
success = output == expected
|
||||||
if not success:
|
if not success:
|
||||||
print "Produced output does not match expected output."
|
print("Produced output does not match expected output.")
|
||||||
print "Expected output:"
|
print("Expected output:")
|
||||||
print '-' * 80
|
print('-' * 80)
|
||||||
print expected
|
print(expected)
|
||||||
print '-' * 80
|
print('-' * 80)
|
||||||
print "Produced output:"
|
print("Produced output:")
|
||||||
print '-' * 80
|
print('-' * 80)
|
||||||
print output
|
print(output)
|
||||||
print '-' * 80
|
print('-' * 80)
|
||||||
raise RuntimeError("HDF5 install check failed")
|
raise RuntimeError("HDF5 install check failed")
|
||||||
shutil.rmtree(checkdir)
|
shutil.rmtree(checkdir)
|
||||||
|
|
||||||
|
@@ -43,7 +43,7 @@ class Ibmisc(CMakePackage):
|
|||||||
depends_on('cmake', type='build')
|
depends_on('cmake', type='build')
|
||||||
depends_on('doxygen', type='build')
|
depends_on('doxygen', type='build')
|
||||||
|
|
||||||
def configure_args(self):
|
def cmake_args(self):
|
||||||
spec = self.spec
|
spec = self.spec
|
||||||
return [
|
return [
|
||||||
'-DUSE_EVERYTRACE=%s' % ('YES' if '+everytrace' in spec else 'NO'),
|
'-DUSE_EVERYTRACE=%s' % ('YES' if '+everytrace' in spec else 'NO'),
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class Lzo(Package):
|
class Lzo(AutotoolsPackage):
|
||||||
"""Real-time data compression library"""
|
"""Real-time data compression library"""
|
||||||
|
|
||||||
homepage = 'https://www.oberhumer.com/opensource/lzo/'
|
homepage = 'https://www.oberhumer.com/opensource/lzo/'
|
||||||
@@ -37,15 +37,8 @@ class Lzo(Package):
|
|||||||
version('2.06', '95380bd4081f85ef08c5209f4107e9f8')
|
version('2.06', '95380bd4081f85ef08c5209f4107e9f8')
|
||||||
version('2.05', 'c67cda5fa191bab761c7cb06fe091e36')
|
version('2.05', 'c67cda5fa191bab761c7cb06fe091e36')
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
def configure_args(self):
|
||||||
configure_args = [
|
return [
|
||||||
'--prefix={0}'.format(prefix),
|
|
||||||
'--disable-dependency-tracking',
|
'--disable-dependency-tracking',
|
||||||
'--enable-shared'
|
'--enable-shared'
|
||||||
]
|
]
|
||||||
configure(*configure_args)
|
|
||||||
make()
|
|
||||||
if self.run_tests:
|
|
||||||
make('check')
|
|
||||||
make('test') # more exhaustive test
|
|
||||||
make('install')
|
|
||||||
|
@@ -25,8 +25,9 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class Openjpeg(Package):
|
class Openjpeg(CMakePackage):
|
||||||
"""OpenJPEG is an open-source JPEG 2000 codec written in C language.
|
"""OpenJPEG is an open-source JPEG 2000 codec written in C language.
|
||||||
|
|
||||||
It has been developed in order to promote the use of JPEG 2000, a
|
It has been developed in order to promote the use of JPEG 2000, a
|
||||||
still-image compression standard from the Joint Photographic
|
still-image compression standard from the Joint Photographic
|
||||||
Experts Group (JPEG).
|
Experts Group (JPEG).
|
||||||
@@ -35,7 +36,7 @@ class Openjpeg(Package):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
homepage = "https://github.com/uclouvain/openjpeg"
|
homepage = "https://github.com/uclouvain/openjpeg"
|
||||||
url = "https://github.com/uclouvain/openjpeg/archive/version.2.1.tar.gz"
|
url = "https://github.com/uclouvain/openjpeg/archive/version.2.1.tar.gz"
|
||||||
|
|
||||||
version('2.1', '3e1c451c087f8462955426da38aa3b3d')
|
version('2.1', '3e1c451c087f8462955426da38aa3b3d')
|
||||||
version('2.0.1', '105876ed43ff7dbb2f90b41b5a43cfa5')
|
version('2.0.1', '105876ed43ff7dbb2f90b41b5a43cfa5')
|
||||||
@@ -44,9 +45,3 @@ class Openjpeg(Package):
|
|||||||
version('1.5.1', 'd774e4b5a0db5f0f171c4fc0aabfa14e')
|
version('1.5.1', 'd774e4b5a0db5f0f171c4fc0aabfa14e')
|
||||||
|
|
||||||
depends_on('cmake', type='build')
|
depends_on('cmake', type='build')
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
|
||||||
cmake('.', *std_cmake_args)
|
|
||||||
|
|
||||||
make()
|
|
||||||
make("install")
|
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class Qhull(Package):
|
class Qhull(CMakePackage):
|
||||||
"""Qhull computes the convex hull, Delaunay triangulation, Voronoi
|
"""Qhull computes the convex hull, Delaunay triangulation, Voronoi
|
||||||
diagram, halfspace intersection about a point, furt hest-site
|
diagram, halfspace intersection about a point, furt hest-site
|
||||||
Delaunay triangulation, and furthest-site Voronoi diagram. The
|
Delaunay triangulation, and furthest-site Voronoi diagram. The
|
||||||
@@ -44,9 +44,3 @@ class Qhull(Package):
|
|||||||
url="http://www.qhull.org/download/qhull-2012.1-src.tgz")
|
url="http://www.qhull.org/download/qhull-2012.1-src.tgz")
|
||||||
|
|
||||||
depends_on('cmake@2.6:', type='build')
|
depends_on('cmake@2.6:', type='build')
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
|
||||||
with working_dir('spack-build', create=True):
|
|
||||||
cmake('..', *std_cmake_args)
|
|
||||||
make()
|
|
||||||
make("install")
|
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
import llnl.util.tty as tty
|
import llnl.util.tty as tty
|
||||||
|
|
||||||
|
|
||||||
class Swiftsim(Package):
|
class Swiftsim(AutotoolsPackage):
|
||||||
"""SPH With Inter-dependent Fine-grained Tasking (SWIFT) provides
|
"""SPH With Inter-dependent Fine-grained Tasking (SWIFT) provides
|
||||||
astrophysicists with a state of the art framework to perform
|
astrophysicists with a state of the art framework to perform
|
||||||
particle based simulations.
|
particle based simulations.
|
||||||
@@ -58,20 +58,15 @@ def setup_environment(self, spack_env, run_env):
|
|||||||
tty.warn('This is needed to clone SWIFT repository')
|
tty.warn('This is needed to clone SWIFT repository')
|
||||||
spack_env.set('GIT_SSL_NO_VERIFY', 1)
|
spack_env.set('GIT_SSL_NO_VERIFY', 1)
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
def autoreconf(self, spec, prefix):
|
||||||
# Generate configure from configure.ac
|
|
||||||
# and Makefile.am
|
|
||||||
libtoolize()
|
libtoolize()
|
||||||
aclocal()
|
aclocal()
|
||||||
autoconf()
|
autoconf()
|
||||||
autogen = Executable('./autogen.sh')
|
autogen = Executable('./autogen.sh')
|
||||||
autogen()
|
autogen()
|
||||||
|
|
||||||
# Configure and install
|
def configure_args(self):
|
||||||
options = ['--prefix=%s' % prefix,
|
return ['--prefix=%s' % self.prefix,
|
||||||
'--enable-mpi' if '+mpi' in spec else '--disable-mpi',
|
'--enable-mpi' if '+mpi' in self.spec else '--disable-mpi',
|
||||||
'--with-metis={0}'.format(spec['metis'].prefix),
|
'--with-metis={0}'.format(self.spec['metis'].prefix),
|
||||||
'--enable-optimization']
|
'--enable-optimization']
|
||||||
configure(*options)
|
|
||||||
make()
|
|
||||||
make("install")
|
|
||||||
|
@@ -25,24 +25,21 @@
|
|||||||
from spack import *
|
from spack import *
|
||||||
|
|
||||||
|
|
||||||
class Szip(Package):
|
class Szip(AutotoolsPackage):
|
||||||
"""An implementation of the extended-Rice lossless compression algorithm.
|
"""Szip is an implementation of the extended-Rice lossless
|
||||||
It provides lossless compression of scientific data, and is provided
|
compression algorithm.
|
||||||
with HDF software products.
|
|
||||||
|
|
||||||
|
It provides lossless compression of scientific data, and is
|
||||||
|
provided with HDF software products.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
homepage = "https://www.hdfgroup.org/doc_resource/SZIP/"
|
homepage = "https://www.hdfgroup.org/doc_resource/SZIP/"
|
||||||
url = "http://www.hdfgroup.org/ftp/lib-external/szip/2.1/src/szip-2.1.tar.gz"
|
url = "http://www.hdfgroup.org/ftp/lib-external/szip/2.1/src/szip-2.1.tar.gz"
|
||||||
|
|
||||||
version('2.1', '902f831bcefb69c6b635374424acbead')
|
version('2.1', '902f831bcefb69c6b635374424acbead')
|
||||||
|
|
||||||
def install(self, spec, prefix):
|
def configure_args(self):
|
||||||
configure('--prefix=%s' % prefix,
|
return ['--enable-production',
|
||||||
'--enable-production',
|
'--enable-shared',
|
||||||
'--enable-shared',
|
'--enable-static',
|
||||||
'--enable-static',
|
'--enable-encoding']
|
||||||
'--enable-encoding')
|
|
||||||
|
|
||||||
make()
|
|
||||||
make("install")
|
|
||||||
|
Reference in New Issue
Block a user