Fix gyptest-app for Xcode 5.0.2

With Xcode 5.0.0 or later, the DTSDKName of Info.plist is always
set, even if SDKROOT is not defined in the Xcode project.

BUG=381
R=mark@chromium.org

Review URL: https://codereview.chromium.org/83463003

git-svn-id: http://gyp.googlecode.com/svn/trunk@1808 78cadc50-ecff-11dd-a971-7dbc132099af
diff --git a/pylib/gyp/xcode_emulation.py b/pylib/gyp/xcode_emulation.py
index 5e50f10..520dcc4 100644
--- a/pylib/gyp/xcode_emulation.py
+++ b/pylib/gyp/xcode_emulation.py
@@ -24,6 +24,7 @@
   # Populated lazily by _SdkPath(). Shared by all XcodeSettings, so cached
   # at class-level for efficiency.
   _sdk_path_cache = {}
+  _sdk_root_cache = {}
 
   # Populated lazily by GetExtraPlistItems(). Shared by all XcodeSettings, so
   # cached at class-level for efficiency.
@@ -290,9 +291,14 @@
     sdk_root = self._SdkRoot(configname)
     if sdk_root.startswith('/'):
       return sdk_root
+    return self._XcodeSdkPath(sdk_root)
+
+  def _XcodeSdkPath(self, sdk_root):
     if sdk_root not in XcodeSettings._sdk_path_cache:
-      XcodeSettings._sdk_path_cache[sdk_root] = self._GetSdkVersionInfoItem(
-          sdk_root, 'Path')
+      sdk_path = self._GetSdkVersionInfoItem(sdk_root, 'Path')
+      XcodeSettings._sdk_path_cache[sdk_root] = sdk_path
+      if sdk_root:
+        XcodeSettings._sdk_root_cache[sdk_path] = sdk_root
     return XcodeSettings._sdk_path_cache[sdk_root]
 
   def _AppendPlatformVersionMinFlags(self, lst):
@@ -885,6 +891,8 @@
       cache['DTXcodeBuild'] = xcode_build
 
       sdk_root = self._SdkRoot(configname)
+      if not sdk_root:
+        sdk_root = self._DefaultSdkRoot()
       cache['DTSDKName'] = sdk_root
       if xcode >= '0430':
         cache['DTSDKBuild'] = self._GetSdkVersionInfoItem(
@@ -909,6 +917,29 @@
       items['UIDeviceFamily'] = self._XcodeIOSDeviceFamily(configname)
     return items
 
+  def _DefaultSdkRoot(self):
+    """Returns the default SDKROOT to use.
+
+    Prior to version 5.0.0, if SDKROOT was not explicitly set in the Xcode
+    project, then the environment variable was empty. Starting with this
+    version, Xcode uses the name of the newest SDK installed.
+    """
+    if self._XcodeVersion() < '0500':
+      return ''
+    default_sdk_path = self._XcodeSdkPath('')
+    default_sdk_root = XcodeSettings._sdk_root_cache.get(default_sdk_path)
+    if default_sdk_root:
+      return default_sdk_root
+    all_sdks = self._GetStdout(['xcodebuild', '-showsdks'])
+    for line in all_sdks.splitlines():
+      items = line.split()
+      if len(items) >= 3 and items[-2] == '-sdk':
+        sdk_root = items[-1]
+        sdk_path = self._XcodeSdkPath(sdk_root)
+        if sdk_path == default_sdk_path:
+          return sdk_root
+    return ''
+
   def _DefaultArch(self):
     # For Mac projects, Xcode changed the default value used when ARCHS is not
     # set from "i386" to "x86_64".
diff --git a/test/mac/gyptest-app.py b/test/mac/gyptest-app.py
index c84c92f..b50e1a8 100755
--- a/test/mac/gyptest-app.py
+++ b/test/mac/gyptest-app.py
@@ -32,6 +32,11 @@
       result.append(os.path.join(dirpath, f)[len(path) + 1:])
   return result
 
+def XcodeVersion():
+  stdout = subprocess.check_output(['xcodebuild', '-version'])
+  version = stdout.splitlines()[0].split()[-1].replace('.', '')
+  return (version + '0' * (3 - len(version))).zfill(4)
+
 
 if sys.platform == 'darwin':
   test = TestGyp.TestGyp(formats=['ninja', 'make', 'xcode'])
@@ -56,7 +61,15 @@
     plist = plistlib.readPlist(info_plist)
     ExpectEq(GetStdout(['sw_vers', '-buildVersion']),
              plist['BuildMachineOSBuild'])
-    ExpectEq('', plist['DTSDKName'])
+
+    # Prior to Xcode 5.0.0, SDKROOT (and thus DTSDKName) was only defined if
+    # set in the Xcode project file. Starting with that version, it is always
+    # defined.
+    expected = ''
+    if XcodeVersion() >= '0500':
+      version = GetStdout(['xcodebuild', '-version', '-sdk', '', 'SDKVersion'])
+      expected = 'macosx' + version
+    ExpectEq(expected, plist['DTSDKName'])
     sdkbuild = GetStdout(
         ['xcodebuild', '-version', '-sdk', '', 'ProductBuildVersion'])
     if not sdkbuild: