ninja/mac: Allow per configuration SDKROOT.

This CL allows some flags to be per configuration instead of per target, so
iOS ninja can build simulator and device.

Make generator keeps its old behavior. Make doesn't know the build configuration
at gyp time and supporting this at build time is difficult.

R=thakischromium.org

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



git-svn-id: http://gyp.googlecode.com/svn/trunk@1737 78cadc50-ecff-11dd-a971-7dbc132099af
diff --git a/pylib/gyp/generator/ninja.py b/pylib/gyp/generator/ninja.py
index 9011807..33b2825 100644
--- a/pylib/gyp/generator/ninja.py
+++ b/pylib/gyp/generator/ninja.py
@@ -769,7 +769,7 @@
     env = self.GetSortedXcodeEnv(additional_settings=extra_env)
     env = self.ComputeExportEnvString(env)
 
-    keys = self.xcode_settings.GetExtraPlistItems()
+    keys = self.xcode_settings.GetExtraPlistItems(self.config_name)
     keys = [QuoteShellArgument(v, self.flavor) for v in sum(keys.items(), ())]
     self.ninja.build(out, 'copy_infoplist', info_plist,
                      variables=[('env', env), ('keys', keys)])
@@ -1066,7 +1066,7 @@
     libraries = gyp.common.uniquer(map(self.ExpandSpecial,
                                        spec.get('libraries', [])))
     if self.flavor == 'mac':
-      libraries = self.xcode_settings.AdjustLibraries(libraries)
+      libraries = self.xcode_settings.AdjustLibraries(libraries, config_name)
     elif self.flavor == 'win':
       libraries = self.msvs_settings.AdjustLibraries(libraries)
 
diff --git a/pylib/gyp/xcode_emulation.py b/pylib/gyp/xcode_emulation.py
index b4af0fd..7b42262 100644
--- a/pylib/gyp/xcode_emulation.py
+++ b/pylib/gyp/xcode_emulation.py
@@ -261,11 +261,13 @@
   def _GetSdkVersionInfoItem(self, sdk, infoitem):
     return self._GetStdout(['xcodebuild', '-version', '-sdk', sdk, infoitem])
 
-  def _SdkRoot(self):
-    return self.GetPerTargetSetting('SDKROOT', default='')
+  def _SdkRoot(self, configname):
+    if configname is None:
+      configname = self.configname
+    return self.GetPerConfigSetting('SDKROOT', configname, default='')
 
-  def _SdkPath(self):
-    sdk_root = self._SdkRoot()
+  def _SdkPath(self, configname=None):
+    sdk_root = self._SdkRoot(configname)
     if sdk_root.startswith('/'):
       return sdk_root
     if sdk_root not in XcodeSettings._sdk_path_cache:
@@ -665,6 +667,12 @@
             del result[key]
     return result
 
+  def GetPerConfigSetting(self, setting, configname, default=None):
+    if configname in self.xcode_settings:
+      return self.xcode_settings[configname].get(setting, default)
+    else:
+      return self.GetPerTargetSetting(setting, default)
+
   def GetPerTargetSetting(self, setting, default=None):
     """Tries to get xcode_settings.setting from spec. Assumes that the setting
        has the same value in all configurations and throws otherwise."""
@@ -677,7 +685,7 @@
       else:
         assert result == self.xcode_settings[configname].get(setting, None), (
             "Expected per-target setting for '%s', got per-config setting "
-            "(target %s)" % (setting, spec['target_name']))
+            "(target %s)" % (setting, self.spec['target_name']))
     if result is None:
       return default
     return result
@@ -743,7 +751,7 @@
         self._GetDebugInfoPostbuilds(configname, output, output_binary, quiet) +
         self._GetStripPostbuilds(configname, output_binary, quiet))
 
-  def _AdjustLibrary(self, library):
+  def _AdjustLibrary(self, library, config_name=None):
     if library.endswith('.framework'):
       l = '-framework ' + os.path.splitext(os.path.basename(library))[0]
     else:
@@ -752,13 +760,14 @@
         l = '-l' + m.group(1)
       else:
         l = library
-    return l.replace('$(SDKROOT)', self._SdkPath())
+    return l.replace('$(SDKROOT)', self._SdkPath(config_name))
 
-  def AdjustLibraries(self, libraries):
+  def AdjustLibraries(self, libraries, config_name=None):
     """Transforms entries like 'Cocoa.framework' in libraries into entries like
     '-framework Cocoa', 'libcrypto.dylib' into '-lcrypto', etc.
     """
