diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py
index aed42f4a2ce1bec48fda624cf9ef03fe558c461c..7f581dfe29cfa9d54d64ba87fc4204f584d5ac2e 100644
--- a/lib/spack/spack/directory_layout.py
+++ b/lib/spack/spack/directory_layout.py
@@ -9,6 +9,12 @@
 from spack.error import SpackError
 
 
+def _check_concrete(spec):
+    """If the spec is not concrete, raise a ValueError"""
+    if not spec.concrete:
+        raise ValueError('Specs passed to a DirectoryLayout must be concrete!')
+
+
 class DirectoryLayout(object):
     """A directory layout is used to associate unique paths with specs.
        Different installations are going to want differnet layouts for their
@@ -39,7 +45,8 @@ def make_path_for_spec(self, spec):
 
     def path_for_spec(self, spec):
         """Return an absolute path from the root to a directory for the spec."""
-        assert(spec.concrete)
+        _check_concrete(spec)
+
         path = self.relative_path_for_spec(spec)
         assert(not path.startswith(self.root))
         return os.path.join(self.root, path)
@@ -105,7 +112,7 @@ def __init__(self, root, **kwargs):
 
 
     def relative_path_for_spec(self, spec):
-        assert(spec.concrete)
+        _check_concrete(spec)
 
         path = new_path(
             spec.architecture,
@@ -134,7 +141,7 @@ def read_spec(self, path):
 
 
     def make_path_for_spec(self, spec):
-        assert(spec.concrete)
+        _check_concrete(spec)
 
         path = self.path_for_spec(spec)
         spec_file_path = new_path(path, self.spec_file)
@@ -200,5 +207,3 @@ class InstallDirectoryAlreadyExistsError(DirectoryLayoutError):
     def __init__(self, path):
         super(InstallDirectoryAlreadyExistsError, self).__init__(
             "Install path %s already exists!")
-
-
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index cb779c404751641f1ea0903db87ba00ae4243068..acbc7fc927419a42f78ec8f727fb16f38073f5ab 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -67,7 +67,7 @@ class Cmake(Package):
            url       = 'http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz'
            md5       = '097278785da7182ec0aea8769d06860c'
 
-           def install(self, prefix):
+           def install(self, spec, prefix):
                configure('--prefix=%s'   % prefix,
                          '--parallel=%s' % make_jobs)
                make()
@@ -407,27 +407,9 @@ def add_commands_to_module(self):
         m.rmtree     = shutil.rmtree
         m.move       = shutil.move
 
-        # Useful directories within the prefix
+        # Useful directories within the prefix are encapsulated in
+        # a Prefix object.
         m.prefix  = self.prefix
-        m.bin     = new_path(self.prefix, 'bin')
-        m.sbin    = new_path(self.prefix, 'sbin')
-        m.etc     = new_path(self.prefix, 'etc')
-        m.include = new_path(self.prefix, 'include')
-        m.lib     = new_path(self.prefix, 'lib')
-        m.lib64   = new_path(self.prefix, 'lib64')
-        m.libexec = new_path(self.prefix, 'libexec')
-        m.share   = new_path(self.prefix, 'share')
-        m.doc     = new_path(m.share, 'doc')
-        m.info    = new_path(m.share, 'info')
-        m.man     = new_path(m.share, 'man')
-        m.man1    = new_path(m.man, 'man1')
-        m.man2    = new_path(m.man, 'man2')
-        m.man3    = new_path(m.man, 'man3')
-        m.man4    = new_path(m.man, 'man4')
-        m.man5    = new_path(m.man, 'man5')
-        m.man6    = new_path(m.man, 'man6')
-        m.man7    = new_path(m.man, 'man7')
-        m.man8    = new_path(m.man, 'man8')
 
 
     def preorder_traversal(self, visited=None, **kwargs):
@@ -529,7 +511,7 @@ def installed_dependents(self):
     @property
     def prefix(self):
         """Get the prefix into which this package should be installed."""
-        return spack.install_layout.path_for_spec(self.spec)
+        return self.spec.prefix
 
 
     def url_version(self, version):
@@ -620,7 +602,7 @@ def do_install(self):
             # case it needs to add extra files)
             spack.install_layout.make_path_for_spec(self.spec)
 
-            self.install(self.prefix)
+            self.install(self.spec, self.prefix)
             if not os.path.isdir(self.prefix):
                 tty.die("Install failed for %s.  No install dir created." % self.name)
 
@@ -683,7 +665,7 @@ def module(self):
                           fromlist=[self.__class__.__name__])
 
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         """Package implementations override this with their own build configuration."""
         tty.die("Packages must provide an install method!")
 
diff --git a/lib/spack/spack/packages/callpath.py b/lib/spack/spack/packages/callpath.py
index e5102a5fad0e94b5777c44e7a066453853e29237..267f4a4e4997d2f5d817ab3dae0b1fe7be82f290 100644
--- a/lib/spack/spack/packages/callpath.py
+++ b/lib/spack/spack/packages/callpath.py
@@ -7,7 +7,7 @@ class Callpath(Package):
     depends_on("dyninst")
     depends_on("mpich")
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/packages/cmake.py b/lib/spack/spack/packages/cmake.py
index d73cdd2c88fa2c679148eab67ad041fbb27e9c4f..3ee294b134bd3c3314fbb74c1537a9970e22232d 100644
--- a/lib/spack/spack/packages/cmake.py
+++ b/lib/spack/spack/packages/cmake.py
@@ -5,7 +5,7 @@ class Cmake(Package):
     url       = 'http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz'
     versions  = { '2.8.10.2' : '097278785da7182ec0aea8769d06860c' }
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure('--prefix=%s'   % prefix,
                   '--parallel=%s' % make_jobs)
         make()
diff --git a/lib/spack/spack/packages/dyninst.py b/lib/spack/spack/packages/dyninst.py
index 7648a389ee74120fc388f2cba9c5aa722e7a1e3e..187cc2bb5ab99da3739bf774e4d560882bf1213c 100644
--- a/lib/spack/spack/packages/dyninst.py
+++ b/lib/spack/spack/packages/dyninst.py
@@ -11,7 +11,7 @@ class Dyninst(Package):
     depends_on("libelf")
     depends_on("libdwarf")
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/packages/libdwarf.py b/lib/spack/spack/packages/libdwarf.py
index 928a007193096549e22a5233961870432766625b..3102c3d4dd65c9150643f1b8a887ce6c3abec637 100644
--- a/lib/spack/spack/packages/libdwarf.py
+++ b/lib/spack/spack/packages/libdwarf.py
@@ -23,21 +23,21 @@ def clean(self):
                     make('clean')
 
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         # dwarf build does not set arguments for ar properly
         make.add_default_arg('ARFLAGS=rcs')
 
         # Dwarf doesn't provide an install, so we have to do it.
-        mkdirp(bin, include, lib, man1)
+        mkdirp(prefix.bin, prefix.include, prefix.lib, prefix.man1)
 
         with working_dir('libdwarf'):
             configure("--prefix=%s" % prefix, '--enable-shared')
             make()
 
-            install('libdwarf.a',  lib)
-            install('libdwarf.so', lib)
-            install('libdwarf.h',  include)
-            install('dwarf.h',     include)
+            install('libdwarf.a',  prefix.lib)
+            install('libdwarf.so', prefix.lib)
+            install('libdwarf.h',  prefix.include)
+            install('dwarf.h',     prefix.include)
 
         with working_dir('dwarfdump2'):
             configure("--prefix=%s" % prefix)
@@ -46,6 +46,6 @@ def install(self, prefix):
             # cause a race in parallel
             make(parallel=False)
 
-            install('dwarfdump',     bin)
-            install('dwarfdump.conf', lib)
-            install('dwarfdump.1',    man1)
+            install('dwarfdump',      prefix.bin)
+            install('dwarfdump.conf', prefix.lib)
+            install('dwarfdump.1',    prefix.man1)
diff --git a/lib/spack/spack/packages/libelf.py b/lib/spack/spack/packages/libelf.py
index 621444706e548ba3e6e860c71290fc365066b470..98e873669361b06f453b36cf0f8ef61698400267 100644
--- a/lib/spack/spack/packages/libelf.py
+++ b/lib/spack/spack/packages/libelf.py
@@ -6,7 +6,7 @@ class Libelf(Package):
 
     versions = { '0.8.13' : '4136d7b4c04df68b686570afa26988ac' }
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix,
                   "--enable-shared",
                   "--disable-dependency-tracking",
diff --git a/lib/spack/spack/packages/libunwind.py b/lib/spack/spack/packages/libunwind.py
index f53985709e4600d0d68a200f512247e834225b0c..0366ebefbab296619ca1c5809ad07f16e96eed4d 100644
--- a/lib/spack/spack/packages/libunwind.py
+++ b/lib/spack/spack/packages/libunwind.py
@@ -6,7 +6,7 @@ class Libunwind(Package):
 
     versions = { '1.1' : 'fb4ea2f6fbbe45bf032cd36e586883ce' }
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/packages/mpich.py b/lib/spack/spack/packages/mpich.py
index 8cd201f965f013ac34c6cc58fac9e3f1a9de27d4..a21db55fe887d5145db98730af0b37301a688ee2 100644
--- a/lib/spack/spack/packages/mpich.py
+++ b/lib/spack/spack/packages/mpich.py
@@ -13,7 +13,7 @@ class Mpich(Package):
     provides('mpi@:3', when='@3:')
     provides('mpi@:1', when='@1:')
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/packages/mpileaks.py b/lib/spack/spack/packages/mpileaks.py
index ffeb38ea45273bfbe2b4133a2c0d849989f4c957..41b7df058746f864d2bbdb8bb01b59e400e41817 100644
--- a/lib/spack/spack/packages/mpileaks.py
+++ b/lib/spack/spack/packages/mpileaks.py
@@ -7,7 +7,7 @@ class Mpileaks(Package):
     depends_on("mpich")
     depends_on("callpath")
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index c27203f05e28558827efd40b7aa2437598d2d0ee..3aba17142becf49e3a53e74334039cff65b4d4d8 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -82,6 +82,7 @@
 from spack.color import *
 from spack.util.lang import *
 from spack.util.string import *
+from spack.util.prefix import Prefix
 
 
 # Convenient names for color formats so that other things can use them
@@ -439,6 +440,11 @@ def preorder_traversal(self, visited=None, d=0, **kwargs):
                 yield elt
 
 
+    @property
+    def prefix(self):
+        return Prefix(spack.install_layout.path_for_spec(self))
+
+
     def _concretize_helper(self, presets=None, visited=None):
         """Recursive helper function for concretize().
            This concretizes everything bottom-up.  As things are
diff --git a/lib/spack/spack/test/mock_packages/callpath.py b/lib/spack/spack/test/mock_packages/callpath.py
index e9ad344eaa9b8e8f935c795a624325912a21b14d..8d8949942f6c877b70997e441229a25ef637541a 100644
--- a/lib/spack/spack/test/mock_packages/callpath.py
+++ b/lib/spack/spack/test/mock_packages/callpath.py
@@ -11,7 +11,7 @@ class Callpath(Package):
     depends_on("dyninst")
     depends_on("mpi")
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/test/mock_packages/dyninst.py b/lib/spack/spack/test/mock_packages/dyninst.py
index 6940c7788dc567211c75639fc3a507b8d6aa5b5e..c4c779f54caba5adb7e9d571b8e4c4ceedacaa19 100644
--- a/lib/spack/spack/test/mock_packages/dyninst.py
+++ b/lib/spack/spack/test/mock_packages/dyninst.py
@@ -12,7 +12,7 @@ class Dyninst(Package):
     depends_on("libelf")
     depends_on("libdwarf")
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/test/mock_packages/fake.py b/lib/spack/spack/test/mock_packages/fake.py
index 68077f5f82897e93cc57e89c5186781256dac33b..c1356180e9a9a574178d33e86bfe5320dcba8aea 100644
--- a/lib/spack/spack/test/mock_packages/fake.py
+++ b/lib/spack/spack/test/mock_packages/fake.py
@@ -5,7 +5,7 @@ class Fake(Package):
     url      = "http://www.fake-spack-example.org/downloads/fake-1.0.tar.gz"
     versions = { '1.0' : 'foobarbaz' }
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/test/mock_packages/libdwarf.py b/lib/spack/spack/test/mock_packages/libdwarf.py
index ccfff562869b52d21f2bad8dd97559d2951d0384..1bb9fbc889cca744857c1cfa955c972394e511aa 100644
--- a/lib/spack/spack/test/mock_packages/libdwarf.py
+++ b/lib/spack/spack/test/mock_packages/libdwarf.py
@@ -23,21 +23,21 @@ def clean(self):
                     make('clean')
 
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         # dwarf build does not set arguments for ar properly
         make.add_default_arg('ARFLAGS=rcs')
 
         # Dwarf doesn't provide an install, so we have to do it.
