diff --git a/lib/spack/env/cc b/lib/spack/env/cc
index b9b79f83a33a56d4090050a5f558e5f92347d880..9758b74f37653b3b231111205ae791a2494019af 100755
--- a/lib/spack/env/cc
+++ b/lib/spack/env/cc
@@ -55,7 +55,10 @@ parameters=(
 
 # The compiler input variables are checked for sanity later:
 #   SPACK_CC, SPACK_CXX, SPACK_F77, SPACK_FC
-# Debug flag is optional; set to "TRUE" for debug logging:
+# The default compiler flags are passed from these variables:
+#   SPACK_CFLAGS, SPACK_CXXFLAGS, SPACK_FCFLAGS, SPACK_FFLAGS,
+#   SPACK_LDFLAGS, SPACK_LDLIBS
+# Debug env var is optional; set to true for debug logging:
 #   SPACK_DEBUG
 # Test command is used to unit test the compiler script.
 #   SPACK_TEST_COMMAND
@@ -99,21 +102,25 @@ case "$command" in
         command="$SPACK_CC"
         language="C"
         comp="CC"
+        lang_flags=C
         ;;
     c++|CC|g++|clang++|icpc|pgc++|xlc++)
         command="$SPACK_CXX"
         language="C++"
         comp="CXX"
+        lang_flags=CXX
         ;;
     f90|fc|f95|gfortran|ifort|pgfortran|xlf90|nagfor)
         command="$SPACK_FC"
         language="Fortran 90"
         comp="FC"
+        lang_flags=F
         ;;
     f77|gfortran|ifort|pgfortran|xlf|nagfor)
         command="$SPACK_F77"
         language="Fortran 77"
         comp="F77"
+        lang_flags=F
         ;;
     ld)
         mode=ld
@@ -131,7 +138,7 @@ if [[ -z $mode ]]; then
         if [[ $arg == -v || $arg == -V || $arg == --version || $arg == -dumpversion ]]; then
             mode=vcheck
             break
-    fi
+        fi
     done
 fi
 
@@ -188,6 +195,42 @@ fi
 input_command="$@"
 args=("$@")
 
+# Prepend cppflags, cflags, cxxflags, fcflags, fflags, and ldflags
+
+# Add ldflags
+case "$mode" in
+    ld|ccld)
+        args=(${SPACK_LDFLAGS[@]} "${args[@]}") ;;
+esac
+
+# Add compiler flags.
+case "$mode" in
+    cc|ccld)
+    # Add c, cxx, fc, and f flags
+        case $lang_flags in
+            C)
+                args=(${SPACK_CFLAGS[@]} "${args[@]}") ;;
+            CXX)
+                args=(${SPACK_CXXFLAGS[@]} "${args[@]}") ;;
+        esac
+        ;;
+esac
+
+# Add cppflags
+case "$mode" in
+    cpp|as|cc|ccld)
+        args=(${SPACK_CPPFLAGS[@]} "${args[@]}") ;;
+esac
+
+case "$mode" in cc|ccld)
+        # Add fortran flags
+        case $lang_flags in
+            F)
+                args=(${SPACK_FFLAGS[@]} "${args[@]}") ;;
+        esac
+        ;;
+esac
+
 # Read spack dependencies from the path environment variable
 IFS=':' read -ra deps <<< "$SPACK_DEPENDENCIES"
 for dep in "${deps[@]}"; do
@@ -230,6 +273,12 @@ elif [[ $mode == ld ]]; then
     $add_rpaths && args=("-rpath" "$SPACK_PREFIX/lib"   "${args[@]}")
 fi
 
+# Add SPACK_LDLIBS to args
+case "$mode" in
+    ld|ccld)
+        args=("${args[@]}" ${SPACK_LDLIBS[@]}) ;;
+esac
+
 #
 # Unset pesky environment variables that could affect build sanity.
 #
diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 5ce4cb1ce1a596b2ef718be3429f981cfd6b5bfe..d87aaa6285833442640593ba1c3268dfdc4250b1 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -51,15 +51,16 @@
 Skimming this module is a nice way to get acquainted with the types of
 calls you can make from within the install() function.
 """
-import multiprocessing
 import os
-import platform
-import shutil
 import sys
+import shutil
+import multiprocessing
+import platform
 
-import spack
 import llnl.util.tty as tty
 from llnl.util.filesystem import *
+
+import spack
 from spack.environment import EnvironmentModifications, validate
 from spack.util.environment import *
 from spack.util.executable import Executable, which
@@ -115,22 +116,24 @@ def __call__(self, *args, **kwargs):
 
 def set_compiler_environment_variables(pkg, env):
     assert pkg.spec.concrete
+    compiler = pkg.compiler
+    flags = pkg.spec.compiler_flags
+
     # Set compiler variables used by CMake and autotools
-    assert all(key in pkg.compiler.link_paths for key in ('cc', 'cxx', 'f77', 'fc'))
+    assert all(key in compiler.link_paths for key in ('cc', 'cxx', 'f77', 'fc'))
 
     # Populate an object with the list of environment modifications
     # and return it
     # TODO : add additional kwargs for better diagnostics, like requestor, ttyout, ttyerr, etc.
     link_dir = spack.build_env_path
-    env.set('CC',  join_path(link_dir, pkg.compiler.link_paths['cc']))
-    env.set('CXX', join_path(link_dir, pkg.compiler.link_paths['cxx']))
-    env.set('F77', join_path(link_dir, pkg.compiler.link_paths['f77']))
-    env.set('FC',  join_path(link_dir, pkg.compiler.link_paths['fc']))
+    env.set('CC',  join_path(link_dir, compiler.link_paths['cc']))
+    env.set('CXX', join_path(link_dir, compiler.link_paths['cxx']))
+    env.set('F77', join_path(link_dir, compiler.link_paths['f77']))
+    env.set('FC',  join_path(link_dir, compiler.link_paths['fc']))
 
     # Set SPACK compiler variables so that our wrapper knows what to call
-    compiler = pkg.compiler
     if compiler.cc:
-        env.set('SPACK_CC',  compiler.cc)
+        env.set('SPACK_CC', compiler.cc)
     if compiler.cxx:
         env.set('SPACK_CXX', compiler.cxx)
     if compiler.f77:
@@ -144,6 +147,12 @@ def set_compiler_environment_variables(pkg, env):
     env.set('SPACK_F77_RPATH_ARG', compiler.f77_rpath_arg)
     env.set('SPACK_FC_RPATH_ARG',  compiler.fc_rpath_arg)
 
+    # Add every valid compiler flag to the environment, prefixed with "SPACK_"
+    for flag in spack.spec.FlagMap.valid_compiler_flags():
+        # Concreteness guarantees key safety here
+        if flags[flag] != []:
+            env.set('SPACK_' + flag.upper(), ' '.join(f for f in flags[flag]))
+
     env.set('SPACK_COMPILER_SPEC', str(pkg.spec.compiler))
     return env
 
diff --git a/lib/spack/spack/cmd/find.py b/lib/spack/spack/cmd/find.py
index 6896e92ef5e108b2fb3790688ffd76f9b360346f..b9feed839c7176b4bb77e95f72d71a64531b1641 100644
--- a/lib/spack/spack/cmd/find.py
+++ b/lib/spack/spack/cmd/find.py
@@ -51,11 +51,14 @@ def setup_parser(subparser):
         help='Show full dependency DAG of installed packages')
 
     subparser.add_argument(
-        '-l', '--long', action='store_true',
+        '-l', '--long', action='store_true', dest='long',
         help='Show dependency hashes as well as versions.')
     subparser.add_argument(
-        '-L', '--very-long', action='store_true',
+        '-L', '--very-long', action='store_true', dest='very_long',
         help='Show dependency hashes as well as versions.')
+    subparser.add_argument(
+        '-f', '--show-flags', action='store_true', dest='show_flags',
+        help='Show spec compiler flags.')
 
     subparser.add_argument(
         '-e', '--explicit', action='store_true',
@@ -64,13 +67,13 @@ def setup_parser(subparser):
         '-E', '--implicit', action='store_true',
         help='Show only specs that were installed as dependencies')
     subparser.add_argument(
-        '-u', '--unknown', action='store_true',
+        '-u', '--unknown', action='store_true', dest='unknown',
         help='Show only specs Spack does not have a package for.')
     subparser.add_argument(
-        '-m', '--missing', action='store_true',
+        '-m', '--missing', action='store_true', dest='missing',
         help='Show missing dependencies as well as installed specs.')
     subparser.add_argument(
-        '-M', '--only-missing', action='store_true',
+        '-M', '--only-missing', action='store_true', dest='only_missing',
         help='Show only missing dependencies.')
     subparser.add_argument(
         '-N', '--namespace', action='store_true',
@@ -95,6 +98,12 @@ def display_specs(specs, **kwargs):
         hashes = True
         hlen = None
 
+    nfmt = '.' if namespace else '_'
+    format_string = '$%s$@$+' % nfmt
+    flags = kwargs.get('show_flags', False)
+    if flags:
+        format_string = '$%s$@$%%+$+' % nfmt
+
     # Make a dict with specs keyed by architecture and compiler.
     index = index_by(specs, ('architecture', 'compiler'))
 
@@ -110,8 +119,7 @@ def display_specs(specs, **kwargs):
         specs = index[(architecture,compiler)]
         specs.sort()
 
-        nfmt = '.' if namespace else '_'
-        abbreviated = [s.format('$%s$@$+' % nfmt, color=True) for s in specs]
+        abbreviated = [s.format(format_string, color=True) for s in specs]
         if mode == 'paths':
             # Print one spec per line along with prefix path
             width = max(len(s) for s in abbreviated)
@@ -126,20 +134,28 @@ def display_specs(specs, **kwargs):
         elif mode == 'deps':
             for spec in specs:
                 print spec.tree(
-                    format='$%s$@$+' % nfmt,
+                    format=format_string,
                     color=True,
                     indent=4,
                     prefix=(lambda s: gray_hash(s, hlen)) if hashes else None)
 
         elif mode == 'short':
-            def fmt(s):
-                string = ""
-                if hashes:
-                    string += gray_hash(s, hlen) + ' '
-                string += s.format('$-%s$@$+' % nfmt, color=True)
-
-                return string
-            colify(fmt(s) for s in specs)
+            # Print columns of output if not printing flags
+            if not flags:
+                def fmt(s):
+                    string = ""
+                    if hashes:
+                        string += gray_hash(s, hlen) + ' '
+                    string += s.format('$-%s$@$+' % nfmt, color=True)
+
+                    return string
+                colify(fmt(s) for s in specs)
+            # Print one entry per line if including flags
+            else:
+                for spec in specs:
+                    # Print the hash if necessary
+                    hsh = gray_hash(spec, hlen) + ' ' if hashes else ''
+                    print hsh + spec.format(format_string, color=True) + '\n'
 
         else:
             raise ValueError(
@@ -151,7 +167,7 @@ def find(parser, args):
     # Filter out specs that don't exist.
     query_specs = spack.cmd.parse_specs(args.query_specs)
     query_specs, nonexisting = partition_list(
-        query_specs, lambda s: spack.repo.exists(s.name))
+        query_specs, lambda s: spack.repo.exists(s.name) or not s.name)
 
     if nonexisting:
         msg = "No such package%s: " % ('s' if len(nonexisting) > 1 else '')
@@ -193,4 +209,4 @@ def find(parser, args):
     display_specs(specs, mode=args.mode,
                   long=args.long,
                   very_long=args.very_long,
-                  namespace=args.namespace)
+                  show_flags=args.show_flags)
diff --git a/lib/spack/spack/cmd/uninstall.py b/lib/spack/spack/cmd/uninstall.py
index 3bffc2633b6730adfcacf0f6bbaef5e706f3bd60..9fdf3045b28846459eee1bd948a4c1d2fe0d6328 100644
--- a/lib/spack/spack/cmd/uninstall.py
+++ b/lib/spack/spack/cmd/uninstall.py
@@ -92,7 +92,7 @@ def concretize_specs(specs, allow_multiple_matches=False, force=False):
         if not allow_multiple_matches and len(matching) > 1:
             tty.error("%s matches multiple packages:" % spec)
             print()
-            display_specs(matching, long=True)
+            display_specs(matching, long=True, show_flags=True)
             print()
             has_errors = True
 
@@ -186,7 +186,7 @@ def uninstall(parser, args):
         if not args.yes_to_all:
             tty.msg("The following packages will be uninstalled : ")
             print('')
-            display_specs(uninstall_list, long=True)
+            display_specs(uninstall_list, long=True, show_flags=True)
             print('')
             ask_for_confirmation('Do you want to proceed ? ')
 
diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py
index e2da2722124faec1a100ef09297472aecdc12ca4..2ae305f20150a5ee69b8b6b77c94d98b34ee4166 100644
--- a/lib/spack/spack/compiler.py
+++ b/lib/spack/spack/compiler.py
@@ -109,7 +109,7 @@ def fc_rpath_arg(self):
         return '-Wl,-rpath,'
 
 
-    def __init__(self, cspec, cc, cxx, f77, fc):
+    def __init__(self, cspec, cc, cxx, f77, fc, **kwargs):
         def check(exe):
             if exe is None:
                 return None
@@ -121,6 +121,15 @@ def check(exe):
         self.f77 = check(f77)
         self.fc  = check(fc)
 
+        # Unfortunately have to make sure these params are accepted
+        # in the same order they are returned by sorted(flags)
+        # in compilers/__init__.py
+        self.flags = {}
+        for flag in spack.spec.FlagMap.valid_compiler_flags():
+            value = kwargs.get(flag, None)
+            if value is not None:
+                self.flags[flag] = value.split()
+
         self.spec = cspec
 
 
@@ -188,7 +197,6 @@ def f77_version(cls, f77):
     def fc_version(cls, fc):
         return cls.default_version(fc)
 
-
     @classmethod
     def _find_matches_in_path(cls, compiler_names, detect_version, *path):
         """Finds compilers in the paths supplied.
diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py
index 692e5518aaf46102bf3576743780cf83ef843ba5..7c951ae8bcdadd8191e39cca02ea553e52d234fe 100644
--- a/lib/spack/spack/compilers/__init__.py
+++ b/lib/spack/spack/compilers/__init__.py
@@ -255,7 +255,11 @@ def get_compiler(cspec):
             else:
                 compiler_paths.append(None)
 
-        return cls(cspec, *compiler_paths)
+        flags = {}
+        for f in spack.spec.FlagMap.valid_compiler_flags():
+            if f in items:
+                flags[f] = items[f]
+        return cls(cspec, *compiler_paths, **flags)
 
     matches = find(compiler_spec, arch, scope)
     return [get_compiler(cspec) for cspec in matches]
diff --git a/lib/spack/spack/concretize.py b/lib/spack/spack/concretize.py
index f5e1c10b488cb7030b99cf249146674a66e3975c..4f78bfc347f98607c8a8ca53f443e12a438fd6c9 100644
--- a/lib/spack/spack/concretize.py
+++ b/lib/spack/spack/concretize.py
@@ -44,6 +44,7 @@
 from itertools import chain
 from spack.config import *
 
+
 class DefaultConcretizer(object):
     """This class doesn't have any state, it just provides some methods for
        concretization.  You can subclass it to override just some of the
@@ -269,6 +270,59 @@ def concretize_compiler(self, spec):
         return True  # things changed.
 
 
+    def concretize_compiler_flags(self, spec):
+        """
+        The compiler flags are updated to match those of the spec whose
+        compiler is used, defaulting to no compiler flags in the spec.
+        Default specs set at the compiler level will still be added later.
+        """
+        ret = False
+        for flag in spack.spec.FlagMap.valid_compiler_flags():
+            try:
+                nearest = next(p for p in spec.traverse(direction='parents')
+                               if ((p.compiler == spec.compiler and p is not spec)
+                               and flag in p.compiler_flags))
+                if ((not flag in spec.compiler_flags) or
+                    sorted(spec.compiler_flags[flag]) != sorted(nearest.compiler_flags[flag])):
+                    if flag in spec.compiler_flags:
+                        spec.compiler_flags[flag] = list(set(spec.compiler_flags[flag]) |
+                                                         set(nearest.compiler_flags[flag]))
+                    else:
+                        spec.compiler_flags[flag] = nearest.compiler_flags[flag]
+                    ret = True
+
+            except StopIteration:
+                if (flag in spec.root.compiler_flags and ((not flag in spec.compiler_flags) or
+                    sorted(spec.compiler_flags[flag]) != sorted(spec.root.compiler_flags[flag]))):
+                    if flag in spec.compiler_flags:
+                        spec.compiler_flags[flag] = list(set(spec.compiler_flags[flag]) |
+                                                         set(spec.root.compiler_flags[flag]))
+                    else:
+                        spec.compiler_flags[flag] = spec.root.compiler_flags[flag]
+                    ret = True
+                else:
+                    if not flag in spec.compiler_flags:
+                        spec.compiler_flags[flag] = []
+
+        # Include the compiler flag defaults from the config files
+        # This ensures that spack will detect conflicts that stem from a change
+        # in default compiler flags.
+        compiler = spack.compilers.compiler_for_spec(spec.compiler)
+        for flag in compiler.flags:
+            if flag not in spec.compiler_flags:
+                spec.compiler_flags[flag] = compiler.flags[flag]
+                if compiler.flags[flag] != []:
+                    ret = True
+            else:
+                if ((sorted(spec.compiler_flags[flag]) != sorted(compiler.flags[flag])) and
+                    (not set(spec.compiler_flags[flag]) >= set(compiler.flags[flag]))):
+                    ret = True
+                    spec.compiler_flags[flag] = list(set(spec.compiler_flags[flag]) |
+                                                     set(compiler.flags[flag]))
+
+        return ret
+
+
 def find_spec(spec, condition):
     """Searches the dag from spec in an intelligent order and looks
        for a spec that matches a condition"""
@@ -330,7 +384,6 @@ def cmp_specs(lhs, rhs):
     return 0
 
 
-
 class UnavailableCompilerVersionError(spack.error.SpackError):
     """Raised when there is no available compiler that satisfies a
        compiler spec."""
diff --git a/lib/spack/spack/database.py b/lib/spack/spack/database.py
index 73bc8143c8a92cd2b692db3084e339cc579bfc5f..f3967e6b72a80fd776e3dd706bfb8bf1e81b9ab3 100644
--- a/lib/spack/spack/database.py
+++ b/lib/spack/spack/database.py
@@ -60,7 +60,7 @@
 _db_dirname = '.spack-db'
 
 # DB version.  This is stuck in the DB file to track changes in format.
-_db_version = Version('0.9')
+_db_version = Version('0.9.1')
 
 # Default timeout for spack database locks is 5 min.
 _db_lock_timeout = 60
@@ -205,6 +205,11 @@ def _read_spec_from_yaml(self, hash_key, installs, parent_key=None):
 
         spec_dict = installs[hash_key]['spec']
 
+        # Install records don't include hash with spec, so we add it in here
+        # to ensure it is read properly.
+        for name in spec_dict:
+            spec_dict[name]['hash'] = hash_key
+
         # Build spec from dict first.
         spec = Spec.from_node_dict(spec_dict)
 
@@ -250,13 +255,18 @@ def check(cond, msg):
         check('installs' in db, "No 'installs' in YAML DB.")
         check('version'  in db, "No 'version' in YAML DB.")
 
+
+        installs = db['installs']
+
         # TODO: better version checking semantics.
         version = Version(db['version'])
-        if version != _db_version:
+        if version > _db_version:
             raise InvalidDatabaseVersionError(_db_version, version)
+        elif version < _db_version:
+            self.reindex(spack.install_layout)
+            installs = dict((k, v.to_dict()) for k, v in self._data.items())
 
         # Iterate through database and check each record.
-        installs = db['installs']
         data = {}
         for hash_key, rec in installs.items():
             try:
diff --git a/lib/spack/spack/multimethod.py b/lib/spack/spack/multimethod.py
index 5fda9328d600c2e9ee9726b31318105a5873221f..170ef3cea297aca997791b05331d18bbfd178563 100644
--- a/lib/spack/spack/multimethod.py
+++ b/lib/spack/spack/multimethod.py
@@ -146,12 +146,12 @@ class SomePackage(Package):
               def install(self, prefix):
                   # Do default install
 
-              @when('=chaos_5_x86_64_ib')
+              @when('arch=chaos_5_x86_64_ib')
               def install(self, prefix):
                   # This will be executed instead of the default install if
                   # the package's sys_type() is chaos_5_x86_64_ib.
 
-              @when('=bgqos_0")
+              @when('arch=bgqos_0")
               def install(self, prefix):
                   # This will be executed if the package's sys_type is bgqos_0
 
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 470353c4f695e81ee012917f5eb15fe227d6b961..58bdc0e4304242c538c26b7ffe127e8b1880b279 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -72,7 +72,9 @@
   dep_list     = { ^ spec }
   spec         = id [ options ]
   options      = { @version-list | +variant | -variant | ~variant |
-                   %compiler | =architecture }
+                   %compiler | arch=architecture | [ flag ]=value}
+  flag         = { cflags | cxxflags | fcflags | fflags | cppflags |
+                   ldflags | ldlibs }
   variant      = id
   architecture = id
   compiler     = id [ version-list ]
@@ -80,6 +82,9 @@
   version      = id | id: | :id | id:id
   id           = [A-Za-z0-9_][A-Za-z0-9_.-]*
 
+Identifiers using the <name>=<value> command, such as architectures and
+compiler flags, require a space before the name.
+
 There is one context-sensitive part: ids in versions may contain '.', while
 other ids may not.
 
@@ -108,6 +113,8 @@
 import spack.error
 import spack.compilers as compilers
 
+# TODO: move display_specs to some other location.
+from spack.cmd.find import display_specs
 from spack.version import *
 from spack.util.string import *
 from spack.util.prefix import Prefix
@@ -143,7 +150,6 @@
    every time we call str()"""
 _any_version = VersionList([':'])
 