-    libraries = [ self._AdjustLibrary(library) for library in libraries]
+    libraries = [self._AdjustLibrary(library, config_name)
+                 for library in libraries]
     return libraries
 
   def _BuildMachineOSBuild(self):
@@ -776,7 +785,7 @@
     build = build.split()[-1]
     return version, build
 
-  def GetExtraPlistItems(self):
+  def GetExtraPlistItems(self, configname=None):
     """Returns a dictionary with extra items to insert into Info.plist."""
     if not XcodeSettings._plist_cache:
       cache = XcodeSettings._plist_cache
@@ -786,7 +795,7 @@
       cache['DTXcode'] = xcode
       cache['DTXcodeBuild'] = xcode_build
 
-      sdk_root = self._SdkRoot()
+      sdk_root = self._SdkRoot(configname)
       cache['DTSDKName'] = sdk_root
       if xcode >= '0430':
         cache['DTSDKBuild'] = self._GetSdkVersionInfoItem(
@@ -1051,8 +1060,8 @@
     'TARGET_BUILD_DIR' : built_products_dir,
     'TEMP_DIR' : '${TMPDIR}',
   }
-  if xcode_settings.GetPerTargetSetting('SDKROOT'):
-    env['SDKROOT'] = xcode_settings._SdkPath()
+  if xcode_settings.GetPerConfigSetting('SDKROOT', configuration):
+    env['SDKROOT'] = xcode_settings._SdkPath(configuration)
   else:
     env['SDKROOT'] = ''
 
diff --git a/test/ios/app-bundle/test-device.gyp b/test/ios/app-bundle/test-device.gyp
new file mode 100644
index 0000000..7ba0aa0
--- /dev/null
+++ b/test/ios/app-bundle/test-device.gyp
@@ -0,0 +1,53 @@
+# Copyright (c) 2011 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+   'target_defaults': {
+    'configurations': {
+      'Debug-iphoneos': {
+        'xcode_settings': {
+          'ARCHS': [ 'armv7' ],
+          'SDKROOT': 'iphoneos',  # -isysroot
+        },
+      },
+      'Debug-iphonesimulator': {
+        'xcode_settings': {
+          'ARCHS': [ 'i386' ],
+          'SDKROOT': 'iphonesimulator',  # -isysroot
+        },
+      },
+    },
+  },
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+  ],
+  'targets': [
+    {
+      'target_name': 'test_app',
+      'product_name': 'Test App Gyp',
+      'type': 'executable',
+      'product_extension': 'bundle',
+      'mac_bundle': 1,
+      'sources': [
+        'TestApp/main.m',
+      ],
+      'mac_bundle_resources': [
+        'TestApp/English.lproj/InfoPlist.strings',
+        'TestApp/English.lproj/MainMenu.xib',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+        ],
+      },
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-fobjc-abi-version=2',
+        ],
+        'INFOPLIST_FILE': 'TestApp/TestApp-Info.plist',
+        'IPHONEOS_DEPLOYMENT_TARGET': '4.2',
+      },
+    },
+  ],
+}
diff --git a/test/ios/gyptest-per-config-settings.py b/test/ios/gyptest-per-config-settings.py
new file mode 100644
index 0000000..5b1e52e
--- /dev/null
+++ b/test/ios/gyptest-per-config-settings.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 Google Inc. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""
+Verifies that device and simulator bundles are built correctly.
+"""
+
+import TestGyp
+import subprocess
+import sys
+
+
+def CheckFileType(file, expected):
+  proc = subprocess.Popen(['lipo', '-info', file], stdout=subprocess.PIPE)
+  o = proc.communicate()[0].strip()
+  assert not proc.returncode
+  if not expected in o:
+    print 'File: Expected %s, got %s' % (expected, o)
+    test.fail_test()
+
+
+if sys.platform == 'darwin':
+  # TODO(justincohen): Enable this in xcode too once ninja can codesign and bots
+  # are configured with signing certs.
+  test = TestGyp.TestGyp(formats=['ninja'])
+
+  test.run_gyp('test-device.gyp', chdir='app-bundle')
+
+  for configuration in ['Debug-iphoneos', 'Debug-iphonesimulator']:
+    test.set_configuration(configuration)
+    test.build('test-device.gyp', test.ALL, chdir='app-bundle')
+    result_file = test.built_file_path('Test App Gyp.bundle/Test App Gyp',
+                                       chdir='app-bundle')
+    test.must_exist(result_file)
+    if configuration == 'Debug-iphoneos':
+      CheckFileType(result_file, 'armv7')
+    else:
+      CheckFileType(result_file, 'i386')
+
+  test.pass_test()