diff --git a/bin/spack b/bin/spack
index 354754594e60f8afd3099ea291e850db2f9d199b..5c042edd2d7b0f776bc67af2a96693e1b08a5811 100755
--- a/bin/spack
+++ b/bin/spack
@@ -126,14 +126,7 @@ def main():
     try:
         return_val = command(parser, args)
     except SpackError, e:
-        if spack.debug:
-            # In debug mode, raise with a full stack trace.
-            raise
-        elif e.long_message:
-            tty.die(e.message, e.long_message)
-        else:
-            tty.die(e.message)
-
+        e.die()
     except KeyboardInterrupt:
         sys.stderr.write('\n')
         tty.die("Keyboard interrupt.")
diff --git a/lib/spack/llnl/util/filesystem.py b/lib/spack/llnl/util/filesystem.py
index 3b34e04740603206f85b172ccce38566d91f29a0..029a7536dfb4a20b90c8b78a4fb55e2a45b2f3a2 100644
--- a/lib/spack/llnl/util/filesystem.py
+++ b/lib/spack/llnl/util/filesystem.py
@@ -25,7 +25,7 @@
 __all__ = ['set_install_permissions', 'install', 'install_tree', 'traverse_tree',
            'expand_user', 'working_dir', 'touch', 'touchp', 'mkdirp',
            'force_remove', 'join_path', 'ancestor', 'can_access', 'filter_file',
-           'change_sed_delimiter', 'is_exe', 'force_symlink']
+           'FileFilter', 'change_sed_delimiter', 'is_exe', 'force_symlink']
 
 import os
 import sys
@@ -40,7 +40,6 @@
 import llnl.util.tty as tty
 from spack.util.compression import ALLOWED_ARCHIVE_TYPES
 
-
 def filter_file(regex, repl, *filenames, **kwargs):
     """Like sed, but uses python regular expressions.
 
@@ -97,6 +96,15 @@ def groupid_to_group(x):
                 shutil.rmtree(backup, ignore_errors=True)
 
 
+class FileFilter(object):
+    """Convenience class for calling filter_file a lot."""
+    def __init__(self, *filenames):
+        self.filenames = filenames
+
+    def filter(self, regex, repl, **kwargs):
+        return filter_file(regex, repl, *self.filenames, **kwargs)
+
+
 def change_sed_delimiter(old_delim, new_delim, *filenames):
     """Find all sed search/replace commands and change the delimiter.
        e.g., if the file contains seds that look like 's///', you can
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index f9e795ac4237ae5b774c18c2cbd0728acc0a3647..81fbedc68974af46768d0b05a6916992a1189e38 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -280,6 +280,10 @@ def child_fun():
             # Use os._exit here to avoid raising a SystemExit exception,
             # which interferes with unit tests.
             os._exit(0)
+
+        except spack.error.SpackError, e:
+            e.die()
+
         except:
             # Child doesn't raise or return to main spack code.
             # Just runs default exception handler and exits.
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
index 15e886ad3c3be2f70eb57111d44866ec1091e7d9..2e1d5d7f03dde4d30d60211f0c8034273850d809 100644
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -75,7 +75,23 @@ def concretize_version(self, spec):
         if valid_versions:
             spec.versions = ver([valid_versions[-1]])
         else:
-            raise NoValidVersionError(spec)
+            # We don't know of any SAFE versions that match the given
+            # spec.  Grab the spec's versions and grab the highest
+            # *non-open* part of the range of versions it specifies.
+            # Someone else can raise an error if this happens,
+            # e.g. when we go to fetch it and don't know how.  But it
+            # *might* work.
+            if not spec.versions or spec.versions == VersionList([':']):
+                raise NoValidVersionError(spec)
+            else:
+                last = spec.versions[-1]
+                if isinstance(last, VersionRange):
+                    if last.end:
+                        spec.versions = ver([last.end])
+                    else:
+                        spec.versions = ver([last.start])
+                else:
+                    spec.versions = ver([last])
 
 
     def concretize_architecture(self, spec):
@@ -174,8 +190,8 @@ def __init__(self, compiler_spec):
 
 
 class NoValidVersionError(spack.error.SpackError):
-    """Raised when there is no available version for a package that
-       satisfies a spec."""
+    """Raised when there is no way to have a concrete version for a
+       particular spec."""
     def __init__(self, spec):
         super(NoValidVersionError, self).__init__(
-            "No available version of %s matches '%s'" % (spec.name, spec.versions))
+            "There are no valid versions for %s that match '%s'" % (spec.name, spec.versions))
diff --git a/lib/spack/spack/error.py b/lib/spack/spack/error.py
index e8fa75668279336009211dcbfab4d04842a59ae1..bfa7951a473ebddc1d5e98d25546cf14f45793a1 100644
--- a/lib/spack/spack/error.py
+++ b/lib/spack/spack/error.py
@@ -22,6 +22,10 @@
 # along with this program; if not, write to the Free Software Foundation,
 # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ##############################################################################
