diff --git a/lib/spack/spack/build_environment.py b/lib/spack/spack/build_environment.py
index 15fb943ca41fa91d23daa5bc2045d3b7550545e1..792cd09eb8fbe4de0fb80e8e3a2a7cda557e912c 100644
--- a/lib/spack/spack/build_environment.py
+++ b/lib/spack/spack/build_environment.py
@@ -223,6 +223,8 @@ def set_compiler_environment_variables(pkg, env):
     for mod in compiler.modules:
         load_module(mod)
 
+    compiler.setup_custom_environment(env)
+
     return env
 
 
diff --git a/lib/spack/spack/compiler.py b/lib/spack/spack/compiler.py
index a77991e4dc6990615649de46f9c56a224a9f3fd7..fc663ea646233ac0441cafc25911737e921296da 100644
--- a/lib/spack/spack/compiler.py
+++ b/lib/spack/spack/compiler.py
@@ -114,9 +114,15 @@ def fc_rpath_arg(self):
 
     def __init__(self, cspec, operating_system,
                  paths, modules=[], alias=None, **kwargs):
+        self.operating_system = operating_system
+        self.spec = cspec
+        self.modules = modules
+        self.alias = alias
+
         def check(exe):
             if exe is None:
                 return None
+            exe = self._find_full_path(exe)
             _verify_executables(exe)
             return exe
 
@@ -138,11 +144,6 @@ def check(exe):
             if value is not None:
                 self.flags[flag] = value.split()
 
-        self.operating_system = operating_system
-        self.spec = cspec
-        self.modules = modules
-        self.alias = alias
-
     @property
     def version(self):
         return self.spec.version
@@ -269,6 +270,21 @@ def check(key):
         successful.reverse()
         return dict(((v, p, s), path) for v, p, s, path in successful)
 
+    def _find_full_path(self, path):
+        """Return the actual path for a tool.
+
+        Some toolchains use forwarding executables (particularly Xcode-based
+        toolchains) which can be manipulated by external environment variables.
+        This method should be used to extract the actual path used for a tool
+        by finding out the end executable the forwarding executables end up
+        running.
+        """
+        return path
+
+    def setup_custom_environment(self, env):
+        """Set any environment variables necessary to use the compiler."""
+        pass
+
     def __repr__(self):
         """Return a string representation of the compiler toolchain."""
         return self.__str__()
diff --git a/lib/spack/spack/compilers/clang.py b/lib/spack/spack/compilers/clang.py
index f7f1bf106bbc834017a673de0fc92640f6f079b0..34eec4ea7be9c640c465270694d97dda3aae8835 100644
--- a/lib/spack/spack/compilers/clang.py
+++ b/lib/spack/spack/compilers/clang.py
@@ -23,11 +23,14 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 ##############################################################################
 import re
+import os
+import spack
 import spack.compiler as cpr
 from spack.compiler import *
 from spack.util.executable import *
 import llnl.util.tty as tty
 from spack.version import ver
+from shutil import copytree, ignore_patterns
 
 
 class Clang(Compiler):
@@ -107,3 +110,79 @@ def default_version(cls, comp):
             cpr._version_cache[comp] = ver
 
         return cpr._version_cache[comp]
