diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index cabde7dc86ef59867a2cd4c220997d08a6443d76..84d2bd77ef336f892b547a11533be30e9e3bb18a 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -28,6 +28,7 @@
 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 c48816cb5b6989661a17b708c7bbc2fa76c3d2de..5d04fed8ffdb880cb421c20d23693b304b534418 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -804,32 +804,21 @@ def do_install(self, **kwargs):
         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 @@ def do_install(self, **kwargs):
                         % (_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 @@ def do_install(self, **kwargs):
                              "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)