+import os
+import sys
+import llnl.util.tty as tty
+import spack
 
 class SpackError(Exception):
     """This is the superclass for all Spack errors.
@@ -38,6 +42,17 @@ def long_message(self):
         return self._long_message
 
 
+    def die(self):
+        if spack.debug:
+            sys.excepthook(*sys.exc_info())
+            os._exit(1)
+        else:
+            tty.error(self.message)
+            if self.long_message:
+                print self.long_message
+            os._exit(1)
+
+
     def __str__(self):
         msg = self.message
         if self.long_message:
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 5dd410d0e4122e25ae83528992444b7c9e93e9df..5abf2a6bb3aa0f2e03228a1e618a4bcb41e89ed0 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -471,13 +471,18 @@ def extendee_spec(self):
         """Spec of the extendee of this package, or None if it is not an extension."""
         if not self.extendees:
             return None
+
+        # TODO: allow more than one extendee.
         name = next(iter(self.extendees))
-        if not name in self.spec:
-            spec, kwargs = self.extendees[name]
-            return spec
 
-        # Need to do this to get the concrete version of the spec
-        return self.spec[name]
+        # If the extendee is in the spec's deps already, return that.
+        for dep in self.spec.traverse():
+            if name == dep.name:
+                return dep
+
+        # Otherwise return the spec from the extends() directive
+        spec, kwargs = self.extendees[name]
+        return spec
 
 
     @property
@@ -542,7 +547,7 @@ def preorder_traversal(self, visited=None, **kwargs):
 
     def provides(self, vpkg_name):
         """True if this package provides a virtual package with the specified name."""
-        return vpkg_name in self.provided
+        return any(s.name == vpkg_name for s in self.provided)
 
 
     def virtual_dependencies(self, visited=None):
@@ -561,8 +566,11 @@ def installed_dependents(self):
            on this one."""
         dependents = []
         for spec in spack.db.installed_package_specs():
-            if self.name != spec.name and self.spec in spec:
-                dependents.append(spec)
+            if self.name == spec.name:
+                continue
+            for dep in spec.traverse():
+                if spec == dep:
+                    dependents.append(spec)
         return dependents
 
 
@@ -816,17 +824,8 @@ def real_work():
             except ProcessError, e:
                 # Annotate with location of build log.
                 e.build_log = log_path
-
-                # One of the processes returned an error code.
-                # Suppress detailed stack trace here unless in debug mode
-                if spack.debug:
-                    raise e
-                else:
-                    tty.error(e)
-
-                # Still need to clean up b/c there was an error.
                 cleanup()
-                os._exit(1)
+                raise e
 
             except:
                 # other exceptions just clean up and raise.
@@ -994,10 +993,13 @@ def do_deactivate(self, **kwargs):
 
             activated = spack.install_layout.extension_map(self.extendee_spec)
             for name, aspec in activated.items():
-                if aspec != self.spec and self.spec in aspec:
-                    raise ActivationError(
-                        "Cannot deactivate %s beacuse %s is activated and depends on it."
-                        % (self.spec.short_spec, aspec.short_spec))
+                if aspec == self.spec:
+                    continue
+                for dep in aspec.traverse():
+                    if self.spec == dep:
+                        raise ActivationError(
+                            "Cannot deactivate %s beacuse %s is activated and depends on it."
+                            % (self.spec.short_spec, aspec.short_spec))
 
         self.extendee_spec.package.deactivate(self, **self.extendee_args)
 
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index aa13f0422c95459a11e9641d21d5f2dde7fc1cd2..5876fc6cf8d26fe143ce8522133b2ecf8d8a235b 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -498,7 +498,13 @@ def virtual(self):
            Possible idea: just use conventin and make virtual deps all
            caps, e.g., MPI vs mpi.
         """
-        return not spack.db.exists(self.name)
+        return Spec.is_virtual(self.name)
+
+
+    @staticmethod
+    def is_virtual(name):
+        """Test if a name is virtual without requiring a Spec."""
+        return not spack.db.exists(name)
 
 
     @property
@@ -1224,7 +1230,17 @@ def satisfies(self, other, deps=True, strict=False):
         """
         other = self._autospec(other)
 