-
 def index_specs(specs):
     """Take a list of specs and return a dict of lists.  Dict is
        keyed by spec name and lists include all specs with the
@@ -296,22 +302,25 @@ class VariantSpec(object):
        on the particular package being built, and each named variant can
        be enabled or disabled.
     """
-    def __init__(self, name, enabled):
+    def __init__(self, name, value):
         self.name = name
-        self.enabled = enabled
+        self.value = value
 
 
     def _cmp_key(self):
-        return (self.name, self.enabled)
+        return (self.name, self.value)
 
 
     def copy(self):
-        return VariantSpec(self.name, self.enabled)
+        return VariantSpec(self.name, self.value)
 
 
     def __str__(self):
-        out = '+' if self.enabled else '~'
-        return out + self.name
+        if self.value in [True,False]:
+            out = '+' if self.value else '~'
+            return out + self.name
+        else:
+            return ' ' + self.name + "=" + self.value
 
 
 class VariantMap(HashableMap):
@@ -322,10 +331,10 @@ def __init__(self, spec):
 
     def satisfies(self, other, strict=False):
         if strict or self.spec._concrete:
-            return all(k in self and self[k].enabled == other[k].enabled
+            return all(k in self and self[k].value == other[k].value
                        for k in other)
         else:
-            return all(self[k].enabled == other[k].enabled
+            return all(self[k].value == other[k].value
                        for k in other if k in self)
 
 
@@ -343,7 +352,7 @@ def constrain(self, other):
         changed = False
         for k in other:
             if k in self:
-                if self[k].enabled != other[k].enabled:
+                if self[k].value != other[k].value:
                     raise UnsatisfiableVariantSpecError(self[k], other[k])
             else:
                 self[k] = other[k].copy()
@@ -368,6 +377,70 @@ def __str__(self):
         return ''.join(str(self[key]) for key in sorted_keys)
 
 
+_valid_compiler_flags = [
+    'cflags', 'cxxflags', 'fflags', 'ldflags', 'ldlibs', 'cppflags']
+
+class FlagMap(HashableMap):
+    def __init__(self, spec):
+        super(FlagMap, self).__init__()
+        self.spec = spec
+
+
+    def satisfies(self, other, strict=False):
+        if strict or (self.spec and self.spec._concrete):
+            return all(f in self and set(self[f]) <= set(other[f])
+                       for f in other)
+        else:
+            return all(set(self[f]) <= set(other[f])
+                   for f in other if (other[f] != [] and f in self))
+
+
+    def constrain(self, other):
+        """Add all flags in other that aren't in self to self.
+
+        Return whether the spec changed.
+        """
+        if other.spec and other.spec._concrete:
+            for k in self:
+                if k not in other:
+                    raise UnsatisfiableCompilerFlagSpecError(self[k], '<absent>')
+
+        changed = False
+        for k in other:
+            if k in self and not set(self[k]) <= set(other[k]):
+                raise UnsatisfiableCompilerFlagSpecError(
+                    ' '.join(f for f in self[k]), ' '.join( f for f in other[k]))
+            elif k not in self:
+                self[k] = other[k]
+                changed = True
+        return changed
+
+    @staticmethod
+    def valid_compiler_flags():
+        return _valid_compiler_flags
+
+    @property
+    def concrete(self):
+        return all(flag in self for flag in _valid_compiler_flags)
+
+
+    def copy(self):
+        clone = FlagMap(None)
+        for name, value in self.items():
+            clone[name] = value
+        return clone
+
+
+    def _cmp_key(self):
+        return ''.join(str(key) + ' '.join(str(v) for v in value) for key, value in sorted(self.items()))
+
+
+    def __str__(self):
+        sorted_keys = filter(lambda flag: self[flag] != [], sorted(self.keys()))
+        cond_symbol = ' ' if len(sorted_keys)>0 else ''
+        return cond_symbol + ' '.join(str(key) + '=\"' + ' '.join(str(f) for f in self[key]) + '\"' for key in sorted_keys)
+
+
 class DependencyMap(HashableMap):
     """Each spec has a DependencyMap containing specs for its dependencies.
        The DependencyMap is keyed by name. """
@@ -409,10 +482,13 @@ def __init__(self, spec_like, *dep_like, **kwargs):
         self.versions = other.versions
         self.architecture = other.architecture
         self.compiler = other.compiler
+        self.compiler_flags = other.compiler_flags
+        self.compiler_flags.spec = self
         self.dependencies = other.dependencies
         self.variants = other.variants
         self.variants.spec = self
         self.namespace = other.namespace
+        self._hash = other._hash
 
         # Specs are by default not assumed to be normal, but in some
         # cases we've read them from a file want to assume normal.
@@ -440,13 +516,30 @@ def _add_version(self, version):
         self.versions.add(version)
 
 
-    def _add_variant(self, name, enabled):
+    def _add_variant(self, name, value):
         """Called by the parser to add a variant."""
         if name in self.variants: raise DuplicateVariantError(
                 "Cannot specify variant '%s' twice" % name)
-        self.variants[name] = VariantSpec(name, enabled)
+        if isinstance(value, basestring) and value.upper() == 'TRUE':
+            value = True
+        elif isinstance(value, basestring) and value.upper() == 'FALSE':
+            value = False
+        self.variants[name] = VariantSpec(name, value)
 
 
+    def _add_flag(self, name, value):
+        """Called by the parser to add a known flag.
+        Known flags currently include "arch"
+        """
+        valid_flags = FlagMap.valid_compiler_flags()
+        if name == 'arch':
+            self._set_architecture(value)
+        elif name in valid_flags:
+            assert(self.compiler_flags is not None)
+            self.compiler_flags[name] = value.split()
+        else:
+            self._add_variant(name,value)
+
     def _set_compiler(self, compiler):
         """Called by the parser to set the compiler."""
         if self.compiler: raise DuplicateCompilerSpecError(
@@ -473,7 +566,7 @@ def _add_dependency(self, spec):
     #
     @property
     def fullname(self):
-        return '%s.%s' % (self.namespace, self.name) if self.namespace else self.name
+        return '%s.%s' % (self.namespace, self.name) if self.namespace else (self.name if self.name else '')
 
 
     @property
@@ -523,7 +616,7 @@ def virtual(self):
     @staticmethod
     def is_virtual(name):
         """Test if a name is virtual without requiring a Spec."""
-        return not spack.repo.exists(name)
+        return (not name is None) and ( not spack.repo.exists(name) )
 
 
     @property
@@ -541,8 +634,8 @@ def concrete(self):
                               and self.variants.concrete
                               and self.architecture
                               and self.compiler and self.compiler.concrete
+                              and self.compiler_flags.concrete
                               and self.dependencies.concrete)
-
         return self._concrete
 
 
@@ -664,19 +757,25 @@ def dag_hash(self, length=None):
         """
         Return a hash of the entire spec DAG, including connectivity.
         """
-        yaml_text = yaml.dump(
-            self.to_node_dict(), default_flow_style=True, width=sys.maxint)
-        sha = hashlib.sha1(yaml_text)
-        return base64.b32encode(sha.digest()).lower()[:length]
-
+        if self._hash:
+            return self._hash[:length]
+        else:
+            yaml_text = yaml.dump(
+                self.to_node_dict(), default_flow_style=True, width=sys.maxint)
+            sha = hashlib.sha1(yaml_text)
+            b32_hash = base64.b32encode(sha.digest()).lower()[:length]
+            if self.concrete:
+                self._hash = b32_hash
+            return b32_hash
 
     def to_node_dict(self):
+        params = dict( (name, v.value) for name, v in self.variants.items() )
+        params.update( dict( (name, value) for name, value in self.compiler_flags.items()) )
         d = {
-            'variants' : dict(
-                (name,v.enabled) for name, v in self.variants.items()),
+            'parameters' : params,
             'arch' : self.architecture,
             'dependencies' : dict((d, self.dependencies[d].dag_hash())
-                                  for d in sorted(self.dependencies))
+                                  for d in sorted(self.dependencies)),
         }
 
         # Older concrete specs do not have a namespace.  Omit for
@@ -689,6 +788,7 @@ def to_node_dict(self):
         else:
             d['compiler'] = None
         d.update(self.versions.to_dict())
+
         return { self.name : d }
 
 
@@ -712,13 +812,27 @@ def from_node_dict(node):
         spec.versions = VersionList.from_dict(node)
         spec.architecture = node['arch']
 
+        if 'hash' in node:
+            spec._hash = node['hash']
+
         if node['compiler'] is None:
             spec.compiler = None
         else:
             spec.compiler = CompilerSpec.from_dict(node)
 
-        for name, enabled in node['variants'].items():
-            spec.variants[name] = VariantSpec(name, enabled)
+        if 'parameters' in node:
+            for name, value in node['parameters'].items():
+                if name in _valid_compiler_flags:
+                    spec.compiler_flags[name] = value
+                else:
+                    spec.variants[name] = VariantSpec(name, value)
+        elif 'variants' in node:
+            for name, value in node['variants'].items():
+                spec.variants[name] = VariantSpec(name, value)
+            for name in FlagMap.valid_compiler_flags():
+                spec.compiler_flags[name] = []
+        else:
+            raise SpackRecordError("Did not find a valid format for variants in YAML file")
 
         return spec
 
@@ -781,11 +895,13 @@ def _concretize_helper(self, presets=None, visited=None):
             # Concretize virtual dependencies last.  Because they're added
             # to presets below, their constraints will all be merged, but we'll
             # still need to select a concrete package later.
-            changed |= any(
-                (spack.concretizer.concretize_architecture(self),
-                 spack.concretizer.concretize_compiler(self),
-                 spack.concretizer.concretize_version(self),
-                 spack.concretizer.concretize_variants(self)))
+            if not self.virtual:
+                changed |= any(
+                    (spack.concretizer.concretize_architecture(self),
+                     spack.concretizer.concretize_compiler(self),
+                     spack.concretizer.concretize_compiler_flags(self),#has to be concretized after compiler
+                     spack.concretizer.concretize_version(self),
+                     spack.concretizer.concretize_variants(self)))
             presets[self.name] = self
 
         visited.add(self.name)
@@ -928,6 +1044,8 @@ def concretize(self):
            with requirements of its pacakges.  See flatten() and normalize() for
            more details on this.
         """
+        if not self.name:
+            raise SpecError("Attempting to concretize anonymous spec")
 
         if self._concrete:
             return
@@ -1128,13 +1246,11 @@ def _merge_dependency(self, dep, visited, spec_deps, provider_index):
                     if required:
                         raise UnsatisfiableProviderSpecError(required[0], dep)
             provider_index.update(dep)
-
         # If the spec isn't already in the set of dependencies, clone
         # it from the package description.
         if dep.name not in spec_deps:
             spec_deps[dep.name] = dep.copy()
             changed = True
-
         # Constrain package information with spec info
         try:
             changed |= spec_deps[dep.name].constrain(dep)
@@ -1177,7 +1293,6 @@ def _normalize_helper(self, visited, spec_deps, provider_index):
             for dep_name in pkg.dependencies:
                 # Do we depend on dep_name?  If so pkg_dep is not None.
                 pkg_dep = self._evaluate_dependency_conditions(dep_name)
-
                 # If pkg_dep is a dependency, merge it.
                 if pkg_dep:
                     changed |= self._merge_dependency(
@@ -1202,8 +1317,10 @@ def normalize(self, force=False):
 
            TODO: normalize should probably implement some form of cycle detection,
            to ensure that the spec is actually a DAG.
-
         """
+        if not self.name:
+            raise SpecError("Attempting to normalize anonymous spec")
+
         if self._normal and not force:
             return False
 
@@ -1248,7 +1365,7 @@ def validate_names(self):
         """
         for spec in self.traverse():
             # Don't get a package for a virtual name.
-            if not spec.virtual:
+            if (not spec.virtual) and spec.name:
                 spack.repo.get(spec.fullname)
 
             # validate compiler in addition to the package name.
@@ -1269,7 +1386,7 @@ def constrain(self, other, deps=True):
         """
         other = self._autospec(other)
 
-        if not self.name == other.name:
+        if not (self.name == other.name or (not self.name) or (not other.name) ):
             raise UnsatisfiableSpecNameError(self.name, other.name)
 
         if other.namespace is not None:
@@ -1281,7 +1398,7 @@ def constrain(self, other, deps=True):
 
         for v in other.variants:
             if (v in self.variants and
-                self.variants[v].enabled != other.variants[v].enabled):
+                self.variants[v].value != other.variants[v].value):
                 raise UnsatisfiableVariantSpecError(self.variants[v],
                                                     other.variants[v])
 
