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.
|
||||
"""
|
||||
import sys
|
||||
import multiprocessing
|
||||
import os
|
||||
import re
|
||||
import select
|
||||
import inspect
|
||||
import sys
|
||||
|
||||
import llnl.util.tty as tty
|
||||
import llnl.util.tty.color as color
|
||||
@@ -100,25 +100,29 @@ def __exit__(self, exc_type, exception, traceback):
|
||||
|
||||
|
||||
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:
|
||||
with log_output(open('logfile.txt', 'w')):
|
||||
# do things ... output will be logged.
|
||||
# Spawns the daemon
|
||||
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:
|
||||
with log_output(open('logfile.txt', 'w'), echo=True):
|
||||
# do things ... output will be logged
|
||||
# and also printed to stdout.
|
||||
with log_output('logfile.txt', echo=True) as log_redirection:
|
||||
# do things ... output is not redirected
|
||||
with log_redirection:
|
||||
# do things ... output will be logged
|
||||
# and also printed to stdout.
|
||||
|
||||
Closes the provided stream when done with the block.
|
||||
If echo is True, also prints the output to stdout.
|
||||
Opens a stream in 'w' mode at daemon spawning and closes it at
|
||||
daemon joining. If echo is True, also prints the output to stdout.
|
||||
"""
|
||||
|
||||
def __init__(self, stream, echo=False, force_color=False, debug=False):
|
||||
self.stream = stream
|
||||
|
||||
# various output options
|
||||
def __init__(self, filename, echo=False, force_color=False, debug=False):
|
||||
self.filename = filename
|
||||
# Various output options
|
||||
self.echo = echo
|
||||
self.force_color = force_color
|
||||
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
|
||||
# out/err streams do not have an associated file descriptor
|
||||
self.directAssignment = False
|
||||
self.read, self.write = os.pipe()
|
||||
|
||||
def trace(self, frame, event, arg):
|
||||
"""Jumps to __exit__ on the child process."""
|
||||
raise _SkipWithBlock()
|
||||
# Sets a daemon that writes to file what it reads from a pipe
|
||||
self.p = multiprocessing.Process(
|
||||
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):
|
||||
"""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
|
||||
and stderr redirected back to the parent via a pipe. If
|
||||
echo is set, also writes to standard out.
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
self.parent_pipe.send(True)
|
||||
self.p.join(60.0) # 1 minute to join the child
|
||||
|
||||
"""
|
||||
# remember these values for later.
|
||||
self._force_color = color._force_color
|
||||
self._debug = tty._debug
|
||||
def _spawn_writing_daemon(self, read):
|
||||
# Parent: read from child, skip the with block.
|
||||
read_file = os.fdopen(read, 'r', 0)
|
||||
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()
|
||||
if self.pid:
|
||||
# Parent: read from child, skip the with block.
|
||||
os.close(write)
|
||||
|
||||
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:
|
||||
# Handle output from the with block process.
|
||||
if read_file in rlist:
|
||||
line = read_file.readline()
|
||||
if not line:
|
||||
# For some reason we never reach this point...
|
||||
break
|
||||
|
||||
# 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
|
||||
# Echo to stdout if requested.
|
||||
if self.echo:
|
||||
sys.stdout.write(line)
|
||||
|
||||
# handle output from the with block process.
|
||||
if read_file in rlist:
|
||||
line = read_file.readline()
|
||||
if not line:
|
||||
break
|
||||
# Stripped output to log file.
|
||||
log_file.write(_strip(line))
|
||||
log_file.flush()
|
||||
|
||||
# Echo to stdout if requested.
|
||||
if self.echo:
|
||||
sys.stdout.write(line)
|
||||
if self.child_pipe.poll():
|
||||
break
|
||||
|
||||
# Stripped output to log file.
|
||||
log_file.write(_strip(line))
|
||||
def __del__(self):
|
||||
"""Closes the pipes"""
|
||||
os.close(self.write)
|
||||
os.close(self.read)
|
||||
|
||||
read_file.flush()
|
||||
read_file.close()
|
||||
class OutputRedirection(object):
|
||||
|
||||
# Set a trace function to skip the with block.
|
||||
sys.settrace(lambda *args, **keys: None)
|
||||
frame = inspect.currentframe(1)
|
||||
frame.f_trace = self.trace
|
||||
def __init__(self, other):
|
||||
self.__dict__.update(other.__dict__)
|
||||
|
||||
else:
|
||||
# Child: redirect output, execute the with block.
|
||||
os.close(read)
|
||||
def __enter__(self):
|
||||
"""Redirect output from the with block to a file.
|
||||
|
||||
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:
|
||||
# Save old stdout and stderr
|
||||
self._stdout = os.dup(sys.stdout.fileno())
|
||||
@@ -205,53 +220,26 @@ def __enter__(self):
|
||||
output_redirect = os.fdopen(write, 'w')
|
||||
sys.stdout = output_redirect
|
||||
sys.stderr = output_redirect
|
||||
|
||||
if self.force_color:
|
||||
color._force_color = True
|
||||
|
||||
if self.debug:
|
||||
tty._debug = True
|
||||
|
||||
def __exit__(self, exc_type, exception, traceback):
|
||||
"""Exits on child, handles skipping the with block on parent."""
|
||||
# Child should just exit here.
|
||||
if self.pid == 0:
|
||||
def __exit__(self, exc_type, exception, traceback):
|
||||
"""Plugs back the original file descriptors
|
||||
for stdout and stderr
|
||||
"""
|
||||
# Flush the log to disk.
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
if exception:
|
||||
# Restore stdout on the child if there's an exception,
|
||||
# and let it be raised normally.
|
||||
#
|
||||
# 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
|
||||
|
||||
if self.directAssignment:
|
||||
# We seem to need this only to pass test/install.py
|
||||
sys.stdout = self._stdout
|
||||
sys.stderr = self._stderr
|
||||
else:
|
||||
# Die quietly if there was no exception.
|
||||
os._exit(0)
|
||||
os.dup2(self._stdout, sys.stdout.fileno())
|
||||
os.dup2(self._stderr, sys.stderr.fileno())
|
||||
|
||||
else:
|
||||
# If the child exited badly, parent also should exit.
|
||||
pid, returncode = os.waitpid(self.pid, 0)
|
||||
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
|
||||
# restore output options.
|
||||
color._force_color = self._force_color
|
||||
tty._debug = self._debug
|
||||
|
@@ -186,10 +186,19 @@
|
||||
# packages should live. This file is overloaded for spack core vs.
|
||||
# for packages.
|
||||
#
|
||||
__all__ = ['Package', 'StagedPackage', 'CMakePackage',
|
||||
'Version', 'when', 'ver', 'alldeps', 'nolink']
|
||||
__all__ = ['Package',
|
||||
'CMakePackage',
|
||||
'AutotoolsPackage',
|
||||
'MakefilePackage',
|
||||
'Version',
|
||||
'when',
|
||||
'ver',
|
||||
'alldeps',
|
||||
'nolink']
|
||||
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.spec import DependencySpec, alldeps, nolink
|
||||
from spack.multimethod import when
|
||||
|
@@ -51,16 +51,14 @@
|
||||
Skimming this module is a nice way to get acquainted with the types of
|
||||
calls you can make from within the install() function.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import multiprocessing
|
||||
import platform
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import *
|
||||
|
||||
import spack
|
||||
from llnl.util.filesystem import *
|
||||
from spack.environment import EnvironmentModifications, validate
|
||||
from spack.util.environment import *
|
||||
from spack.util.executable import Executable, which
|
||||
@@ -351,8 +349,8 @@ def set_module_variables_for_package(pkg, module):
|
||||
m.cmake = Executable('cmake')
|
||||
m.ctest = Executable('ctest')
|
||||
|
||||
# standard CMake arguments
|
||||
m.std_cmake_args = get_std_cmake_args(pkg)
|
||||
# Standard CMake arguments
|
||||
m.std_cmake_args = spack.CMakePackage._std_args(pkg)
|
||||
|
||||
# Put spack compiler paths in module scope.
|
||||
link_dir = spack.build_env_path
|
||||
@@ -522,41 +520,26 @@ def child_fun():
|
||||
carries on.
|
||||
"""
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
def child_execution(child_connection):
|
||||
try:
|
||||
# call the forked function.
|
||||
setup_package(pkg, dirty=dirty)
|
||||
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,
|
||||
# which interferes with unit tests.
|
||||
os._exit(0)
|
||||
|
||||
except spack.error.SpackError as e:
|
||||
e.die()
|
||||
|
||||
except:
|
||||
# Child doesn't raise or return to main spack code.
|
||||
# Just runs default exception handler and exits.
|
||||
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))
|
||||
parent_connection, child_connection = multiprocessing.Pipe()
|
||||
p = multiprocessing.Process(
|
||||
target=child_execution,
|
||||
args=(child_connection,)
|
||||
)
|
||||
p.start()
|
||||
exc_type, exception, traceback = parent_connection.recv()
|
||||
p.join()
|
||||
if exception is not None:
|
||||
raise exception
|
||||
|
||||
|
||||
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
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import string
|
||||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
|
||||
from ordereddict_backport import OrderedDict
|
||||
import llnl.util.tty as tty
|
||||
from llnl.util.filesystem import mkdirp
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
import spack.cmd.checksum
|
||||
import spack.url
|
||||
import spack.util.web
|
||||
from spack.spec import Spec
|
||||
from spack.util.naming import *
|
||||
from llnl.util.filesystem import mkdirp
|
||||
from ordereddict_backport import OrderedDict
|
||||
from spack.repository import Repo, RepoError
|
||||
|
||||
from spack.spec import Spec
|
||||
from spack.util.executable import which
|
||||
|
||||
from spack.util.naming import *
|
||||
|
||||
description = "Create a new package file from an archive URL"
|
||||
|
||||
@@ -87,7 +86,7 @@
|
||||
from spack import *
|
||||
|
||||
|
||||
class ${class_name}(Package):
|
||||
class ${class_name}(${base_class_name}):
|
||||
""\"FIXME: Put a proper description of your package here.""\"
|
||||
|
||||
# FIXME: Add a proper url for your package's homepage here.
|
||||
@@ -98,109 +97,160 @@ class ${class_name}(Package):
|
||||
|
||||
${dependencies}
|
||||
|
||||
def install(self, spec, prefix):
|
||||
${install}
|
||||
${body}
|
||||
""")
|
||||
|
||||
# Build dependencies and extensions
|
||||
dependencies_dict = {
|
||||
'autotools': """\
|
||||
|
||||
class DefaultGuess(object):
|
||||
"""Provides the default values to be used for the package file template"""
|
||||
base_class_name = 'Package'
|
||||
|
||||
dependencies = """\
|
||||
# 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.
|
||||
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.
|
||||
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.
|
||||
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')
|
||||
|
||||
# FIXME: Add additional dependencies if required.
|
||||
# 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')
|
||||
|
||||
# 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')
|
||||
|
||||
# FIXME: Add additional dependencies if required.
|
||||
# depends_on('octave-foo', type=nolink)""",
|
||||
# depends_on('octave-foo', type=nolink)"""
|
||||
|
||||
'unknown': """\
|
||||
# FIXME: Add dependencies if required.
|
||||
# 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': """\
|
||||
body = """\
|
||||
def install(self, spec, prefix):
|
||||
# FIXME: Add logic to build and install here.
|
||||
octave('--quiet', '--norc',
|
||||
'--built-in-docstrings-file=/dev/null',
|
||||
'--texi-macros-file=/dev/null',
|
||||
'--eval', 'pkg prefix {0}; pkg install {1}'.format(
|
||||
prefix, self.stage.archive_file))""",
|
||||
prefix, self.stage.archive_file))"""
|
||||
|
||||
'unknown': """\
|
||||
# FIXME: Unknown build system
|
||||
make()
|
||||
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 __init__(self, name, *args):
|
||||
name = 'octave-{0}'.format(name)
|
||||
super(OctaveGuess, self).__init__(name, *args)
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
@@ -227,6 +277,16 @@ def setup_parser(subparser):
|
||||
|
||||
class BuildSystemGuesser(object):
|
||||
|
||||
_choices = {
|
||||
'autotools': AutotoolsGuess,
|
||||
'cmake': CMakeGuess,
|
||||
'scons': SconsGuess,
|
||||
'bazel': BazelGuess,
|
||||
'python': PythonGuess,
|
||||
'R': RGuess,
|
||||
'octave': OctaveGuess
|
||||
}
|
||||
|
||||
def __call__(self, stage, url):
|
||||
"""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."""
|
||||
@@ -275,6 +335,10 @@ def __call__(self, stage, url):
|
||||
|
||||
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):
|
||||
# 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),
|
||||
*spack.cmd.elide_list(
|
||||
["%-10s%s" % (v, u) for v, u in versions.iteritems()]))
|
||||
print
|
||||
print('')
|
||||
archives_to_fetch = tty.get_number(
|
||||
"Include how many checksums in the package file?",
|
||||
default=5, abort='q')
|
||||
@@ -389,16 +453,10 @@ def create(parser, args):
|
||||
if not ver_hash_tuples:
|
||||
tty.die("Could not fetch any tarballs for %s" % name)
|
||||
|
||||
# Add prefix to package name if it is an extension.
|
||||
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)
|
||||
guess = guesser.make_guess(name, url, ver_hash_tuples)
|
||||
|
||||
# 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:
|
||||
tty.die("%s already exists." % pkg_path)
|
||||
else:
|
||||
@@ -408,12 +466,15 @@ def create(parser, args):
|
||||
with open(pkg_path, "w") as pkg_file:
|
||||
pkg_file.write(
|
||||
package_template.substitute(
|
||||
name=name,
|
||||
class_name=mod_to_class(name),
|
||||
url=url,
|
||||
versions=make_version_calls(ver_hash_tuples),
|
||||
dependencies=dependencies_dict[guesser.build_system],
|
||||
install=install_dict[guesser.build_system]))
|
||||
name=guess.name,
|
||||
class_name=guess.class_name,
|
||||
base_class_name=guess.base_class_name,
|
||||
url=guess.url,
|
||||
versions=guess.versions,
|
||||
dependencies=guess.dependencies,
|
||||
body=guess.body
|
||||
)
|
||||
)
|
||||
|
||||
# If everything checks out, go ahead and edit.
|
||||
spack.editor(pkg_path)
|
||||
|
@@ -48,8 +48,11 @@ def setup_parser(subparser):
|
||||
|
||||
def print_text_info(pkg):
|
||||
"""Print out a plain text description of a package."""
|
||||
print "Package: ", pkg.name
|
||||
print "Homepage: ", pkg.homepage
|
||||
header = "{0}: ".format(pkg.build_system_class)
|
||||
|
||||
print header, pkg.name
|
||||
whitespaces = ''.join([' '] * (len(header) - len("Homepage: ")))
|
||||
print "Homepage:", whitespaces, pkg.homepage
|
||||
|
||||
print
|
||||
print "Safe versions: "
|
||||
@@ -84,6 +87,13 @@ def print_text_info(pkg):
|
||||
|
||||
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'):
|
||||
print
|
||||
print "%s Dependencies:" % deptype.capitalize()
|
||||
@@ -94,7 +104,7 @@ def print_text_info(pkg):
|
||||
print " None"
|
||||
|
||||
print
|
||||
print "Virtual packages: "
|
||||
print "Virtual Packages: "
|
||||
if pkg.provided:
|
||||
for spec, when in pkg.provided.items():
|
||||
print " %s provides %s" % (when, spec)
|
||||
|
@@ -22,7 +22,6 @@
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
from __future__ import print_function
|
||||
import argparse
|
||||
|
||||
import llnl.util.tty as tty
|
||||
@@ -75,7 +74,7 @@ def setup_parser(subparser):
|
||||
help="Run tests during installation of a package.")
|
||||
|
||||
|
||||
def install(parser, args):
|
||||
def install(parser, args, **kwargs):
|
||||
if not args.package:
|
||||
tty.die("install requires at least one package argument")
|
||||
|
||||
@@ -88,7 +87,7 @@ def install(parser, args):
|
||||
|
||||
# Parse cli arguments and construct a dictionary
|
||||
# that will be passed to Package.do_install API
|
||||
kwargs = {
|
||||
kwargs.update({
|
||||
'keep_prefix': args.keep_prefix,
|
||||
'keep_stage': args.keep_stage,
|
||||
'install_deps': 'dependencies' in args.things_to_install,
|
||||
@@ -97,7 +96,7 @@ def install(parser, args):
|
||||
'verbose': args.verbose,
|
||||
'fake': args.fake,
|
||||
'dirty': args.dirty
|
||||
}
|
||||
})
|
||||
|
||||
# Spec from cli
|
||||
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,
|
||||
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import sys
|
||||
import os
|
||||
import argparse
|
||||
import os
|
||||
import string
|
||||
import sys
|
||||
|
||||
import llnl.util.tty as tty
|
||||
|
||||
import spack
|
||||
import spack.cmd
|
||||
from spack import which
|
||||
from spack.cmd.edit import edit_package
|
||||
from spack.stage import DIYStage
|
||||
from llnl.util.filesystem import set_executable
|
||||
|
||||
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.")
|
||||
|
||||
|
||||
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):
|
||||
if not args.spec:
|
||||
tty.die("spack setup requires a package spec argument.")
|
||||
@@ -80,6 +148,12 @@ def setup(self, args):
|
||||
|
||||
spec.concretize()
|
||||
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.
|
||||
|
||||
@@ -89,10 +163,4 @@ def setup(self, args):
|
||||
# TODO: make this an argument, not a global.
|
||||
spack.do_checksum = False
|
||||
|
||||
package.do_install(
|
||||
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)
|
||||
write_spconfig(package)
|
||||
|
@@ -26,6 +26,7 @@
|
||||
import sys
|
||||
import llnl.util.tty as tty
|
||||
import spack
|
||||
import inspect
|
||||
|
||||
|
||||
class SpackError(Exception):
|
||||
@@ -49,7 +50,7 @@ def die(self):
|
||||
else:
|
||||
tty.error(self.message)
|
||||
if self.long_message:
|
||||
print self.long_message
|
||||
print(self.long_message)
|
||||
os._exit(1)
|
||||
|
||||
def __str__(self):
|
||||
@@ -58,6 +59,16 @@ def __str__(self):
|
||||
msg += "\n %s" % self._long_message
|
||||
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):
|
||||
"""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
|
||||
README.
|
||||
"""
|
||||
import contextlib
|
||||
import copy
|
||||
import functools
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
import time
|
||||
import string
|
||||
import contextlib
|
||||
from StringIO import StringIO
|
||||
|
||||
import llnl.util.lock
|
||||
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.build_environment
|
||||
import spack.compilers
|
||||
import spack.directives
|
||||
import spack.error
|
||||
@@ -60,20 +56,188 @@
|
||||
import spack.repository
|
||||
import spack.url
|
||||
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.util.crypto import bit_length
|
||||
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 import directory_layout
|
||||
|
||||
|
||||
"""Allowed URL schemes for spack packages."""
|
||||
_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.
|
||||
|
||||
***The Package class***
|
||||
@@ -309,7 +473,7 @@ class SomePackage(Package):
|
||||
Package creators override functions like install() (all of them do this),
|
||||
clean() (some of them do this), and others to provide custom behavior.
|
||||
"""
|
||||
|
||||
__metaclass__ = PackageMeta
|
||||
#
|
||||
# These are default values for instance variables.
|
||||
#
|
||||
@@ -344,12 +508,6 @@ class SomePackage(Package):
|
||||
"""Per-process lock objects for each install prefix."""
|
||||
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):
|
||||
# this determines how the package should be built.
|
||||
self.spec = spec
|
||||
@@ -429,6 +587,8 @@ def __init__(self, spec):
|
||||
if self.is_extension:
|
||||
spack.repo.get(self.extendee_spec)._check_extendable()
|
||||
|
||||
self.extra_args = {}
|
||||
|
||||
def possible_dependencies(self, visited=None):
|
||||
"""Return set of possible transitive dependencies of this package."""
|
||||
if visited is None:
|
||||
@@ -886,12 +1046,34 @@ def namespace(self):
|
||||
return namespace
|
||||
|
||||
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)
|
||||
touch(join_path(self.prefix.bin, 'fake'))
|
||||
mkdirp(self.prefix.lib)
|
||||
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):
|
||||
resources = []
|
||||
# Select the resources that are needed for this build
|
||||
@@ -925,13 +1107,10 @@ def _prefix_write_lock(self):
|
||||
finally:
|
||||
self.prefix_lock.release_write()
|
||||
|
||||
install_phases = set(['configure', 'build', 'install', 'provenance'])
|
||||
|
||||
def do_install(self,
|
||||
keep_prefix=False,
|
||||
keep_stage=False,
|
||||
install_deps=True,
|
||||
install_self=True,
|
||||
skip_patch=False,
|
||||
verbose=False,
|
||||
make_jobs=None,
|
||||
@@ -939,7 +1118,7 @@ def do_install(self,
|
||||
fake=False,
|
||||
explicit=False,
|
||||
dirty=False,
|
||||
install_phases=install_phases):
|
||||
**kwargs):
|
||||
"""Called by commands to install a package and its dependencies.
|
||||
|
||||
Package implementations should override install() to describe
|
||||
@@ -975,9 +1154,7 @@ def do_install(self,
|
||||
# Ensure package is not already installed
|
||||
layout = spack.install_layout
|
||||
with self._prefix_read_lock():
|
||||
if ('install' in install_phases and
|
||||
layout.check_installed(self.spec)):
|
||||
|
||||
if layout.check_installed(self.spec):
|
||||
tty.msg(
|
||||
"%s is already installed in %s" % (self.name, self.prefix))
|
||||
rec = spack.installed_db.get_record(self.spec)
|
||||
@@ -987,6 +1164,8 @@ def do_install(self,
|
||||
rec.explicit = True
|
||||
return
|
||||
|
||||
self._do_install_pop_kwargs(kwargs)
|
||||
|
||||
tty.msg("Installing %s" % self.name)
|
||||
|
||||
# First, install dependencies recursively.
|
||||
@@ -1009,7 +1188,6 @@ def do_install(self,
|
||||
# Set parallelism before starting build.
|
||||
self.make_jobs = make_jobs
|
||||
|
||||
# ------------------- BEGIN def build_process()
|
||||
# Then install the package itself.
|
||||
def build_process():
|
||||
"""Forked for each build. Has its own process and python
|
||||
@@ -1022,112 +1200,129 @@ def build_process():
|
||||
else:
|
||||
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.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()):
|
||||
# Run the pre-install hook in the child process after
|
||||
# the directory is created.
|
||||
spack.hooks.pre_install(self)
|
||||
|
||||
if fake:
|
||||
self.do_fake_install()
|
||||
else:
|
||||
# Do the real install in the source directory.
|
||||
self.stage.chdir_to_source()
|
||||
|
||||
# Save the build environment in a file before building.
|
||||
env_path = join_path(os.getcwd(), 'spack-build.env')
|
||||
|
||||
try:
|
||||
try:
|
||||
with contextlib.nested(self.stage, self._prefix_write_lock()):
|
||||
# Run the pre-install hook in the child process after
|
||||
# the directory is created.
|
||||
spack.hooks.pre_install(self)
|
||||
if fake:
|
||||
self.do_fake_install()
|
||||
else:
|
||||
# Do the real install in the source directory.
|
||||
self.stage.chdir_to_source()
|
||||
# Save the build environment in a file before building.
|
||||
env_path = join_path(os.getcwd(), 'spack-build.env')
|
||||
# Redirect I/O to a build log (and optionally to
|
||||
# the terminal)
|
||||
log_path = join_path(os.getcwd(), 'spack-build.out')
|
||||
log_file = open(log_path, 'w')
|
||||
with log_output(log_file, verbose, sys.stdout.isatty(),
|
||||
True):
|
||||
dump_environment(env_path)
|
||||
self.install(self.spec, self.prefix)
|
||||
# FIXME : refactor this assignment
|
||||
self.log_path = log_path
|
||||
self.env_path = env_path
|
||||
dump_environment(env_path)
|
||||
# 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:
|
||||
# Annotate ProcessErrors with the location of
|
||||
# the build log
|
||||
e.build_log = log_path
|
||||
raise e
|
||||
# Stop timer.
|
||||
self._total_time = time.time() - start_time
|
||||
build_time = self._total_time - self._fetch_time
|
||||
|
||||
# Ensure that something was actually installed.
|
||||
if 'install' in self.install_phases:
|
||||
self.sanity_check_prefix()
|
||||
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)
|
||||
|
||||
# Copy provenance into the install directory on success
|
||||
if 'provenance' in self.install_phases:
|
||||
log_install_path = layout.build_log_path(self.spec)
|
||||
env_install_path = layout.build_env_path(self.spec)
|
||||
packages_dir = 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 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()
|
||||
except ProcessError as e:
|
||||
# Annotate ProcessErrors with the location of
|
||||
# the build log
|
||||
e.build_log = log_path
|
||||
raise e
|
||||
|
||||
try:
|
||||
# Create the install prefix and fork the build process.
|
||||
spack.install_layout.create_install_directory(self.spec)
|
||||
except directory_layout.InstallDirectoryAlreadyExistsError:
|
||||
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:
|
||||
# Fork a child to do the actual installation
|
||||
spack.build_environment.fork(self, build_process, dirty=dirty)
|
||||
except:
|
||||
# remove the install prefix if anything went wrong during install.
|
||||
# If we installed then we should keep the prefix
|
||||
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:
|
||||
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
|
||||
# the database, so that we don't need to re-read from file.
|
||||
# NOTE: add() implicitly acquires a write-lock
|
||||
spack.installed_db.add(
|
||||
self.spec, spack.install_layout, explicit=explicit)
|
||||
def _do_install_pop_kwargs(self, kwargs):
|
||||
"""Pops kwargs from do_install before starting the installation
|
||||
|
||||
Args:
|
||||
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):
|
||||
"""This function checks whether install succeeded."""
|
||||
@@ -1281,13 +1476,6 @@ def setup_dependent_package(self, module, dependent_spec):
|
||||
"""
|
||||
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):
|
||||
if not self.installed:
|
||||
# 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)
|
||||
|
||||
|
||||
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):
|
||||
"""Execute a dummy install and flatten dependencies"""
|
||||
flatten_dependencies(spec, prefix)
|
||||
@@ -1598,166 +1796,6 @@ def _hms(seconds):
|
||||
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):
|
||||
"""Raised when something goes wrong during fetch."""
|
||||
|
||||
|
@@ -25,28 +25,24 @@
|
||||
from spack import *
|
||||
|
||||
|
||||
class Astyle(Package):
|
||||
class Astyle(MakefilePackage):
|
||||
"""A Free, Fast, and Small Automatic Formatter for C, C++, C++/CLI,
|
||||
Objective-C, C#, and Java Source Code.
|
||||
"""
|
||||
|
||||
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')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
parallel = False
|
||||
|
||||
with working_dir('src'):
|
||||
# we need to edit the makefile in place to set compiler:
|
||||
make_file = join_path(self.stage.source_path,
|
||||
'build', 'gcc', 'Makefile')
|
||||
filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, make_file)
|
||||
def build_directory(self):
|
||||
return join_path(self.stage.source_path, 'build', self.compiler.name)
|
||||
|
||||
make('-f',
|
||||
make_file,
|
||||
parallel=False)
|
||||
def edit(self, spec, prefix):
|
||||
makefile = join_path(self.build_directory(), 'Makefile')
|
||||
filter_file(r'^CXX\s*=.*', 'CXX=%s' % spack_cxx, makefile)
|
||||
|
||||
mkdirp(self.prefix.bin)
|
||||
install(join_path(self.stage.source_path, 'src', 'bin', 'astyle'),
|
||||
self.prefix.bin)
|
||||
def install_args(self):
|
||||
return ['prefix={0}'.format(prefix)]
|
||||
|
@@ -25,10 +25,8 @@
|
||||
from spack import *
|
||||
|
||||
|
||||
class Autoconf(Package):
|
||||
"""
|
||||
Autoconf -- system configuration part of autotools
|
||||
"""
|
||||
class Autoconf(AutotoolsPackage):
|
||||
"""Autoconf -- system configuration part of autotools"""
|
||||
homepage = 'https://www.gnu.org/software/autoconf/'
|
||||
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']
|
||||
for name in executables:
|
||||
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 *
|
||||
|
||||
|
||||
class Blitz(Package):
|
||||
class Blitz(AutotoolsPackage):
|
||||
"""N-dimensional arrays for C++"""
|
||||
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')
|
||||
|
||||
# No dependencies
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure('--prefix=%s' % prefix)
|
||||
make()
|
||||
make("install")
|
||||
|
@@ -25,12 +25,12 @@
|
||||
from spack import *
|
||||
|
||||
|
||||
class Gmp(Package):
|
||||
"""GMP is a free library for arbitrary precision arithmetic, operating
|
||||
on signed integers, rational numbers, and floating-point numbers."""
|
||||
|
||||
class Gmp(AutotoolsPackage):
|
||||
"""GMP is a free library for arbitrary precision arithmetic,
|
||||
operating on signed integers, rational numbers, and
|
||||
floating-point numbers."""
|
||||
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.0', '86ee6e54ebfc4a90b643a65e402c4048')
|
||||
@@ -39,16 +39,10 @@ class Gmp(Package):
|
||||
|
||||
depends_on('m4', type='build')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
config_args = ['--prefix=' + prefix,
|
||||
'--enable-cxx']
|
||||
|
||||
def configure_args(self):
|
||||
args = ['--enable-cxx']
|
||||
# We need this flag if we want all the following checks to pass.
|
||||
if spec.compiler.name == 'intel':
|
||||
config_args.append('CXXFLAGS=-no-ftz')
|
||||
args.append('CXXFLAGS=-no-ftz')
|
||||
|
||||
configure(*config_args)
|
||||
|
||||
make()
|
||||
make('check')
|
||||
make('install')
|
||||
return args
|
||||
|
@@ -27,10 +27,10 @@
|
||||
import shutil
|
||||
|
||||
|
||||
class Hdf5(Package):
|
||||
class Hdf5(AutotoolsPackage):
|
||||
"""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
|
||||
flexible and efficient I/O and for high volume and complex data.
|
||||
data. It supports an unlimited variety of datatypes, and is designed for
|
||||
flexible and efficient I/O and for high volume and complex data.
|
||||
"""
|
||||
|
||||
homepage = "http://www.hdfgroup.org/HDF5/"
|
||||
@@ -58,17 +58,19 @@ class Hdf5(Package):
|
||||
variant('threadsafe', default=False,
|
||||
description='Enable thread-safe capabilities')
|
||||
|
||||
depends_on("mpi", when='+mpi')
|
||||
depends_on("szip", when='+szip')
|
||||
depends_on("zlib@1.1.2:")
|
||||
depends_on('mpi', when='+mpi')
|
||||
depends_on('szip', when='+szip')
|
||||
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
|
||||
|
||||
:param spec: spec of the package
|
||||
:raises RuntimeError: in case of inconsistencies
|
||||
"""
|
||||
spec = self.spec
|
||||
if '+fortran' in spec and not self.compiler.fc:
|
||||
msg = 'cannot build a fortran variant without a fortran compiler'
|
||||
raise RuntimeError(msg)
|
||||
@@ -77,8 +79,8 @@ def validate(self, spec):
|
||||
msg = 'cannot use variant +threadsafe with either +cxx or +fortran'
|
||||
raise RuntimeError(msg)
|
||||
|
||||
def install(self, spec, prefix):
|
||||
self.validate(spec)
|
||||
def configure_args(self):
|
||||
spec = self.spec
|
||||
# Handle compilation after spec validation
|
||||
extra_args = []
|
||||
|
||||
@@ -139,21 +141,13 @@ def install(self, spec, prefix):
|
||||
'--disable-hl',
|
||||
])
|
||||
|
||||
configure(
|
||||
"--prefix=%s" % prefix,
|
||||
"--with-zlib=%s" % spec['zlib'].prefix,
|
||||
*extra_args)
|
||||
make()
|
||||
return ["--with-zlib=%s" % spec['zlib'].prefix] + extra_args
|
||||
|
||||
if self.run_tests:
|
||||
make("check")
|
||||
|
||||
make("install")
|
||||
self.check_install(spec)
|
||||
|
||||
def check_install(self, spec):
|
||||
"Build and run a small program to test the installed HDF5 library"
|
||||
print "Checking HDF5 installation..."
|
||||
def check(self):
|
||||
super(Hdf5, self).check()
|
||||
# Build and run a small program to test the installed HDF5 library
|
||||
spec = self.spec
|
||||
print("Checking HDF5 installation...")
|
||||
checkdir = "spack-check"
|
||||
with working_dir(checkdir, create=True):
|
||||
source = r"""
|
||||
@@ -190,15 +184,15 @@ def check_install(self, spec):
|
||||
output = ""
|
||||
success = output == expected
|
||||
if not success:
|
||||
print "Produced output does not match expected output."
|
||||
print "Expected output:"
|
||||
print '-' * 80
|
||||
print expected
|
||||
print '-' * 80
|
||||
print "Produced output:"
|
||||
print '-' * 80
|
||||
print output
|
||||
print '-' * 80
|
||||
print("Produced output does not match expected output.")
|
||||
print("Expected output:")
|
||||
print('-' * 80)
|
||||
print(expected)
|
||||
print('-' * 80)
|
||||
print("Produced output:")
|
||||
print('-' * 80)
|
||||
print(output)
|
||||
print('-' * 80)
|
||||
raise RuntimeError("HDF5 install check failed")
|
||||
shutil.rmtree(checkdir)
|
||||
|
||||
|
@@ -43,7 +43,7 @@ class Ibmisc(CMakePackage):
|
||||
depends_on('cmake', type='build')
|
||||
depends_on('doxygen', type='build')
|
||||
|
||||
def configure_args(self):
|
||||
def cmake_args(self):
|
||||
spec = self.spec
|
||||
return [
|
||||
'-DUSE_EVERYTRACE=%s' % ('YES' if '+everytrace' in spec else 'NO'),
|
||||
|
@@ -25,7 +25,7 @@
|
||||
from spack import *
|
||||
|
||||
|
||||
class Lzo(Package):
|
||||
class Lzo(AutotoolsPackage):
|
||||
"""Real-time data compression library"""
|
||||
|
||||
homepage = 'https://www.oberhumer.com/opensource/lzo/'
|
||||
@@ -37,15 +37,8 @@ class Lzo(Package):
|
||||
version('2.06', '95380bd4081f85ef08c5209f4107e9f8')
|
||||
version('2.05', 'c67cda5fa191bab761c7cb06fe091e36')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure_args = [
|
||||
'--prefix={0}'.format(prefix),
|
||||
def configure_args(self):
|
||||
return [
|
||||
'--disable-dependency-tracking',
|
||||
'--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 *
|
||||
|
||||
|
||||
class Openjpeg(Package):
|
||||
class Openjpeg(CMakePackage):
|
||||
"""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
|
||||
still-image compression standard from the Joint Photographic
|
||||
Experts Group (JPEG).
|
||||
@@ -35,7 +36,7 @@ class Openjpeg(Package):
|
||||
"""
|
||||
|
||||
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.0.1', '105876ed43ff7dbb2f90b41b5a43cfa5')
|
||||
@@ -44,9 +45,3 @@ class Openjpeg(Package):
|
||||
version('1.5.1', 'd774e4b5a0db5f0f171c4fc0aabfa14e')
|
||||
|
||||
depends_on('cmake', type='build')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
cmake('.', *std_cmake_args)
|
||||
|
||||
make()
|
||||
make("install")
|
||||
|
@@ -25,7 +25,7 @@
|
||||
from spack import *
|
||||
|
||||
|
||||
class Qhull(Package):
|
||||
class Qhull(CMakePackage):
|
||||
"""Qhull computes the convex hull, Delaunay triangulation, Voronoi
|
||||
diagram, halfspace intersection about a point, furt hest-site
|
||||
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")
|
||||
|
||||
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
|
||||
|
||||
|
||||
class Swiftsim(Package):
|
||||
class Swiftsim(AutotoolsPackage):
|
||||
"""SPH With Inter-dependent Fine-grained Tasking (SWIFT) provides
|
||||
astrophysicists with a state of the art framework to perform
|
||||
particle based simulations.
|
||||
@@ -58,20 +58,15 @@ def setup_environment(self, spack_env, run_env):
|
||||
tty.warn('This is needed to clone SWIFT repository')
|
||||
spack_env.set('GIT_SSL_NO_VERIFY', 1)
|
||||
|
||||
def install(self, spec, prefix):
|
||||
# Generate configure from configure.ac
|
||||
# and Makefile.am
|
||||
def autoreconf(self, spec, prefix):
|
||||
libtoolize()
|
||||
aclocal()
|
||||
autoconf()
|
||||
autogen = Executable('./autogen.sh')
|
||||
autogen()
|
||||
|
||||
# Configure and install
|
||||
options = ['--prefix=%s' % prefix,
|
||||
'--enable-mpi' if '+mpi' in spec else '--disable-mpi',
|
||||
'--with-metis={0}'.format(spec['metis'].prefix),
|
||||
'--enable-optimization']
|
||||
configure(*options)
|
||||
make()
|
||||
make("install")
|
||||
def configure_args(self):
|
||||
return ['--prefix=%s' % self.prefix,
|
||||
'--enable-mpi' if '+mpi' in self.spec else '--disable-mpi',
|
||||
'--with-metis={0}'.format(self.spec['metis'].prefix),
|
||||
'--enable-optimization']
|
||||
|
@@ -25,24 +25,21 @@
|
||||
from spack import *
|
||||
|
||||
|
||||
class Szip(Package):
|
||||
"""An implementation of the extended-Rice lossless compression algorithm.
|
||||
It provides lossless compression of scientific data, and is provided
|
||||
with HDF software products.
|
||||
class Szip(AutotoolsPackage):
|
||||
"""Szip is an implementation of the extended-Rice lossless
|
||||
compression algorithm.
|
||||
|
||||
It provides lossless compression of scientific data, and is
|
||||
provided with HDF software products.
|
||||
"""
|
||||
|
||||
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')
|
||||
|
||||
def install(self, spec, prefix):
|
||||
configure('--prefix=%s' % prefix,
|
||||
'--enable-production',
|
||||
'--enable-shared',
|
||||
'--enable-static',
|
||||
'--enable-encoding')
|
||||
|
||||
make()
|
||||
make("install")
|
||||
def configure_args(self):
|
||||
return ['--enable-production',
|
||||
'--enable-shared',
|
||||
'--enable-static',
|
||||
'--enable-encoding']
|
||||
|
Reference in New Issue
Block a user