-        # First thing we care about is whether the name matches
+        # A concrete provider can satisfy a virtual dependency.
+        if not self.virtual and other.virtual:
+            pkg = spack.db.get(self.name)
+            if pkg.provides(other.name):
+                for provided, when_spec in pkg.provided.items():
+                    if self.satisfies(when_spec, deps=False, strict=strict):
+                        if provided.satisfies(other):
+                            return True
+            return False
+
+        # Otherwise, first thing we care about is whether the name matches
         if self.name != other.name:
             return False
 
@@ -1364,11 +1380,21 @@ def version(self):
 
 
     def __getitem__(self, name):
-        """TODO: reconcile __getitem__, _add_dependency, __contains__"""
+        """Get a dependency from the spec by its name."""
         for spec in self.traverse():
             if spec.name == name:
                 return spec
 
+        if Spec.is_virtual(name):
+            # TODO: this is a kind of kludgy way to find providers
+            # TODO: should we just keep virtual deps in the DAG instead of
+            # TODO: removing them on concretize?
+            for spec in self.traverse():
+                if spec.virtual:
+                    continue
+                if spec.package.provides(name):
+                    return spec
+
         raise KeyError("No spec with name %s in %s" % (name, self))
 
 
@@ -1380,6 +1406,7 @@ def __contains__(self, spec):
         for s in self.traverse():
             if s.satisfies(spec, strict=True):
                 return True
+
         return False
 
 
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index cc839a23405918749aee70f230c0a1a3e117ac22..b3a77d076a16575bc2082d5227707674fae45a18 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -152,7 +152,10 @@ def test_virtual_is_fully_expanded_for_callpath(self):
         spec.concretize()
 
         self.assertTrue('zmpi' in spec.dependencies)
-        self.assertFalse('mpi' in spec)
+        self.assertTrue(all(not 'mpi' in d.dependencies for d in spec.traverse()))
+        self.assertTrue('zmpi' in spec)
+        self.assertTrue('mpi' in spec)
+
         self.assertTrue('fake' in spec.dependencies['zmpi'])
 
 
@@ -168,7 +171,9 @@ def test_virtual_is_fully_expanded_for_mpileaks(self):
         self.assertTrue('zmpi' in spec.dependencies['callpath'].dependencies)
         self.assertTrue('fake' in spec.dependencies['callpath'].dependencies['zmpi'].dependencies)
 
-        self.assertFalse('mpi' in spec)
+        self.assertTrue(all(not 'mpi' in d.dependencies for d in spec.traverse()))
+        self.assertTrue('zmpi' in spec)
+        self.assertTrue('mpi' in spec)
 
 
     def test_my_dep_depends_on_provider_of_my_virtual_dep(self):
diff --git a/lib/spack/spack/test/directory_layout.py b/lib/spack/spack/test/directory_layout.py
index beac03841083b1d328bf8ba0e947a57a1624bb3b..b3ad8efec4b783ea0c8448d882fb5b2104a8b36f 100644
--- a/lib/spack/spack/test/directory_layout.py
+++ b/lib/spack/spack/test/directory_layout.py
@@ -167,12 +167,15 @@ def test_handle_unknown_package(self):
     def test_find(self):
         """Test that finding specs within an install layout works."""
         packages = list(spack.db.all_packages())[:max_packages]
+
+        # Create install prefixes for all packages in the list
         installed_specs = {}
         for pkg in packages:
             spec = pkg.spec.concretized()
             installed_specs[spec.name] = spec
             self.layout.create_install_directory(spec)
 
+        # Make sure all the installed specs appear in DirectoryLayout.all_specs()
         found_specs = dict((s.name, s) for s in self.layout.all_specs())
         for name, spec in found_specs.items():
             self.assertTrue(name in found_specs)
diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py
index 20df2603f5b3416ef1b06652e2891c194dc56271..6666dbbb52c794c21e530a2762c365ec5281708f 100644
--- a/lib/spack/spack/test/spec_semantics.py
+++ b/lib/spack/spack/test/spec_semantics.py
@@ -189,6 +189,67 @@ def test_unsatisfiable_variant_mismatch(self):
         self.check_unsatisfiable('mpich+foo', 'mpich~foo')
 
 
+    def test_satisfies_virtual(self):
+        self.assertTrue(Spec('mpich').satisfies(Spec('mpi')))
+        self.assertTrue(Spec('mpich2').satisfies(Spec('mpi')))
+        self.assertTrue(Spec('zmpi').satisfies(Spec('mpi')))
+
+
+    # ================================================================================
+    # Indexing specs
+    # ================================================================================
+    def test_self_index(self):
+        s = Spec('callpath')
+        self.assertTrue(s['callpath'] == s)
+
+
+    def test_dep_index(self):
+        s = Spec('callpath')
+        s.normalize()
+
+        self.assertTrue(s['callpath'] == s)
+        self.assertTrue(type(s['dyninst']) == Spec)
+        self.assertTrue(type(s['libdwarf']) == Spec)
+        self.assertTrue(type(s['libelf']) == Spec)
+        self.assertTrue(type(s['mpi']) == Spec)
+
+        self.assertTrue(s['dyninst'].name  == 'dyninst')
+        self.assertTrue(s['libdwarf'].name == 'libdwarf')
+        self.assertTrue(s['libelf'].name   == 'libelf')
+        self.assertTrue(s['mpi'].name      == 'mpi')
+
+
+    def test_spec_contains_deps(self):
+        s = Spec('callpath')
+        s.normalize()
+        self.assertTrue('dyninst' in s)
+        self.assertTrue('libdwarf' in s)
+        self.assertTrue('libelf' in s)
+        self.assertTrue('mpi' in s)
+
+
+    def test_virtual_index(self):
+        s = Spec('callpath')
+        s.concretize()
+
+        s_mpich = Spec('callpath ^mpich')
+        s_mpich.concretize()
+
+        s_mpich2 = Spec('callpath ^mpich2')
+        s_mpich2.concretize()
+
+        s_zmpi = Spec('callpath ^zmpi')
+        s_zmpi.concretize()
+
+
+        self.assertTrue(s['mpi'].name != 'mpi')
+        self.assertTrue(s_mpich['mpi'].name == 'mpich')
+        self.assertTrue(s_mpich2['mpi'].name == 'mpich2')
+        self.assertTrue(s_zmpi['zmpi'].name == 'zmpi')
+
+        for spec in [s, s_mpich, s_mpich2, s_zmpi]:
+            self.assertTrue('mpi' in spec)
+
 
     # ================================================================================
     # Constraints
diff --git a/lib/spack/spack/util/executable.py b/lib/spack/spack/util/executable.py
index 6eede0f78e225a48f6a710e97d57df7ae2ad19ba..1dcda0d87f478d777d121ebf87f6adb665349ba2 100644
--- a/lib/spack/spack/util/executable.py
+++ b/lib/spack/spack/util/executable.py
@@ -124,6 +124,11 @@ def __repr__(self):
         return "<exe: %s>" % self.exe
 
 
+    def __str__(self):
+        return ' '.join(self.exe)
+
+
+
 def which(name, **kwargs):
     """Finds an executable in the path like command-line which."""
     path     = kwargs.get('path', os.environ.get('PATH', '').split(os.pathsep))
diff --git a/var/spack/packages/arpack/package.py b/var/spack/packages/arpack/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..8c67c536f32cd86b820bf79039efbc4387cfbec0
--- /dev/null
+++ b/var/spack/packages/arpack/package.py
@@ -0,0 +1,41 @@
+from spack import *
+import os
+import shutil
+
+class Arpack(Package):
+    """A collection of Fortran77 subroutines designed to solve large scale
+       eigenvalue problems.
+    """
+    homepage = "http://www.caam.rice.edu/software/ARPACK/"
+    url      = "http://www.caam.rice.edu/software/ARPACK/SRC/arpack96.tar.gz"
+
+    version('96', 'fffaa970198b285676f4156cebc8626e')
+
+    depends_on('blas')
+    depends_on('lapack')
+
+    def patch(self):
+        # Filter the cray makefile to make a spack one.
+        shutil.move('ARMAKES/ARmake.CRAY', 'ARmake.inc')
+        makefile = FileFilter('ARmake.inc')
+
+        # Be sure to use Spack F77 wrapper
+        makefile.filter('^FC.*', 'FC = f77')
+        makefile.filter('^FFLAGS.*', 'FFLAGS = -O2 -g')
+
+        # Set up some variables.
+        makefile.filter('^PLAT.*',      'PLAT = ')
+        makefile.filter('^home.*',    'home = %s' % os.getcwd())
+        makefile.filter('^BLASdir.*',   'BLASdir = %s' % self.spec['blas'].prefix)
+        makefile.filter('^LAPACKdir.*', 'LAPACKdir = %s' % self.spec['lapack'].prefix)
+
+        # build the library in our own prefix.
+        makefile.filter('^ARPACKLIB.*', 'ARPACKLIB = %s/libarpack.a' % os.getcwd())
+
+
+    def install(self, spec, prefix):
+        with working_dir('SRC'):
+            make('all')
+
+        mkdirp(prefix.lib)
+        install('libarpack.a', prefix.lib)
diff --git a/var/spack/packages/atlas/package.py b/var/spack/packages/atlas/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..fc683363a70dc6217fd98b64271dce26e5d0a223
--- /dev/null
+++ b/var/spack/packages/atlas/package.py
@@ -0,0 +1,60 @@
+from spack import *
+from spack.util.executable import Executable
+import os
+
+class Atlas(Package):
+    """
+    Automatically Tuned Linear Algebra Software, generic shared
+    ATLAS is an approach for the automatic generation and optimization of
+    numerical software. Currently ATLAS supplies optimized versions for the
+    complete set of linear algebra kernels known as the Basic Linear Algebra
+    Subroutines (BLAS), and a subset of the linear algebra routines in the
+    LAPACK library.
+    """
+    homepage = "http://math-atlas.sourceforge.net/"
+
+    version('3.11.34', '0b6c5389c095c4c8785fd0f724ec6825',
+            url='http://sourceforge.net/projects/math-atlas/files/Developer%20%28unstable%29/3.11.34/atlas3.11.34.tar.bz2/download')
+    version('3.10.2', 'a4e21f343dec8f22e7415e339f09f6da',
+            url='http://downloads.sourceforge.net/project/math-atlas/Stable/3.10.2/atlas3.10.2.tar.bz2')
+
+    # TODO: make this provide BLAS once it works better.  Create a way
+    # TODO: to mark "beta" packages and require explicit invocation.
+
+    # provides('blas')
+
+
+    def patch(self):
+        # Disable thraed check.  LLNL's environment does not allow
+        # disabling of CPU throttling in a way that ATLAS actually
+        # understands.
+        filter_file(r'^\s+if \(thrchk\) exit\(1\);', 'if (0) exit(1);',
+                    'CONFIG/src/config.c')
+        # TODO: investigate a better way to add the check back in
+        # TODO: using, say, MSRs.  Or move this to a variant.
+
+    @when('@:3.10')
+    def install(self, spec, prefix):
+        with working_dir('ATLAS-Build', create=True):
+            configure = Executable('../configure')
+            configure('--prefix=%s' % prefix, '-C', 'ic', 'cc', '-C', 'if', 'f77', "--dylibs")
+            make()
+            make('check')
+            make('ptcheck')
+            make('time')
+            make("install")
+
+
+    def install(self, spec, prefix):
+        with working_dir('ATLAS-Build', create=True):
+            configure = Executable('../configure')
+            configure('--incdir=%s' % prefix.include,
+                      '--libdir=%s' % prefix.lib,
+                      '--cc=cc',
+                      "--shared")
+
+            make()
+            make('check')
+            make('ptcheck')
+            make('time')
+            make("install")
diff --git a/var/spack/packages/boxlib/package.py b/var/spack/packages/boxlib/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..4f1b71132f5a3bd768eca0b7ce6543506c56a241
--- /dev/null
+++ b/var/spack/packages/boxlib/package.py
@@ -0,0 +1,25 @@
+from spack import *
+
+class Boxlib(Package):
+    """BoxLib, a software framework for massively parallel
+       block-structured adaptive mesh refinement (AMR) codes."""
+
+    homepage = "https://ccse.lbl.gov/BoxLib/"
+    url = "https://ccse.lbl.gov/pub/Downloads/BoxLib.git";
+
+    # TODO: figure out how best to version this.  No tags in the repo!
+    version('master', git='https://ccse.lbl.gov/pub/Downloads/BoxLib.git')
+
+    depends_on('mpi')
+
+    def install(self, spec, prefix):
+        args = std_cmake_args
+        args += ['-DCCSE_ENABLE_MPI=1',
+                 '-DCMAKE_C_COMPILER=%s' % which('mpicc'),
+                 '-DCMAKE_CXX_COMPILER=%s' % which('mpicxx'),
+                 '-DCMAKE_Fortran_COMPILER=%s' % which('mpif90')]
+
+        cmake('.', *args)
+        make()
+        make("install")
+
diff --git a/var/spack/packages/cblas/package.py b/var/spack/packages/cblas/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..93cf5fb7b8426df68d746b50bb33f1762b901842
--- /dev/null
+++ b/var/spack/packages/cblas/package.py
@@ -0,0 +1,32 @@
+from spack import *
+import os
+
+class Cblas(Package):
+    """The BLAS (Basic Linear Algebra Subprograms) are routines that
+       provide standard building blocks for performing basic vector and
+       matrix operations."""
+
+    homepage = "http://www.netlib.org/blas/_cblas/"
+
+    # tarball has no version, but on the date below, this MD5 was correct.
+    version('2015-06-06', '1e8830f622d2112239a4a8a83b84209a',
+            url='http://www.netlib.org/blas/blast-forum/cblas.tgz')
+
+    depends_on('blas')
+    parallel = False
+
+    def patch(self):
+        mf = FileFilter('Makefile.in')
+
+        mf.filter('^BLLIB =.*', 'BLLIB = %s/libblas.a' % self.spec['blas'].prefix.lib)
+        mf.filter('^CC =.*', 'CC = cc')
+        mf.filter('^FC =.*', 'FC = f90')
+
+
+    def install(self, spec, prefix):
+        make('all')
+        mkdirp(prefix.lib)
+
+        # Rename the generated lib file to libcblas.a
+        install('./lib/cblas_LINUX.a', '%s/libcblas.a' % prefix.lib)
+
diff --git a/var/spack/packages/cgm/package.py b/var/spack/packages/cgm/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..05d6395c5a293eaffc64c82a80c3fdebfb841b92
--- /dev/null
+++ b/var/spack/packages/cgm/package.py
@@ -0,0 +1,30 @@
+from spack import *
+
+class Cgm(Package):
+    """The Common Geometry Module, Argonne (CGMA) is a code library
+       which provides geometry functionality used for mesh generation and
+       other applications."""
+    homepage = "http://trac.mcs.anl.gov/projects/ITAPS/wiki/CGM"
+    url      = "http://ftp.mcs.anl.gov/pub/fathom/cgm13.1.1.tar.gz"
+
+    version('13.1.1', '4e8dbc4ba8f65767b29f985f7a23b01f')
+    version('13.1.0', 'a6c7b22660f164ce893fb974f9cb2028')
+    version('13.1'  , '95f724bda04919fc76818a5b7bc0b4ed')
+
+    depends_on("mpi")
+
+    def patch(self):
+        filter_file('^(#include "CGMParallelConventions.h")',
+                    '//\1',
+                    'geom/parallel/CGMReadParallel.cpp')
+
+
+    def install(self, spec, prefix):
+        configure("--with-mpi",
+                  "--prefix=%s" % prefix,
+                  "CFLAGS=-static",
+                  "CXXFLAGS=-static",
+                  "FCFLAGS=-static")
+
+        make()
+        make("install")
diff --git a/var/spack/packages/hypre/package.py b/var/spack/packages/hypre/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..198b3f00dcd88303c16383c8ceda03e69ae1e064
--- /dev/null
+++ b/var/spack/packages/hypre/package.py
@@ -0,0 +1,32 @@
+from spack import *
+
+class Hypre(Package):
+    """Hypre is a library of high performance preconditioners that
+       features parallel multigrid methods for both structured and
+       unstructured grid problems."""
+
+    homepage = "https://computation.llnl.gov/project/linear_solvers/software.php"
+    url      = "https://computation.llnl.gov/project/linear_solvers/download/hypre-2.10.0b.tar.gz"
+
+    version('2.10.0b', '768be38793a35bb5d055905b271f5b8e')
+
+    depends_on("mpi")
+    depends_on("blas")
+    depends_on("lapack")
+
+    def install(self, spec, prefix):
+        blas_dir = spec['blas'].prefix
+        lapack_dir = spec['lapack'].prefix
+
+        # Hypre's source is staged under ./src so we'll have to manually
+        # cd into it.
+        with working_dir("src"):
+            configure(
+                "--prefix=%s" % prefix,
+                "--with-blas-libs=blas",
+                "--with-blas-lib-dirs=%s/lib" % blas_dir,
+                "--with-lapack-libs=\"lapack blas\"",
+                "--with-lapack-lib-dirs=%s/lib" % lapack_dir,
+                "--with-MPI")
+            make()
+            make("install")
diff --git a/var/spack/packages/lapack/package.py b/var/spack/packages/lapack/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..d9d37e3e4aa1f20205045da60911d342ac3ada59
--- /dev/null
+++ b/var/spack/packages/lapack/package.py
@@ -0,0 +1,45 @@
+from spack import *
+
+class Lapack(Package):
+    """
+    LAPACK version 3.X is a comprehensive FORTRAN library that does
+    linear algebra operations including matrix inversions, least
+    squared solutions to linear sets of equations, eigenvector
+    analysis, singular value decomposition, etc. It is a very
+    comprehensive and reputable package that has found extensive
+    use in the scientific community.
+    """
+    homepage = "http://www.netlib.org/lapack/"
+    url      = "http://www.netlib.org/lapack/lapack-3.5.0.tgz"
+
+    version('3.5.0', 'b1d3e3e425b2e44a06760ff173104bdf')
+    version('3.4.2', '61bf1a8a4469d4bdb7604f5897179478')
+    version('3.4.1', '44c3869c38c8335c2b9c2a8bb276eb55')
+    version('3.4.0', '02d5706ec03ba885fc246e5fa10d8c70')
+    version('3.3.1', 'd0d533ec9a5b74933c2a1e84eedc58b4')
+
+    # blas is a virtual dependency.
+    depends_on('blas')
+
+    # Doesn't always build correctly in parallel
+    parallel = False
+
+    @when('^netlib-blas')
+    def get_blas_libs(self):
+        blas = self.spec['netlib-blas']
+        return [join_path(blas.prefix.lib, 'blas.a')]
+
+
+    @when('^atlas')
+    def get_blas_libs(self):
+        blas = self.spec['atlas']
+        return [join_path(blas.prefix.lib, l)
+                for l in ('libf77blas.a', 'libatlas.a')]
+
+
+    def install(self, spec, prefix):
+        blas_libs = ";".join(self.get_blas_libs())
+        cmake(".", '-DBLAS_LIBRARIES=' + blas_libs, *std_cmake_args)
+        make()
+        make("install")
+
diff --git a/var/spack/packages/metis/package.py b/var/spack/packages/metis/package.py
index fa13d521274fdc91a382beff533167b9093e4d38..7ce5ae1925d7774ea82b836efef531021aa05893 100644
--- a/var/spack/packages/metis/package.py
+++ b/var/spack/packages/metis/package.py
@@ -5,28 +5,23 @@ class Metis(Package):
        partitioning finite element meshes, and producing fill reducing
        orderings for sparse matrices. The algorithms implemented in
        METIS are based on the multilevel recursive-bisection,