@@ -1300,6 +1417,8 @@ def constrain(self, other, deps=True):
         changed |= self.versions.intersect(other.versions)
         changed |= self.variants.constrain(other.variants)
 
+        changed |= self.compiler_flags.constrain(other.compiler_flags)
+
         old = self.architecture
         self.architecture = self.architecture or other.architecture
         changed |= (self.architecture != old)
@@ -1370,7 +1489,10 @@ def _autospec(self, spec_like):
             return spec_like
 
         try:
-            return spack.spec.Spec(spec_like)
+            spec = spack.spec.Spec(spec_like)
+            if not spec.name:
+                raise SpecError("anonymous package -- this will always be handled")
+            return spec
         except SpecError:
             return parse_anonymous_spec(spec_like, self.name)
 
@@ -1390,7 +1512,7 @@ def satisfies(self, other, deps=True, strict=False):
         """
         other = self._autospec(other)
 
-        # A concrete provider can satisfy a virtual dependency.
+       # A concrete provider can satisfy a virtual dependency.
         if not self.virtual and other.virtual:
             pkg = spack.repo.get(self.fullname)
             if pkg.provides(other.name):
@@ -1401,7 +1523,7 @@ def satisfies(self, other, deps=True, strict=False):
             return False
 
         # Otherwise, first thing we care about is whether the name matches
-        if self.name != other.name:
+        if self.name != other.name and self.name and other.name:
             return False
 
         # namespaces either match, or other doesn't require one.
@@ -1422,7 +1544,10 @@ def satisfies(self, other, deps=True, strict=False):
         elif strict and (other.compiler and not self.compiler):
             return False
 
-        if not self.variants.satisfies(other.variants, strict=strict):
+        var_strict = strict
+        if (not self.name) or (not other.name):
+            var_strict = True
+        if not self.variants.satisfies(other.variants, strict=var_strict):
             return False
 
         # Architecture satisfaction is currently just string equality.
@@ -1433,9 +1558,15 @@ def satisfies(self, other, deps=True, strict=False):
         elif strict and (other.architecture and not self.architecture):
             return False
 
+        if not self.compiler_flags.satisfies(other.compiler_flags, strict=strict):
+            return False
+
         # If we need to descend into dependencies, do it, otherwise we're done.
         if deps:
-            return self.satisfies_dependencies(other, strict=strict)
+            deps_strict = strict
+            if not (self.name and other.name):
+                deps_strict=True
+            return self.satisfies_dependencies(other, strict=deps_strict)
         else:
             return True
 
@@ -1515,10 +1646,12 @@ def _dup(self, other, **kwargs):
         if kwargs.get('cleardeps', True):
             self.dependents = DependencyMap()
             self.dependencies = DependencyMap()
+        self.compiler_flags = other.compiler_flags.copy()
         self.variants = other.variants.copy()
         self.variants.spec = self
         self.external = other.external
         self.namespace = other.namespace
+        self._hash = other._hash
 
         # If we copy dependencies, preserve DAG structure in the new spec
         if kwargs.get('deps', True):
@@ -1643,7 +1776,9 @@ def _cmp_node(self):
                 self.versions,
                 self.variants,
                 self.architecture,
-                self.compiler)
+                self.compiler,
+                self.compiler_flags,
+                self.dag_hash())
 
 
     def eq_node(self, other):
@@ -1672,7 +1807,7 @@ def colorized(self):
         return colorize_spec(self)
 
 
-    def format(self, format_string='$_$@$%@$+$=', **kwargs):
+    def format(self, format_string='$_$@$%@+$+$=', **kwargs):
         """Prints out particular pieces of a spec, depending on what is
            in the format string.  The format strings you can provide are::
 
@@ -1681,8 +1816,10 @@ def format(self, format_string='$_$@$%@$+$=', **kwargs):
                $@   Version with '@' prefix
                $%   Compiler with '%' prefix
                $%@  Compiler with '%' prefix & compiler version with '@' prefix
+               $%+  Compiler with '%' prefix & compiler flags prefixed by name
+               $%@+ Compiler, compiler version, and compiler flags with same prefixes as above
                $+   Options
-               $=   Architecture with '=' prefix
+               $=   Architecture prefixed by 'arch='
                $#   7-char prefix of DAG hash with '-' prefix
                $$   $
 
@@ -1693,6 +1830,7 @@ def format(self, format_string='$_$@$%@$+$=', **kwargs):
                ${COMPILER}      Full compiler string
                ${COMPILERNAME}  Compiler name
                ${COMPILERVER}   Compiler version
+               ${COMPILERFLAGS} Compiler flags
                ${OPTIONS}       Options
                ${ARCHITECTURE}  Architecture
                ${SHA1}          Dependencies 8-char sha1 prefix
@@ -1739,7 +1877,8 @@ def write(s, c):
                 fmt += 's'
 
                 if c == '_':
-                    out.write(fmt % self.name)
+                    name = self.name if self.name else ''
+                    out.write(fmt % name)
                 elif c == '.':
                     out.write(fmt % self.fullname)
                 elif c == '@':
@@ -1754,7 +1893,7 @@ def write(s, c):
                         write(fmt % str(self.variants), c)
                 elif c == '=':
                     if self.architecture:
-                        write(fmt % (c + str(self.architecture)), c)
+                        write(fmt % (' arch' + c + str(self.architecture)), c)
                 elif c == '#':
                     out.write('-' + fmt % (self.dag_hash(7)))
                 elif c == '$':
@@ -1771,11 +1910,16 @@ def write(s, c):
                     if (self.compiler and self.compiler.versions and
                         self.compiler.versions != _any_version):
                         write(c + str(self.compiler.versions), '%')
+                elif c == '+':
+                    if self.compiler_flags:
+                        write(fmt % str(self.compiler_flags), '%')
+                    compiler = False
                 elif c == '$':
                     escape = True
+                    compiler = False
                 else:
                     out.write(c)
-                compiler = False
+                    compiler = False
 
             elif named:
                 if not c == '}':
@@ -1785,6 +1929,7 @@ def write(s, c):
                     named_str += c
                     continue;
                 if named_str == 'PACKAGE':
+                    name = self.name if self.name else ''
                     write(fmt % self.name, '@')
                 if named_str == 'VERSION':
                     if self.versions and self.versions != _any_version:
@@ -1798,6 +1943,9 @@ def write(s, c):
                 elif named_str == 'COMPILERVER':
                     if self.compiler:
                         write(fmt % self.compiler.versions, '%')
+                elif named_str == 'COMPILERFLAGS':
+                    if self.compiler:
+                        write(fmt % str(self.compiler_flags), '%')
                 elif named_str == 'OPTIONS':
                     if self.variants:
                         write(fmt % str(self.variants), '+')
@@ -1842,7 +1990,7 @@ def tree(self, **kwargs):
         showid = kwargs.pop('ids',   False)
         cover  = kwargs.pop('cover', 'nodes')
         indent = kwargs.pop('indent', 0)
-        fmt    = kwargs.pop('format', '$_$@$%@$+$=')
+        fmt    = kwargs.pop('format', '$_$@$%@+$+$=')
         prefix = kwargs.pop('prefix', None)
         check_kwargs(kwargs, self.tree)
 
@@ -1874,12 +2022,13 @@ def __repr__(self):
 #
 # These are possible token types in the spec grammar.
 #