-        mkdirp(bin, include, lib, man1)
+        mkdirp(prefix.bin, prefix.include, prefix.lib, prefix.man1)
 
         with working_dir('libdwarf'):
             configure("--prefix=%s" % prefix, '--enable-shared')
             make()
 
-            install('libdwarf.a',  lib)
-            install('libdwarf.so', lib)
-            install('libdwarf.h',  include)
-            install('dwarf.h',     include)
+            install('libdwarf.a',  prefix.lib)
+            install('libdwarf.so', prefix.lib)
+            install('libdwarf.h',  prefix.include)
+            install('dwarf.h',     prefix.include)
 
         with working_dir('dwarfdump2'):
             configure("--prefix=%s" % prefix)
@@ -46,6 +46,6 @@ def install(self, prefix):
             # cause a race in parallel
             make(parallel=False)
 
-            install('dwarfdump',     bin)
-            install('dwarfdump.conf', lib)
-            install('dwarfdump.1',    man1)
+            install('dwarfdump',      prefix.bin)
+            install('dwarfdump.conf', prefix.lib)
+            install('dwarfdump.1',    prefix.man1)
diff --git a/lib/spack/spack/test/mock_packages/libelf.py b/lib/spack/spack/test/mock_packages/libelf.py
index 75948b26fba42cf117f191bdd3df449479562bd1..4d6b62b96bcc7f486ec64a84a3c799c77797e5e1 100644
--- a/lib/spack/spack/test/mock_packages/libelf.py
+++ b/lib/spack/spack/test/mock_packages/libelf.py
@@ -8,7 +8,7 @@ class Libelf(Package):
                   '0.8.12' : 'e21f8273d9f5f6d43a59878dc274fec7',
                   '0.8.10' : '9db4d36c283d9790d8fa7df1f4d7b4d9' }
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix,
                   "--enable-shared",
                   "--disable-dependency-tracking",
diff --git a/lib/spack/spack/test/mock_packages/mpich.py b/lib/spack/spack/test/mock_packages/mpich.py
index c2a479c07a1ad14051ee31a7d38aa589b1af2ef1..351d224dc029f086218a7a742509f86cb2ca7210 100644
--- a/lib/spack/spack/test/mock_packages/mpich.py
+++ b/lib/spack/spack/test/mock_packages/mpich.py
@@ -15,7 +15,7 @@ class Mpich(Package):
     provides('mpi@:3', when='@3:')
     provides('mpi@:1', when='@1:')
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/test/mock_packages/mpich2.py b/lib/spack/spack/test/mock_packages/mpich2.py
index ecf99925ccac726b67bb046d3a66b9deb2011914..382cac977ab2bb61339dbb55f7ba6ca4bc595df5 100644
--- a/lib/spack/spack/test/mock_packages/mpich2.py
+++ b/lib/spack/spack/test/mock_packages/mpich2.py
@@ -17,7 +17,7 @@ class Mpich2(Package):
     provides('mpi@:2.1', when='@1.1:')
     provides('mpi@:2.2', when='@1.2:')
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/test/mock_packages/mpileaks.py b/lib/spack/spack/test/mock_packages/mpileaks.py
index 6f9b143e9d1acb069f42ed6be2c469566378d2c4..da71ff65bb91eb777191ff559c3cb7f2a39172ec 100644
--- a/lib/spack/spack/test/mock_packages/mpileaks.py
+++ b/lib/spack/spack/test/mock_packages/mpileaks.py
@@ -12,7 +12,7 @@ class Mpileaks(Package):
     depends_on("mpi")
     depends_on("callpath")
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/test/mock_packages/zmpi.py b/lib/spack/spack/test/mock_packages/zmpi.py
index 93b6193eecdb7e18c65fbae9938ffc70e115d440..ec7e6fcdab48217a34ed0fb624965547e7314f36 100644
--- a/lib/spack/spack/test/mock_packages/zmpi.py
+++ b/lib/spack/spack/test/mock_packages/zmpi.py
@@ -11,7 +11,7 @@ class Zmpi(Package):
     provides('mpi@:10.0')
     depends_on('fake')
 