-       multilevel k-way, and multi-constraint partitioning schemes
-       developed in our lab."""
+       multilevel k-way, and multi-constraint partitioning schemes."""
 
     homepage = "http://glaros.dtc.umn.edu/gkhome/metis/metis/overview"
     url      = "http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/metis-5.1.0.tar.gz"
 
     version('5.1.0', '5465e67079419a69e0116de24fce58fe')
 
-    # FIXME: Add dependencies if this package requires them.
-    # depends_on("foo")
-
-    def patch(self):
-        filter_file(r'#define IDXTYPEWIDTH 32', '#define IDXTYPEWIDTH 64', 'include/metis.h',
-                    string=True)
-
+    depends_on('mpi')
 
     def install(self, spec, prefix):
-        with working_dir('spack-build', create=True):
-            cmake('..',
-                  '-DGKLIB_PATH=../GKlib',
-                  '-DBUILD_SHARED_LIBS=TRUE',
-                  *std_cmake_args)
-            make()
-            make("install")
-
+        cmake(".",
+              '-DGKLIB_PATH=%s/GKlib' % pwd(),
+              '-DSHARED=1',
+              '-DCMAKE_C_COMPILER=mpicc',
+              '-DCMAKE_CXX_COMPILER=mpicxx',
+              '-DSHARED=1',
+              *std_cmake_args)
+
+        make()
+        make("install")
diff --git a/var/spack/packages/netlib-blas/package.py b/var/spack/packages/netlib-blas/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..0a6cdb04423c709f5693a93220b586960aff267c
--- /dev/null
+++ b/var/spack/packages/netlib-blas/package.py
@@ -0,0 +1,40 @@
+from spack import *
+import os
+
+
+class NetlibBlas(Package):
+    """Netlib reference BLAS"""
+    homepage = "http://www.netlib.org/lapack/"
+    url      = "http://www.netlib.org/lapack/lapack-3.5.0.tgz"
+
+    version('3.5.0', 'b1d3e3e425b2e44a06760ff173104bdf')
+
+    # virtual dependency
+    provides('blas')
+
+    # Doesn't always build correctly in parallel
+    parallel = False
+
+    def patch(self):
+        os.symlink('make.inc.example', 'make.inc')
+
+        mf = FileFilter('make.inc')
+        mf.filter('^FORTRAN.*', 'FORTRAN = f90')
+        mf.filter('^LOADER.*',  'LOADER = f90')
+        mf.filter('^CC =.*',  'CC = cc')
+
+
+    def install(self, spec, prefix):
+        make('blaslib')
+
+        # Tests that blas builds correctly
+        make('blas_testing')
+
+        # No install provided
+        mkdirp(prefix.lib)
+        install('librefblas.a', prefix.lib)
+
+        # Blas virtual package should provide blas.a and libblas.a
+        with working_dir(prefix.lib):
+            symlink('librefblas.a', 'blas.a')
+            symlink('librefblas.a', 'libblas.a')
diff --git a/var/spack/packages/parpack/package.py b/var/spack/packages/parpack/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..622aceca04f86efde1f6e22577ace0aae975ddac
--- /dev/null
+++ b/var/spack/packages/parpack/package.py
@@ -0,0 +1,43 @@
+from spack import *
+import os
+import shutil
+
+class Parpack(Package):
+    """ARPACK is a collection of Fortran77 subroutines designed to solve large
+       scale eigenvalue problems."""
+
+    homepage = "http://www.caam.rice.edu/software/ARPACK/download.html"
+    url      = "http://www.caam.rice.edu/software/ARPACK/SRC/parpack96.tar.Z"
+
+    version('96', 'a175f70ff71837a33ff7e4b0b6054f43')
+
+    depends_on('mpi')
+    depends_on('blas')
+    depends_on('lapack')
+
+    def patch(self):
+        # Filter the CJ makefile to make a spack one.
+        shutil.move('ARMAKES/ARmake.CJ', 'ARmake.inc')
+        mf = FileFilter('ARmake.inc')
+
+        # Be sure to use Spack F77 wrapper
+        mf.filter('^FC.*',     'FC = f77')
+        mf.filter('^FFLAGS.*', 'FFLAGS = -O2 -g')
+
+        # Set up some variables.
+        mf.filter('^PLAT.*',      'PLAT = ')
+        mf.filter('^home.*',      'home = %s' % os.getcwd())
+        mf.filter('^BLASdir.*',   'BLASdir = %s' % self.spec['blas'].prefix)
+        mf.filter('^LAPACKdir.*', 'LAPACKdir = %s' % self.spec['lapack'].prefix)
+        mf.filter('^MAKE.*',      'MAKE = make')
+
+        # build the library in our own prefix.
+        mf.filter('^ARPACKLIB.*', 'PARPACKLIB = %s/libparpack.a' % os.getcwd())
+
+
+    def install(self, spec, prefix):
+        with working_dir('PARPACK/SRC/MPI'):
+            make('all')
+
+        mkdirp(prefix.lib)
+        install('libparpack.a', prefix.lib)
diff --git a/var/spack/packages/petsc/package.py b/var/spack/packages/petsc/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..4864e39bf188a93e759b387fd9a9528b1990a266
--- /dev/null
+++ b/var/spack/packages/petsc/package.py
@@ -0,0 +1,40 @@
+from spack import *
+
+class Petsc(Package):
+    """PETSc is a suite of data structures and routines for the
+       scalable (parallel) solution of scientific applications modeled by
+       partial differential equations."""
+
+    homepage = "http://www.mcs.anl.gov/petsc/index.html"
+    url      = "http://ftp.mcs.anl.gov/pub/petsc/release-snapshots/petsc-3.5.3.tar.gz"
+
+    version('3.5.3', 'd4fd2734661e89f18ac6014b5dd1ef2f')
+    version('3.5.2', 'ad170802b3b058b5deb9cd1f968e7e13')
+    version('3.5.1', 'a557e029711ebf425544e117ffa44d8f')
+
+    depends_on("boost")
+    depends_on("blas")
+    depends_on("lapack")
+    depends_on("hypre")
+    depends_on("parmetis")
+    depends_on("metis")
+    depends_on("hdf5")
+    depends_on("mpi")
+
+    def install(self, spec, prefix):
+        configure("--prefix=%s" % prefix,
+                  "CC=cc",
+                  "CXX=c++",
+                  "FC=f90",
+                  "--with-blas-lib=%s/libblas.a"     % spec['blas'].prefix.lib,
+                  "--with-lapack-lib=%s/liblapack.a" % spec['lapack'].prefix.lib,
+                  "--with-boost-dir=%s"              % spec['boost'].prefix,
+                  "--with-hypre-dir=%s"              % spec['hypre'].prefix,
+                  "--with-parmetis-dir=%s"           % spec['parmetis'].prefix,
+                  "--with-metis-dir=%s"              % spec['metis'].prefix,
+                  "--with-hdf5-dir=%s"               % spec['hdf5'].prefix,
+                  "--with-shared-libraries=0")
+
+        # PETSc has its own way of doing parallel make.
+        make('MAKE_NP=%s' % make_jobs, parallel=False)
+        make("install")