-DEP, AT, COLON, COMMA, ON, OFF, PCT, EQ, ID = range(9)
+HASH, DEP, AT, COLON, COMMA, ON, OFF, PCT, EQ, QT, ID = range(11)
 
 class SpecLexer(spack.parse.Lexer):
     """Parses tokens that make up spack specs."""
     def __init__(self):
         super(SpecLexer, self).__init__([
+            (r'/',         lambda scanner, val: self.token(HASH,  val)),
             (r'\^',        lambda scanner, val: self.token(DEP,   val)),
             (r'\@',        lambda scanner, val: self.token(AT,    val)),
             (r'\:',        lambda scanner, val: self.token(COLON, val)),
@@ -1891,6 +2040,7 @@ def __init__(self):
             (r'\=',        lambda scanner, val: self.token(EQ,    val)),
             # This is more liberal than identifier_re (see above).
             # Checked by check_identifier() for better error messages.
+            (r'([\"\'])(?:(?=(\\?))\2.)*?\1',lambda scanner, val: self.token(QT, val)),
             (r'\w[\w.-]*', lambda scanner, val: self.token(ID,    val)),
             (r'\s+',       lambda scanner, val: None)])
 
@@ -1898,27 +2048,52 @@ def __init__(self):
 class SpecParser(spack.parse.Parser):
     def __init__(self):
         super(SpecParser, self).__init__(SpecLexer())
-
+        self.previous = None
 
     def do_parse(self):
         specs = []
 
         try:
             while self.next:
+                # TODO: clean this parsing up a bit
+                if self.previous:
+                    specs.append(self.spec(self.previous.value))
                 if self.accept(ID):
-                    specs.append(self.spec())
+                    self.previous = self.token
+                    if self.accept(EQ):
+                        if not specs:
+                            specs.append(self.spec(None))
+                        if self.accept(QT):
+                            self.token.value = self.token.value[1:-1]
+                        else:
+                            self.expect(ID)
+                        specs[-1]._add_flag(self.previous.value, self.token.value)
+                    else:
+                        specs.append(self.spec(self.previous.value))
+                    self.previous = None
+                elif self.accept(HASH):
+                    specs.append(self.spec_by_hash())
 
                 elif self.accept(DEP):
                     if not specs:
-                        self.last_token_error("Dependency has no package")
-                    self.expect(ID)
-                    specs[-1]._add_dependency(self.spec())
+                        self.previous = self.token
+                        specs.append(self.spec(None))
+                        self.previous = None
+                    if self.accept(HASH):
+                        specs[-1]._add_dependency(self.spec_by_hash())
+                    else:
+                        self.expect(ID)
+                        specs[-1]._add_dependency(self.spec(self.token.value))
 
                 else:
-                    self.unexpected_token()
+                    # Attempt to construct an anonymous spec, but check that the first token is valid
+                    # TODO: Is this check even necessary, or will it all be Lex errors now?
+                    specs.append(self.spec(None,True))
+
         except spack.parse.ParseError, e:
             raise SpecParseError(e)
 
+
         return specs
 
 
@@ -1927,15 +2102,35 @@ def parse_compiler(self, text):
         return self.compiler()
 
 
-    def spec(self):
+    def spec_by_hash(self):
+        self.expect(ID)
+
+        specs = spack.installed_db.query()
+        matches = [spec for spec in specs if
+                   spec.dag_hash()[:len(self.token.value)] == self.token.value]
+
+        if not matches:
+            tty.die("%s does not match any installed packages." %self.token.value)
+
+        if len(matches) != 1:
+            raise AmbiguousHashError("Multiple packages specify hash %s." % self.token.value, *matches)
+
+        return matches[0]
+
+
+    def spec(self, name, check_valid_token = False):
         """Parse a spec out of the input.  If a spec is supplied, then initialize
            and return it instead of creating a new one."""
-
-        spec_namespace, dot, spec_name = self.token.value.rpartition('.')
-        if not spec_namespace:
+        if name:
+            spec_namespace, dot, spec_name = name.rpartition('.')
+            if not spec_namespace:
+                spec_namespace = None
+            self.check_identifier(spec_name)
+        else:
             spec_namespace = None
+            spec_name = None
+
 
-        self.check_identifier(spec_name)
 
         # This will init the spec without calling __init__.
         spec = Spec.__new__(Spec)
@@ -1945,9 +2140,11 @@ def spec(self):
         spec.architecture = None
         spec.compiler = None
         spec.external = None
+        spec.compiler_flags = FlagMap(spec)
         spec.dependents   = DependencyMap()
         spec.dependencies = DependencyMap()
         spec.namespace = spec_namespace
+        spec._hash = None
 
         spec._normal = False
         spec._concrete = False
@@ -1956,26 +2153,50 @@ def spec(self):
         # unspecified or not.
         added_version = False
 
+        if self.previous and self.previous.value == DEP:
+            if self.accept(HASH):
+                spec.add_dependency(self.spec_by_hash())
+            else:
+                self.expect(ID)
+                if self.accept(EQ):
+                    raise SpecParseError(spack.parse.ParseError("","","Expected dependency received anonymous spec"))
+                spec.add_dependency(self.spec(self.token.value))
+
         while self.next:
             if self.accept(AT):
                 vlist = self.version_list()
                 for version in vlist:
                     spec._add_version(version)
                 added_version = True
+                check_valid_token = False
 
             elif self.accept(ON):
                 spec._add_variant(self.variant(), True)
+                check_valid_token = False
 
             elif self.accept(OFF):
-                spec._add_variant(self.variant(), False)
+                spec._add_variant(self.variant(),False)
+                check_valid_token = False
 
             elif self.accept(PCT):
                 spec._set_compiler(self.compiler())
+                check_valid_token = False
 
-            elif self.accept(EQ):
-                spec._set_architecture(self.architecture())
+            elif self.accept(ID):
+                self.previous = self.token
+                if self.accept(EQ):
+                    if self.accept(QT):
+                        self.token.value = self.token.value[1:-1]
+                    else:
+                        self.expect(ID)
+                    spec._add_flag(self.previous.value, self.token.value)
+                    self.previous = None
+                else:
+                    return spec
 
             else:
+                if check_valid_token:
+                    self.unexpected_token()
                 break
 
         # If there was no version in the spec, consier it an open range
@@ -1985,13 +2206,17 @@ def spec(self):
         return spec
 
 
-    def variant(self):
-        self.expect(ID)
-        self.check_identifier()
-        return self.token.value
-
+    def variant(self,name=None):
+        #TODO: Make generalized variants possible
+        if name:
+            return name
+        else:
+            self.expect(ID)
+            self.check_identifier()
+            return self.token.value
 
     def architecture(self):
+        #TODO: Make this work properly as a subcase of variant (includes adding names to grammar)
         self.expect(ID)
         return self.token.value
 
@@ -2073,8 +2298,10 @@ def parse_anonymous_spec(spec_like, pkg_name):
     if isinstance(spec_like, str):
         try:
             anon_spec = Spec(spec_like)
+            if anon_spec.name != pkg_name:
+                raise SpecParseError(spack.parse.ParseError("","","Expected anonymous spec for package %s but found spec for package %s" % (pkg_name, anon_spec.name) ))
         except SpecParseError:
-            anon_spec = Spec(pkg_name + spec_like)
+            anon_spec = Spec(pkg_name + ' ' +  spec_like)
             if anon_spec.name != pkg_name: raise ValueError(
                     "Invalid spec for package %s: %s" % (pkg_name, spec_like))
     else:
@@ -2175,7 +2402,6 @@ def __init__(self, vpkg, providers):
         self.vpkg = vpkg
         self.providers = providers
 
-
 class UnsatisfiableSpecError(SpecError):
     """Raised when a spec conflicts with package constraints.
        Provide the requirement that was violated when raising."""
@@ -2214,6 +2440,11 @@ def __init__(self, provided, required):
         super(UnsatisfiableVariantSpecError, self).__init__(
             provided, required, "variant")
 
+class UnsatisfiableCompilerFlagSpecError(UnsatisfiableSpecError):
+    """Raised when a spec variant conflicts with package constraints."""
+    def __init__(self, provided, required):
+        super(UnsatisfiableCompilerFlagSpecError, self).__init__(
+            provided, required, "compiler_flags")
 
 class UnsatisfiableArchitectureSpecError(UnsatisfiableSpecError):
     """Raised when a spec architecture conflicts with package constraints."""
@@ -2240,3 +2471,13 @@ def __init__(self, provided, required):
 class SpackYAMLError(spack.error.SpackError):
     def __init__(self, msg, yaml_error):
         super(SpackYAMLError, self).__init__(msg, str(yaml_error))
+
+class SpackRecordError(spack.error.SpackError):
+    def __init__(self, msg):
+        super(SpackRecordError, self).__init__(msg)
+
+class AmbiguousHashError(SpecError):
+    def __init__(self, msg, *specs):
+        super(AmbiguousHashError, self).__init__(msg)
+        for spec in specs:
+            print '    ', spec.format('$.$@$%@+$+$=$#')
diff --git a/lib/spack/spack/test/cc.py b/lib/spack/spack/test/cc.py
index a6308661434640a6b358434185b2d8b6dd54c334..ea2b1644621a4671131687c117a51c82f6c3714a 100644
--- a/lib/spack/spack/test/cc.py
+++ b/lib/spack/spack/test/cc.py
@@ -56,11 +56,16 @@ def setUp(self):
         self.cc = Executable(join_path(spack.build_env_path, "cc"))
         self.ld = Executable(join_path(spack.build_env_path, "ld"))
         self.cpp = Executable(join_path(spack.build_env_path, "cpp"))
+        self.cxx = Executable(join_path(spack.build_env_path, "c++"))
+        self.fc = Executable(join_path(spack.build_env_path, "fc"))
 
         self.realcc = "/bin/mycc"
         self.prefix = "/spack-test-prefix"
 
         os.environ['SPACK_CC'] = self.realcc
+        os.environ['SPACK_CXX'] = self.realcc
+        os.environ['SPACK_FC'] = self.realcc
+
         os.environ['SPACK_PREFIX'] = self.prefix
         os.environ['SPACK_ENV_PATH']="test"
         os.environ['SPACK_DEBUG_LOG_DIR'] = "."
@@ -102,6 +107,15 @@ def check_cc(self, command, args, expected):
         self.assertEqual(self.cc(*args, output=str).strip(), expected)
 
 
+    def check_cxx(self, command, args, expected):
+        os.environ['SPACK_TEST_COMMAND'] = command
+        self.assertEqual(self.cxx(*args, output=str).strip(), expected)
+
+    def check_fc(self, command, args, expected):
+        os.environ['SPACK_TEST_COMMAND'] = command
+        self.assertEqual(self.fc(*args, output=str).strip(), expected)
+
+
     def check_ld(self, command, args, expected):
         os.environ['SPACK_TEST_COMMAND'] = command
         self.assertEqual(self.ld(*args, output=str).strip(), expected)
