summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/spack/spack/build_environment.py56
-rw-r--r--lib/spack/spack/package.py39
2 files changed, 63 insertions, 32 deletions
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index cabde7dc86..84d2bd77ef 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -28,6 +28,7 @@ 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
@@ -212,3 +213,58 @@ def setup_package(pkg):
for dep_spec in pkg.spec.traverse(root=False):
dep_spec.package.setup_dependent_environment(
pkg.module, dep_spec, pkg.spec)
+
+
+def fork(pkg, function):
+ """Fork a child process to do part of a spack build.
+
+ Arguments:
+
+ pkg -- pkg whose environemnt we should set up the
+ forked process for.
+ function -- arg-less function to run in the child process.
+
+ Usage:
+ def child_fun():
+ # do stuff
+ build_env.fork(pkg, child_fun)
+
+ Forked processes are run with the build environemnt set up by
+ spack.build_environment. This allows package authors to have
+ full control over the environment, etc. without offecting
+ other builds that might be executed in the same spack call.
+
+ If something goes wrong, the child process is expected toprint
+ the error and the parent process will exit with error as
+ well. If things go well, the child exits and the parent
+ carries on.
+ """
+ try:
+ pid = os.fork()
+ except OSError, e:
+ raise InstallError("Unable to fork build process: %s" % e)
+
+ if pid == 0:
+ # Give the child process the package's build environemnt.
+ setup_package(pkg)
+
+ try:
+ # call the forked function.
+ function()
+
+ # Use os._exit here to avoid raising a SystemExit exception,
+ # which interferes with unit tests.
+ os._exit(0)
+ 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:
+ sys.exit(1)
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index c48816cb5b..5d04fed8ff 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -804,32 +804,21 @@ class Package(object):
if not fake_install:
self.do_patch()
- # Fork a child process to do the build. This allows each
- # package authors to have full control over their environment,
- # etc. without offecting other builds that might be executed
- # in the same spack call.
- try:
- pid = os.fork()
- except OSError, e:
- raise InstallError("Unable to fork build process: %s" % e)
+ # create the install directory. The install layout
+ # handles this in case so that it can use whatever
+ # package naming scheme it likes.
+ spack.install_layout.make_path_for_spec(self.spec)
- if pid == 0:
+ def real_work():
try:
tty.msg("Building %s." % self.name)
- # create the install directory. The install layout
- # handles this in case so that it can use whatever
- # package naming scheme it likes.
- spack.install_layout.make_path_for_spec(self.spec)
-
# Run the pre-install hook in the child process after
# the directory is created.
spack.hooks.pre_install(self)
# Set up process's build environment before running install.
self.stage.chdir_to_source()
- build_env.setup_package(self)
-
if fake_install:
self.do_fake_install()
else:
@@ -852,10 +841,6 @@ class Package(object):
% (_hms(self._fetch_time), _hms(build_time), _hms(self._total_time)))
print_pkg(self.prefix)
- # Use os._exit here to avoid raising a SystemExit exception,
- # which interferes with unit tests.
- os._exit(0)
-
except:
if not keep_prefix:
# If anything goes wrong, remove the install prefix
@@ -865,24 +850,14 @@ class Package(object):
"Spack will think this package is installed." +
"Manually remove this directory to fix:",
self.prefix)
+ raise
- # 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)
-
- # 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:
- sys.exit(1)
+ build_env.fork(self, real_work)
# Once everything else is done, run post install hooks
spack.hooks.post_install(self)
-
def _sanity_check_install(self):
installed = set(os.listdir(self.prefix))
installed.difference_update(spack.install_layout.hidden_file_paths)