-    def install(self, prefix):
+    def install(self, spec, prefix):
         configure("--prefix=%s" % prefix)
         make()
         make("install")
diff --git a/lib/spack/spack/util/prefix.py b/lib/spack/spack/util/prefix.py
new file mode 100644
index 0000000000000000000000000000000000000000..f0ab790a170fd193544686b67dc696522434eb09
--- /dev/null
+++ b/lib/spack/spack/util/prefix.py
@@ -0,0 +1,67 @@
+"""
+This file contains utilities to help with installing packages.
+"""
+from spack.util.filesystem import new_path
+
+class Prefix(object):
+    """This class represents an installation prefix, but provides useful
+       attributes for referring to directories inside the prefix.
+
+       For example, you can do something like this::
+
+           prefix = Prefix('/usr')
+           print prefix.lib
+           print prefix.lib64
+           print prefix.bin
+           print prefix.share
+           print prefix.man4
+
+       This program would print:
+
+           /usr/lib
+           /usr/lib64
+           /usr/bin
+           /usr/share
+           /usr/share/man/man4
+
+       In addition, Prefix objects can be added to strings, e.g.:
+
+           print "foobar " + prefix
+
+       This prints 'foobar /usr". All of this is meant to make custom
+       installs easy.
+    """
+
+    def __init__(self, prefix):
+        self.prefix = prefix
+        self.bin     = new_path(self.prefix, 'bin')
+        self.sbin    = new_path(self.prefix, 'sbin')
+        self.etc     = new_path(self.prefix, 'etc')
+        self.include = new_path(self.prefix, 'include')
+        self.lib     = new_path(self.prefix, 'lib')
+        self.lib64   = new_path(self.prefix, 'lib64')
+        self.libexec = new_path(self.prefix, 'libexec')
+        self.share   = new_path(self.prefix, 'share')
+        self.doc     = new_path(self.share, 'doc')
+        self.info    = new_path(self.share, 'info')
+        self.man     = new_path(self.share, 'man')
+        self.man1    = new_path(self.man, 'man1')
+        self.man2    = new_path(self.man, 'man2')
+        self.man3    = new_path(self.man, 'man3')
+        self.man4    = new_path(self.man, 'man4')
+        self.man5    = new_path(self.man, 'man5')
+        self.man6    = new_path(self.man, 'man6')
+        self.man7    = new_path(self.man, 'man7')
+        self.man8    = new_path(self.man, 'man8')
+
+
+    def __str__(self):
+        return self.prefix
+
+
+    def __add__(self, other):
+        return str(self) + other
+
+
+    def __radd__(self, other):
+        return other + str(self)