@@ -142,6 +156,64 @@ def test_ld_mode(self):
         self.check_ld('dump-mode', ['foo.o', 'bar.o', 'baz.o', '-o', 'foo', '-Wl,-rpath,foo'], "ld")
 
 
+    def test_flags(self):
+        os.environ['SPACK_LDFLAGS'] = '-L foo'
+        os.environ['SPACK_LDLIBS'] = '-lfoo'
+        os.environ['SPACK_CPPFLAGS'] = '-g -O1'
+        os.environ['SPACK_CFLAGS'] = '-Wall'
+        os.environ['SPACK_CXXFLAGS'] = '-Werror'
+        os.environ['SPACK_FFLAGS'] = '-w'
+
+        # Test ldflags added properly in ld mode
+        self.check_ld('dump-args', test_command,
+                      "ld " +
+                      '-rpath ' + self.prefix + '/lib ' +
+                      '-rpath ' + self.prefix + '/lib64 ' +
+                      '-L foo ' +
+                      ' '.join(test_command) + ' ' +
+                      '-lfoo')
+
+        # Test cppflags added properly in cpp mode
+        self.check_cpp('dump-args', test_command,
+                       "cpp " +
+                      '-g -O1 ' +
+                      ' '.join(test_command))
+
+        # Test ldflags, cppflags, and language specific flags are added in proper order
+        self.check_cc('dump-args', test_command,
+                      self.realcc + ' ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib64 ' +
+                      '-g -O1 ' +
+                      '-Wall ' +
+                      '-L foo ' +
+                      ' '.join(test_command) + ' ' +
+                      '-lfoo')
+
+        self.check_cxx('dump-args', test_command,
+                      self.realcc + ' ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib64 ' +
+                      '-g -O1 ' +
+                      '-Werror ' +
+                      '-L foo ' +
+                      ' '.join(test_command) + ' ' +
+                      '-lfoo')
+
+        self.check_fc('dump-args', test_command,
+                      self.realcc + ' ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib ' +
+                      '-Wl,-rpath,' + self.prefix + '/lib64 ' +
+                      '-w ' +
+                      '-g -O1 ' +
+                      '-L foo ' +
+                      ' '.join(test_command) + ' ' +
+                      '-lfoo')
+
+        os.environ['SPACK_LDFLAGS']=''
+        os.environ['SPACK_LDLIBS']=''
+
+
     def test_dep_rpath(self):
         """Ensure RPATHs for root package are added."""
         self.check_cc('dump-args', test_command,
diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py
index 799fdae3a9bc672b8d84f482a42221d1f2a48d97..963481054e5c6d2bd3af1dfba02092cb3581a66a 100644
--- a/lib/spack/spack/test/concretize.py
+++ b/lib/spack/spack/test/concretize.py
@@ -38,11 +38,20 @@ def check_spec(self, abstract, concrete):
             for name in abstract.variants:
                 avariant = abstract.variants[name]
                 cvariant = concrete.variants[name]
-                self.assertEqual(avariant.enabled, cvariant.enabled)
+                self.assertEqual(avariant.value, cvariant.value)
+
+        if abstract.compiler_flags:
+            for flag in abstract.compiler_flags:
+                aflag = abstract.compiler_flags[flag]
+                cflag = concrete.compiler_flags[flag]
+                self.assertTrue(set(aflag) <= set(cflag))
 
         for name in abstract.package.variants:
             self.assertTrue(name in concrete.variants)
 
+        for flag in concrete.compiler_flags.valid_compiler_flags():
+            self.assertTrue(flag in concrete.compiler_flags)
+
         if abstract.compiler and abstract.compiler.concrete:
             self.assertEqual(abstract.compiler, concrete.compiler)
 
@@ -75,9 +84,14 @@ def test_concretize_dag(self):
     def test_concretize_variant(self):
         self.check_concretize('mpich+debug')
         self.check_concretize('mpich~debug')
+        self.check_concretize('mpich debug=2')
         self.check_concretize('mpich')
 
 
+    def test_conretize_compiler_flags(self):
+        self.check_concretize('mpich cppflags="-O3"')
+
+
     def test_concretize_preferred_version(self):
         spec = self.check_concretize('python')
         self.assertEqual(spec.versions, ver('2.7.11'))
@@ -231,7 +245,7 @@ def test_compiler_inheritance(self):
 
 
     def test_external_package(self):
-        spec = Spec('externaltool')
+        spec = Spec('externaltool%gcc')
         spec.concretize()
 
         self.assertEqual(spec['externaltool'].external, '/path/to/external_tool')
diff --git a/lib/spack/spack/test/modules.py b/lib/spack/spack/test/modules.py
index 56e294de26e446c8e1221deea3f3613474aea8e3..c73badf8f24d70d370bf17a9c2369a077fd0e6c8 100644
--- a/lib/spack/spack/test/modules.py
+++ b/lib/spack/spack/test/modules.py
@@ -73,7 +73,7 @@ def mock_open(filename, mode):
         'all': {
             'filter': {'environment_blacklist': ['CMAKE_PREFIX_PATH']}
         },
-        '=x86-linux': {
+        'arch=x86-linux': {
             'environment': {'set': {'FOO': 'foo'},
                             'unset': ['BAR']}
         }
@@ -123,26 +123,26 @@ def get_modulefile_content(self, spec):
 
     def test_simple_case(self):
         spack.modules.CONFIGURATION = configuration_autoload_direct
-        spec = spack.spec.Spec('mpich@3.0.4=x86-linux')
+        spec = spack.spec.Spec('mpich@3.0.4 arch=x86-linux')
         content = self.get_modulefile_content(spec)
         self.assertTrue('module-whatis "mpich @3.0.4"' in content)
 
     def test_autoload(self):
         spack.modules.CONFIGURATION = configuration_autoload_direct
-        spec = spack.spec.Spec('mpileaks=x86-linux')
+        spec = spack.spec.Spec('mpileaks arch=x86-linux')
         content = self.get_modulefile_content(spec)
         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 2)
         self.assertEqual(len([x for x in content if 'module load ' in x]), 2)
 
         spack.modules.CONFIGURATION = configuration_autoload_all
-        spec = spack.spec.Spec('mpileaks=x86-linux')
+        spec = spack.spec.Spec('mpileaks arch=x86-linux')
         content = self.get_modulefile_content(spec)
         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 5)
         self.assertEqual(len([x for x in content if 'module load ' in x]), 5)
 
     def test_alter_environment(self):
         spack.modules.CONFIGURATION = configuration_alter_environment