+
+    def _find_full_path(self, path):
+        basename = os.path.basename(path)
+
+        if not self.is_apple or basename not in ('clang', 'clang++'):
+            return super(Clang, self)._find_full_path(path)
+
+        xcrun = Executable('xcrun')
+        full_path = xcrun('-f', basename, output=str)
+        return full_path.strip()
+
+    def setup_custom_environment(self, env):
+        """Set the DEVELOPER_DIR environment for the Xcode toolchain.
+
+        On macOS, not all buildsystems support querying CC and CXX for the
+        compilers to use and instead query the Xcode toolchain for what
+        compiler to run. This side-steps the spack wrappers. In order to inject
+        spack into this setup, we need to copy (a subset of) Xcode.app and
+        replace the compiler executables with symlinks to the spack wrapper.
+        Currently, the stage is used to store the Xcode.app copies. We then set
+        the 'DEVELOPER_DIR' environment variables to cause the xcrun and
+        related tools to use this Xcode.app.
+        """
+        super(Clang, self).setup_custom_environment(env)
+
+        if not self.is_apple:
+            return
+
+        xcode_select = Executable('xcode-select')
+        real_root = xcode_select('--print-path', output=str).strip()
+        real_root = os.path.dirname(os.path.dirname(real_root))
+        developer_root = os.path.join(spack.stage_path,
+                                      'xcode-select',
+                                      self.name,
+                                      str(self.version))
+        xcode_link = os.path.join(developer_root, 'Xcode.app')
+
+        if not os.path.exists(developer_root):
+            tty.warn('Copying Xcode from %s to %s in order to add spack '
+                     'wrappers to it. Please do not interrupt.'
+                     % (real_root, developer_root))
+
+            # We need to make a new Xcode.app instance, but with symlinks to
+            # the spack wrappers for the compilers it ships. This is necessary
+            # because some projects insist on just asking xcrun and related
+            # tools where the compiler runs. These tools are very hard to trick
+            # as they do realpath and end up ignoring the symlinks in a
+            # "softer" tree of nothing but symlinks in the right places.
+            copytree(real_root, developer_root, symlinks=True,
+                     ignore=ignore_patterns('AppleTV*.platform',
+                                            'Watch*.platform',
+                                            'iPhone*.platform',
+                                            'Documentation',
+                                            'swift*'))
+
+            real_dirs = [
+                'Toolchains/XcodeDefault.xctoolchain/usr/bin',
+                'usr/bin',
+            ]
+
+            bins = ['c++', 'c89', 'c99', 'cc', 'clang', 'clang++', 'cpp']
+
+            for real_dir in real_dirs:
+                dev_dir = os.path.join(developer_root,
+                                       'Contents',
+                                       'Developer',
+                                       real_dir)
+                for fname in os.listdir(dev_dir):
+                    if fname in bins:
+                        os.unlink(os.path.join(dev_dir, fname))
+                        os.symlink(os.path.join(spack.build_env_path, 'cc'),
+                                   os.path.join(dev_dir, fname))
+
+            os.symlink(developer_root, xcode_link)
+
+        env.set('DEVELOPER_DIR', xcode_link)
diff --git a/var/spack/repos/builtin/packages/icu4c/package.py b/var/spack/repos/builtin/packages/icu4c/package.py
index 848ebfdeace4470d4aeb21d194816ee4dd0caa9d..e2fcb7bd5ffb6c4b90fe503288865e16f1e73fb7 100644
--- a/var/spack/repos/builtin/packages/icu4c/package.py
+++ b/var/spack/repos/builtin/packages/icu4c/package.py
@@ -42,7 +42,8 @@ def url_for_version(self, version):
 
     def install(self, spec, prefix):
         with working_dir('source'):
-            configure('--prefix={0}'.format(prefix))
+            configure('--prefix={0}'.format(prefix),
+                      '--enable-rpath')
 
             make()
             make('check')
diff --git a/var/spack/repos/builtin/packages/qt/package.py b/var/spack/repos/builtin/packages/qt/package.py
index 2dba05ce1316626955038f466b2b3cebb1d1b6f8..f04f05ec89bf64ac9f702ed5433d1d2b3712c994 100644
--- a/var/spack/repos/builtin/packages/qt/package.py
+++ b/var/spack/repos/builtin/packages/qt/package.py
@@ -183,7 +183,6 @@ def common_config_args(self):
                 '-no-xcb-xlib',
                 '-no-pulseaudio',
                 '-no-alsa',
-                '-no-gtkstyle',
             ])
 
         if '@4' in self.spec and sys.platform == 'darwin':