-        spec = spack.spec.Spec('mpileaks=x86-linux')
+        spec = spack.spec.Spec('mpileaks arch=x86-linux')
         content = self.get_modulefile_content(spec)
         self.assertEqual(
             len([x
@@ -152,7 +152,7 @@ def test_alter_environment(self):
             len([x for x in content if 'setenv FOO "foo"' in x]), 1)
         self.assertEqual(len([x for x in content if 'unsetenv BAR' in x]), 1)
 
-        spec = spack.spec.Spec('libdwarf=x64-linux')
+        spec = spack.spec.Spec('libdwarf arch=x64-linux')
         content = self.get_modulefile_content(spec)
         self.assertEqual(
             len([x
@@ -164,14 +164,14 @@ def test_alter_environment(self):
 
     def test_blacklist(self):
         spack.modules.CONFIGURATION = configuration_blacklist
-        spec = spack.spec.Spec('mpileaks=x86-linux')
+        spec = spack.spec.Spec('mpileaks arch=x86-linux')
         content = self.get_modulefile_content(spec)
         self.assertEqual(len([x for x in content if 'is-loaded' in x]), 1)
         self.assertEqual(len([x for x in content if 'module load ' in x]), 1)
 
     def test_conflicts(self):
         spack.modules.CONFIGURATION = configuration_conflicts
-        spec = spack.spec.Spec('mpileaks=x86-linux')
+        spec = spack.spec.Spec('mpileaks arch=x86-linux')
         content = self.get_modulefile_content(spec)
         self.assertEqual(
             len([x for x in content if x.startswith('conflict')]), 2)
diff --git a/lib/spack/spack/test/multimethod.py b/lib/spack/spack/test/multimethod.py
index f653ca3477977dbed435a5d2a9b80eb57e6cecd6..a33656adccb6a09359005ae71b349a25fbf95b0a 100644
--- a/lib/spack/spack/test/multimethod.py
+++ b/lib/spack/spack/test/multimethod.py
@@ -25,9 +25,13 @@
 """
 Test for multi_method dispatch.
 """
+import unittest
 
 import spack
 from spack.multimethod import *
+from spack.version import *
+from spack.spec import Spec
+from spack.multimethod import when
 from spack.test.mock_packages_test import *
 from spack.version import *
 
@@ -89,19 +93,19 @@ def test_default_works(self):
 
 
     def test_architecture_match(self):
-        pkg = spack.repo.get('multimethod=x86_64')
+        pkg = spack.repo.get('multimethod arch=x86_64')
         self.assertEqual(pkg.different_by_architecture(), 'x86_64')
 
-        pkg = spack.repo.get('multimethod=ppc64')
+        pkg = spack.repo.get('multimethod arch=ppc64')
         self.assertEqual(pkg.different_by_architecture(), 'ppc64')
 
-        pkg = spack.repo.get('multimethod=ppc32')
+        pkg = spack.repo.get('multimethod arch=ppc32')
         self.assertEqual(pkg.different_by_architecture(), 'ppc32')
 
-        pkg = spack.repo.get('multimethod=arm64')
+        pkg = spack.repo.get('multimethod arch=arm64')
         self.assertEqual(pkg.different_by_architecture(), 'arm64')
 
-        pkg = spack.repo.get('multimethod=macos')
+        pkg = spack.repo.get('multimethod arch=macos')
         self.assertRaises(NoSuchMethodError, pkg.different_by_architecture)
 
 
diff --git a/lib/spack/spack/test/optional_deps.py b/lib/spack/spack/test/optional_deps.py
index 90382dfc4acaf1ba801e37125c49e6fb3f979b41..b5ba0ecf35649903e91e10c3785bd350200beb88 100644
--- a/lib/spack/spack/test/optional_deps.py
+++ b/lib/spack/spack/test/optional_deps.py
@@ -42,6 +42,13 @@ def test_normalize_simple_conditionals(self):
         self.check_normalize('optional-dep-test+a',
                              Spec('optional-dep-test+a', Spec('a')))
 
+        self.check_normalize('optional-dep-test a=true',
+                             Spec('optional-dep-test a=true', Spec('a')))
+
+
+        self.check_normalize('optional-dep-test a=true',
+                             Spec('optional-dep-test+a', Spec('a')))
+
         self.check_normalize('optional-dep-test@1.1',
                              Spec('optional-dep-test@1.1', Spec('b')))
 
diff --git a/lib/spack/spack/test/spec_dag.py b/lib/spack/spack/test/spec_dag.py
index 4645f985659d92f333f9361086a169cccbb23590..52f4f7395e055ce6de03291078ae0a8aaafbd5a7 100644
--- a/lib/spack/spack/test/spec_dag.py
+++ b/lib/spack/spack/test/spec_dag.py
@@ -31,6 +31,8 @@
 import spack
 import spack.package
 
+from llnl.util.lang import list_modules
+
 from spack.spec import Spec
 from spack.test.mock_packages_test import *
 
@@ -239,8 +241,8 @@ def test_unsatisfiable_compiler_version(self):
 
 
     def test_unsatisfiable_architecture(self):
-        self.set_pkg_dep('mpileaks', 'mpich=bgqos_0')
-        spec = Spec('mpileaks ^mpich=sles_10_ppc64 ^callpath ^dyninst ^libelf ^libdwarf')
+        self.set_pkg_dep('mpileaks', 'mpich arch=bgqos_0')
+        spec = Spec('mpileaks ^mpich arch=sles_10_ppc64 ^callpath ^dyninst ^libelf ^libdwarf')
         self.assertRaises(spack.spec.UnsatisfiableArchitectureSpecError, spec.normalize)
 
 
diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py
index 60eb86d6529a9e336ded577f82b59321d2587821..0cb78b90edef26dc7a563020e79223259f6f2204 100644
--- a/lib/spack/spack/test/spec_semantics.py
+++ b/lib/spack/spack/test/spec_semantics.py
@@ -22,6 +22,7 @@
 # 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 unittest
 from spack.spec import *
 from spack.test.mock_packages_test import *
 
@@ -138,11 +139,11 @@ def test_satisfies_compiler_version(self):
 
 
     def test_satisfies_architecture(self):
-        self.check_satisfies('foo=chaos_5_x86_64_ib', '=chaos_5_x86_64_ib')
-        self.check_satisfies('foo=bgqos_0', '=bgqos_0')
+        self.check_satisfies('foo arch=chaos_5_x86_64_ib', ' arch=chaos_5_x86_64_ib')
+        self.check_satisfies('foo arch=bgqos_0', ' arch=bgqos_0')
 
-        self.check_unsatisfiable('foo=bgqos_0', '=chaos_5_x86_64_ib')
-        self.check_unsatisfiable('foo=chaos_5_x86_64_ib', '=bgqos_0')
+        self.check_unsatisfiable('foo arch=bgqos_0', ' arch=chaos_5_x86_64_ib')
+        self.check_unsatisfiable('foo arch=chaos_5_x86_64_ib', ' arch=bgqos_0')
 
 
     def test_satisfies_dependencies(self):
@@ -190,12 +191,20 @@ def test_satisfies_virtual_dependency_versions(self):
     def test_satisfies_matching_variant(self):
         self.check_satisfies('mpich+foo', 'mpich+foo')
         self.check_satisfies('mpich~foo', 'mpich~foo')
+        self.check_satisfies('mpich foo=1', 'mpich foo=1')
+
+        #confirm that synonymous syntax works correctly
+        self.check_satisfies('mpich+foo', 'mpich foo=True')
+        self.check_satisfies('mpich foo=true', 'mpich+foo')
+        self.check_satisfies('mpich~foo', 'mpich foo=FALSE')
+        self.check_satisfies('mpich foo=False', 'mpich~foo')
 
 
     def test_satisfies_unconstrained_variant(self):
         # only asked for mpich, no constraints.  Either will do.
         self.check_satisfies('mpich+foo', 'mpich')
         self.check_satisfies('mpich~foo', 'mpich')
+        self.check_satisfies('mpich foo=1', 'mpich')
 
 
     def test_unsatisfiable_variants(self):
@@ -204,16 +213,44 @@ def test_unsatisfiable_variants(self):
         # 'mpich' is not concrete:
         self.check_satisfies('mpich', 'mpich+foo', False)
         self.check_satisfies('mpich', 'mpich~foo', False)
+        self.check_satisfies('mpich', 'mpich foo=1', False)
 
         # 'mpich' is concrete:
         self.check_unsatisfiable('mpich', 'mpich+foo', True)
         self.check_unsatisfiable('mpich', 'mpich~foo', True)
+        self.check_unsatisfiable('mpich', 'mpich foo=1', True)
 
 
     def test_unsatisfiable_variant_mismatch(self):
         # No matchi in specs
         self.check_unsatisfiable('mpich~foo', 'mpich+foo')
         self.check_unsatisfiable('mpich+foo', 'mpich~foo')
+        self.check_unsatisfiable('mpich foo=1', 'mpich foo=2')
+
+
+    def test_satisfies_matching_compiler_flag(self):
+        self.check_satisfies('mpich cppflags="-O3"', 'mpich cppflags="-O3"')
+        self.check_satisfies('mpich cppflags="-O3 -Wall"', 'mpich cppflags="-O3 -Wall"')
+
+
+    def test_satisfies_unconstrained_compiler_flag(self):
+        # only asked for mpich, no constraints.  Any will do.
+        self.check_satisfies('mpich cppflags="-O3"', 'mpich')
+
+
+    def test_unsatisfiable_compiler_flag(self):
+        # This case is different depending on whether the specs are concrete.
+
+        # 'mpich' is not concrete:
+        self.check_satisfies('mpich', 'mpich cppflags="-O3"', False)
+
+        # 'mpich' is concrete:
+        self.check_unsatisfiable('mpich', 'mpich cppflags="-O3"', True)
+
+
+    def test_unsatisfiable_compiler_flag_mismatch(self):
+        # No matchi in specs
+        self.check_unsatisfiable('mpich cppflags="-O3"', 'mpich cppflags="-O2"')
 
 
     def test_satisfies_virtual(self):
@@ -301,18 +338,26 @@ def test_constrain_variants(self):
         self.check_constrain('libelf+debug+foo', 'libelf+debug', 'libelf+foo')
         self.check_constrain('libelf+debug+foo', 'libelf+debug', 'libelf+debug+foo')
 
+        self.check_constrain('libelf debug=2 foo=1', 'libelf debug=2', 'libelf foo=1')
+        self.check_constrain('libelf debug=2 foo=1', 'libelf debug=2', 'libelf debug=2 foo=1')
+
         self.check_constrain('libelf+debug~foo', 'libelf+debug', 'libelf~foo')
         self.check_constrain('libelf+debug~foo', 'libelf+debug', 'libelf+debug~foo')
 
 
+    def test_constrain_compiler_flags(self):
+        self.check_constrain('libelf cflags="-O3" cppflags="-Wall"', 'libelf cflags="-O3"', 'libelf cppflags="-Wall"')
+        self.check_constrain('libelf cflags="-O3" cppflags="-Wall"', 'libelf cflags="-O3"', 'libelf cflags="-O3" cppflags="-Wall"')
+
+
     def test_constrain_arch(self):
-        self.check_constrain('libelf=bgqos_0', 'libelf=bgqos_0', 'libelf=bgqos_0')
-        self.check_constrain('libelf=bgqos_0', 'libelf', 'libelf=bgqos_0')
+        self.check_constrain('libelf arch=bgqos_0', 'libelf arch=bgqos_0', 'libelf arch=bgqos_0')
+        self.check_constrain('libelf arch=bgqos_0', 'libelf', 'libelf arch=bgqos_0')
 
 
     def test_constrain_compiler(self):
-        self.check_constrain('libelf=bgqos_0', 'libelf=bgqos_0', 'libelf=bgqos_0')
-        self.check_constrain('libelf=bgqos_0', 'libelf', 'libelf=bgqos_0')
+        self.check_constrain('libelf %gcc@4.4.7', 'libelf %gcc@4.4.7', 'libelf %gcc@4.4.7')
+        self.check_constrain('libelf %gcc@4.4.7', 'libelf', 'libelf %gcc@4.4.7')
 
 
     def test_invalid_constraint(self):
@@ -321,8 +366,11 @@ def test_invalid_constraint(self):
 
         self.check_invalid_constraint('libelf+debug', 'libelf~debug')
         self.check_invalid_constraint('libelf+debug~foo', 'libelf+debug+foo')
+        self.check_invalid_constraint('libelf debug=2', 'libelf debug=1')
 
-        self.check_invalid_constraint('libelf=bgqos_0', 'libelf=x86_54')
+        self.check_invalid_constraint('libelf cppflags="-O3"', 'libelf cppflags="-O2"')
+
+        self.check_invalid_constraint('libelf arch=bgqos_0', 'libelf arch=x86_54')
 
 
     def test_constrain_changed(self):
@@ -332,7 +380,9 @@ def test_constrain_changed(self):
         self.check_constrain_changed('libelf%gcc', '%gcc@4.5')
         self.check_constrain_changed('libelf', '+debug')
         self.check_constrain_changed('libelf', '~debug')
-        self.check_constrain_changed('libelf', '=bgqos_0')
+        self.check_constrain_changed('libelf', 'debug=2')
+        self.check_constrain_changed('libelf', 'cppflags="-O3"')
+        self.check_constrain_changed('libelf', ' arch=bgqos_0')
 
 
     def test_constrain_not_changed(self):
@@ -343,7 +393,9 @@ def test_constrain_not_changed(self):
         self.check_constrain_not_changed('libelf%gcc@4.5', '%gcc@4.5')
         self.check_constrain_not_changed('libelf+debug', '+debug')
         self.check_constrain_not_changed('libelf~debug', '~debug')
-        self.check_constrain_not_changed('libelf=bgqos_0', '=bgqos_0')
+        self.check_constrain_not_changed('libelf debug=2', 'debug=2')
+        self.check_constrain_not_changed('libelf cppflags="-O3"', 'cppflags="-O3"')
+        self.check_constrain_not_changed('libelf arch=bgqos_0', ' arch=bgqos_0')
         self.check_constrain_not_changed('libelf^foo', 'libelf^foo')
         self.check_constrain_not_changed('libelf^foo^bar', 'libelf^foo^bar')
 
@@ -355,7 +407,8 @@ def test_constrain_dependency_changed(self):
         self.check_constrain_changed('libelf^foo%gcc', 'libelf^foo%gcc@4.5')
         self.check_constrain_changed('libelf^foo', 'libelf^foo+debug')
         self.check_constrain_changed('libelf^foo', 'libelf^foo~debug')
-        self.check_constrain_changed('libelf^foo', 'libelf^foo=bgqos_0')
+        self.check_constrain_changed('libelf^foo', 'libelf^foo cppflags="-O3"')
+        self.check_constrain_changed('libelf^foo', 'libelf^foo arch=bgqos_0')
 
 
     def test_constrain_dependency_not_changed(self):
@@ -365,4 +418,6 @@ def test_constrain_dependency_not_changed(self):
         self.check_constrain_not_changed('libelf^foo%gcc@4.5', 'libelf^foo%gcc@4.5')
         self.check_constrain_not_changed('libelf^foo+debug', 'libelf^foo+debug')
         self.check_constrain_not_changed('libelf^foo~debug', 'libelf^foo~debug')
-        self.check_constrain_not_changed('libelf^foo=bgqos_0', 'libelf^foo=bgqos_0')
+        self.check_constrain_not_changed('libelf^foo cppflags="-O3"', 'libelf^foo cppflags="-O3"')
+        self.check_constrain_not_changed('libelf^foo arch=bgqos_0', 'libelf^foo arch=bgqos_0')
+
diff --git a/lib/spack/spack/test/spec_syntax.py b/lib/spack/spack/test/spec_syntax.py
index 928d111ea93c6112e7c2e55913d121c30aac1a54..c4e4c9cdfe5141ec50078f0b709039054305bf90 100644
--- a/lib/spack/spack/test/spec_syntax.py
+++ b/lib/spack/spack/test/spec_syntax.py
@@ -104,6 +104,8 @@ def test_dependencies_with_versions(self):
 
     def test_full_specs(self):
         self.check_parse("mvapich_foo^_openmpi@1.2:1.4,1.6%intel@12.1+debug~qt_4^stackwalker@8.1_1e")
+        self.check_parse("mvapich_foo^_openmpi@1.2:1.4,1.6%intel@12.1 debug=2~qt_4^stackwalker@8.1_1e")
+        self.check_parse('mvapich_foo^_openmpi@1.2:1.4,1.6%intel@12.1 cppflags="-O3"+debug~qt_4^stackwalker@8.1_1e')
 
     def test_canonicalize(self):
         self.check_parse(
@@ -128,7 +130,10 @@ def test_parse_errors(self):
 
     def test_duplicate_variant(self):
         self.assertRaises(DuplicateVariantError, self.check_parse, "x@1.2+debug+debug")
-        self.assertRaises(DuplicateVariantError, self.check_parse, "x ^y@1.2+debug+debug")
+        self.assertRaises(DuplicateVariantError, self.check_parse, "x ^y@1.2+debug debug=true")
+        self.assertRaises(DuplicateVariantError, self.check_parse, "x ^y@1.2 debug=false debug=true")
+        self.assertRaises(DuplicateVariantError, self.check_parse, "x ^y@1.2 debug=false~debug")
+
 
     def test_duplicate_depdendence(self):
         self.assertRaises(DuplicateDependencyError, self.check_parse, "x ^y ^y")
diff --git a/lib/spack/spack/variant.py b/lib/spack/spack/variant.py
index 20686d44b22c13c6876d00a015b0fc395886cbc8..ad875f5ef5ca064b3d99afeae6c5f5a93886b344 100644
--- a/lib/spack/spack/variant.py
+++ b/lib/spack/spack/variant.py
@@ -32,5 +32,5 @@
 class Variant(object):
     """Represents a variant on a build.  Can be either on or off."""
     def __init__(self, default, description):
-        self.default     = bool(default)
+        self.default     = default
         self.description = str(description)
diff --git a/lib/spack/spack/virtual.py b/lib/spack/spack/virtual.py
index 91ad77c8fdf1f7f8cca27dcfa87c6a476cc116bd..bb8333f023501332ef182051d9f6c2dbaeb5f220 100644
--- a/lib/spack/spack/virtual.py
+++ b/lib/spack/spack/virtual.py
@@ -67,10 +67,15 @@ def update(self, spec):
         if type(spec) != spack.spec.Spec:
             spec = spack.spec.Spec(spec)
 
+        if not spec.name:
+            # Empty specs do not have a package
+            return
+
         assert(not spec.virtual)
 
         pkg = spec.package
         for provided_spec, provider_spec in pkg.provided.iteritems():
+            provider_spec.compiler_flags = spec.compiler_flags.copy()#We want satisfaction other than flags
             if provider_spec.satisfies(spec, deps=False):
                 provided_name = provided_spec.name
 
diff --git a/var/spack/repos/builtin.mock/packages/multimethod/package.py b/var/spack/repos/builtin.mock/packages/multimethod/package.py
index 2d15722470e064c5c04721b1cc80be824229c127..def73ad82e5ffe934d2ce500f9ead84db517dd39 100644
--- a/var/spack/repos/builtin.mock/packages/multimethod/package.py
+++ b/var/spack/repos/builtin.mock/packages/multimethod/package.py
@@ -103,19 +103,19 @@ def has_a_default(self):
     #
     # Make sure we can switch methods on different architectures
     #
-    @when('=x86_64')
+    @when('arch=x86_64')
     def different_by_architecture(self):
         return 'x86_64'
 
-    @when('=ppc64')
+    @when('arch=ppc64')
     def different_by_architecture(self):
         return 'ppc64'
 
-    @when('=ppc32')
+    @when('arch=ppc32')
     def different_by_architecture(self):
         return 'ppc32'
 
-    @when('=arm64')
+    @when('arch=arm64')
     def different_by_architecture(self):
         return 'arm64'
 
diff --git a/var/spack/repos/builtin/packages/boost/package.py b/var/spack/repos/builtin/packages/boost/package.py
index b1b9c58b32818f4e72db4df69f15782dc8a8c762..c3d09d29ac9925fa29ddbb8d17fd8c172460c375 100644
--- a/var/spack/repos/builtin/packages/boost/package.py
+++ b/var/spack/repos/builtin/packages/boost/package.py
@@ -127,7 +127,7 @@ def url_for_version(self, version):
             dots, underscores)
 
     def determine_toolset(self, spec):
-        if spec.satisfies("=darwin-x86_64"):
+        if spec.satisfies("arch=darwin-x86_64"):
             return 'darwin'
 
         toolsets = {'g++': 'gcc',
diff --git a/var/spack/repos/builtin/packages/ghostscript/package.py b/var/spack/repos/builtin/packages/ghostscript/package.py
index 707f65c90284b531785a8b6cb350f9b2f13ed6dc..c22b90088e32f64483bbe05ec199d0c6d3ac7dd6 100644
--- a/var/spack/repos/builtin/packages/ghostscript/package.py
+++ b/var/spack/repos/builtin/packages/ghostscript/package.py
@@ -28,9 +28,9 @@
 class Ghostscript(Package):
     """an interpreter for the PostScript language and for PDF. """
     homepage = "http://ghostscript.com/"
-    url      = "http://downloads.ghostscript.com/public/old-gs-releases/ghostscript-9.16.tar.gz"
+    url      = "http://downloads.ghostscript.com/public/old-gs-releases/ghostscript-9.18.tar.gz"
 
-    version('9.16', '829319325bbdb83f5c81379a8f86f38f')
+    version('9.18', '33a47567d7a591c00a253caddd12a88a')
 
     parallel = False
 
diff --git a/var/spack/repos/builtin/packages/libpciaccess/package.py b/var/spack/repos/builtin/packages/libpciaccess/package.py
index 5d1e93eab75da07d9a1bef7c99f754b098128e37..42e8711a7df98b71c510a99287c81c711e1f8854 100644
--- a/var/spack/repos/builtin/packages/libpciaccess/package.py
+++ b/var/spack/repos/builtin/packages/libpciaccess/package.py
@@ -37,7 +37,7 @@ class Libpciaccess(Package):
 
     def install(self, spec, prefix):
         # libpciaccess does not support OS X
-        if spec.satisfies('=darwin-x86_64'):
+        if spec.satisfies('arch=darwin-x86_64'):
             # create a dummy directory
             mkdir(prefix.lib)
             return
diff --git a/var/spack/repos/builtin/packages/lua/package.py b/var/spack/repos/builtin/packages/lua/package.py
index e6219675862049bcb102b237786b9417a1598ae7..170f90516ab140ea54880052113f9c23dd1832bf 100644
--- a/var/spack/repos/builtin/packages/lua/package.py
+++ b/var/spack/repos/builtin/packages/lua/package.py
@@ -57,7 +57,7 @@ class Lua(Package):
         placement='luarocks')
 
     def install(self, spec, prefix):
-        if spec.satisfies("=darwin-i686") or spec.satisfies("=darwin-x86_64"):
+        if spec.satisfies("arch=darwin-i686") or spec.satisfies("arch=darwin-x86_64"):
             target = 'macosx'
         else:
             target = 'linux'
diff --git a/var/spack/repos/builtin/packages/openssl/package.py b/var/spack/repos/builtin/packages/openssl/package.py
index 119cdd83c219238888d517fb567e78f89663e90e..34ab0703ad66c8ad36699ecc5977fa2e71c4b30a 100644
--- a/var/spack/repos/builtin/packages/openssl/package.py
+++ b/var/spack/repos/builtin/packages/openssl/package.py
@@ -35,7 +35,7 @@ class Openssl(Package):
        Transport Layer Security (TLS v1) protocols as well as a
        full-strength general purpose cryptography library."""
     homepage = "http://www.openssl.org"
-    url      = "http://www.openssl.org/source/openssl-1.0.1h.tar.gz"
+    url      = "https://www.openssl.org/source/openssl-1.0.1h.tar.gz"
 
     version('1.0.1h', '8d6d684a9430d5cc98a62a5d8fbda8cf')
     version('1.0.1r', '1abd905e079542ccae948af37e393d28')
@@ -100,7 +100,7 @@ def install(self, spec, prefix):
         # in the environment, then this will override what is set in the
         # Makefile, leading to build errors.
         env.pop('APPS', None)
-        if spec.satisfies("=darwin-x86_64") or spec.satisfies("=ppc64"):
+        if spec.satisfies("arch=darwin-x86_64") or spec.satisfies("arch=ppc64"):
             # This needs to be done for all 64-bit architectures (except Linux,
             # where it happens automatically?)
             env['KERNEL_BITS'] = '64'