Fix ARCHS selection when building for iOS

When building for iOS, consider any architecture set in the gyp files
as valid (to allow building for x86_64 when using Xcode 4.0 or higher).

BUG=webrtc:3073
R=thakis@chromium.org

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

git-svn-id: http://gyp.googlecode.com/svn/trunk@1881 78cadc50-ecff-11dd-a971-7dbc132099af
diff --git a/pylib/gyp/xcode_emulation.py b/pylib/gyp/xcode_emulation.py
index d86413a..d6fe8f5 100644
--- a/pylib/gyp/xcode_emulation.py
+++ b/pylib/gyp/xcode_emulation.py
@@ -389,7 +389,8 @@
     if arch is not None:
       archs = [arch]
     else:
-      archs = self._Settings().get('ARCHS', [self._DefaultArch()])
+      assert self.configname
+      archs = self.GetActiveArchs(self.configname)
     if len(archs) != 1:
       # TODO: Supporting fat binaries will be annoying.
       self._WarnUnimplemented('ARCHS')
@@ -646,7 +647,8 @@
     if arch is not None:
       archs = [arch]
     else:
-      archs = self._Settings().get('ARCHS', [self._DefaultArch()])
+      assert self.configname
+      archs = self.GetActiveArchs(self.configname)
     if len(archs) != 1:
       # TODO: Supporting fat binaries will be annoying.
       self._WarnUnimplemented('ARCHS')
@@ -1470,7 +1472,17 @@
   for archs in defaults_archs.itervalues():
     allowed_archs.update(archs)
   selected_archs = set()
-  for arch in (xcode_settings.get('ARCHS', []) or ['$(ARCHS_STANDARD)']):
+  archs = xcode_settings.get('ARCHS')
+  if archs:
+    # Respect any architecture that have been explicitly configured in the
+    # input gyp files (except variables like $(ARCHS_STANDARD)).
+    variable_pattern = re.compile(r'^\$\([a-zA-Z0-9_]*\)$')
+    for arch in archs:
+      if not variable_pattern.search(arch):
+        allowed_archs.add(arch)
+  else:
+    archs = ['$(ARCHS_STANDARD)']
+  for arch in archs:
     if arch in defaults_archs:
       selected_archs.update(defaults_archs[arch])
     elif arch in allowed_archs:
diff --git a/test/ios/app-bundle/test-crosscompile.gyp b/test/ios/app-bundle/test-crosscompile.gyp
new file mode 100644
index 0000000..d904958
--- /dev/null
+++ b/test/ios/app-bundle/test-crosscompile.gyp
@@ -0,0 +1,47 @@
+# Copyright (c) 2014 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.
+{
+  'make_global_settings': [
+    ['CC', '/usr/bin/clang'],
+  ],
+  'targets': [
+    # This target will not be built, but is here so that ninja Xcode emulation
+    # understand this is a multi-platform (ios + mac) build.
+    {
+      'target_name': 'TestDummy',
+      'product_name': 'TestDummy',
+      'toolsets': ['target'],
+      'type': 'executable',
+      'mac_bundle': 1,
+      'sources': [
+        'tool_main.cc',
+      ],
+      'xcode_settings': {
+        'SDKROOT': 'iphonesimulator',  # -isysroot
+        'TARGETED_DEVICE_FAMILY': '1,2',
+        'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+      },
+    },
+    {
+      'target_name': 'TestHost',
+      'product_name': 'TestHost',
+      'toolsets': ['host'],
+      'type': 'executable',
+      'mac_bundle': 0,
+      'sources': [
+        'tool_main.cc',
+      ],
+      'xcode_settings': {
+        'SDKROOT': 'macosx',
+        'ARCHS': [
+          '$(ARCHS_STANDARD)',
+          'x86_64',
+        ],
+        'VALID_ARCHS': [
+          'x86_64',
+        ],
+      }
+    }
+  ],
+}
diff --git a/test/ios/app-bundle/tool_main.cc b/test/ios/app-bundle/tool_main.cc
new file mode 100644
index 0000000..9dc3c94
--- /dev/null
+++ b/test/ios/app-bundle/tool_main.cc
@@ -0,0 +1,7 @@
+// Copyright (c) 2014 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.
+
+int main() {
+  return 0;
+}
diff --git a/test/ios/gyptest-archs.py b/test/ios/gyptest-archs.py
index 8870fec..38c5c61 100644
--- a/test/ios/gyptest-archs.py
+++ b/test/ios/gyptest-archs.py
@@ -12,52 +12,40 @@
 import TestMac
 
 import collections
-import plistlib
-import os
-import re
-import struct
-import subprocess
 import sys
-import tempfile
 
 
 if sys.platform == 'darwin':
   test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
 
   test_cases = [
-    ('Default', 'TestNoArchs', ['i386']),
     ('Default', 'TestArch32Bits', ['i386']),
-    ('Default', 'TestArch64Bits', ['x86_64']),
-    ('Default', 'TestMultiArchs', ['i386', 'x86_64']),
-    ('Default-iphoneos', 'TestNoArchs', ['armv7']),
     ('Default-iphoneos', 'TestArch32Bits', ['armv7']),
-    ('Default-iphoneos', 'TestArch64Bits', ['arm64']),
-    ('Default-iphoneos', 'TestMultiArchs', ['armv7', 'arm64']),
   ]
 
+  if TestMac.Xcode.Version() < '0510':
+    test_cases.extend([
+        ('Default', 'TestNoArchs', ['i386']),
+        ('Default-iphoneos', 'TestNoArchs', ['armv7'])])
+
+  if TestMac.Xcode.Version() >= '0500':
+    test_cases.extend([
+        ('Default', 'TestArch64Bits', ['x86_64']),
+        ('Default', 'TestMultiArchs', ['i386', 'x86_64']),
+        ('Default-iphoneos', 'TestArch64Bits', ['arm64']),
+        ('Default-iphoneos', 'TestMultiArchs', ['armv7', 'arm64'])])
+
   test.run_gyp('test-archs.gyp', chdir='app-bundle')
   for configuration, target, archs in test_cases:
-    is_64_bit_build = ('arm64' in archs or 'x86_64' in archs)
     is_device_build = configuration.endswith('-iphoneos')
 
     kwds = collections.defaultdict(list)
-    if test.format == 'xcode' and is_device_build:
-      configuration, sdk = configuration.split('-')
-      kwds['arguments'].extend(['-sdk', sdk])
-
-    # TODO(sdefresne): remove those special-cases once the bots have been
-    # updated to use a more recent version of Xcode.
-    if TestMac.Xcode.Version() < '0500':
-      if is_64_bit_build:
-        continue
-      if test.format == 'xcode':
-        arch = 'i386'
-        if is_device_build:
-          arch = 'armv7'
-        kwds['arguments'].extend(['-arch', arch])
-    elif TestMac.Xcode.Version() >= '0510':
-      if target == 'TestNoArchs':
-        continue
+    if test.format == 'xcode':
+      if is_device_build:
+        configuration, sdk = configuration.split('-')
+        kwds['arguments'].extend(['-sdk', sdk])
+      if TestMac.Xcode.Version() < '0500':
+        kwds['arguments'].extend(['-arch', archs[0]])
 
     test.set_configuration(configuration)
     filename = '%s.bundle/%s' % (target, target)
diff --git a/test/ios/gyptest-crosscompile.py b/test/ios/gyptest-crosscompile.py
new file mode 100644
index 0000000..a081683
--- /dev/null
+++ b/test/ios/gyptest-crosscompile.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2014 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 tools are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import sys
+import os
+
+if sys.platform == 'darwin':
+  test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+  oldenv = os.environ.copy()
+  try:
+    os.environ['GYP_CROSSCOMPILE'] = '1'
+    test.run_gyp('test-crosscompile.gyp', chdir='app-bundle')
+  finally:
+    os.environ.clear()
+    os.environ.update(oldenv)
+
+  test.set_configuration('Default')
+  test.build('test-crosscompile.gyp', 'TestHost', chdir='app-bundle')
+  result_file = test.built_file_path('TestHost', chdir='app-bundle')
+  test.must_exist(result_file)
+  TestMac.CheckFileType(test, result_file, ['x86_64'])
+
+  test.pass_test()
diff --git a/test/lib/TestMac.py b/test/lib/TestMac.py
index 755d40e..68605d7 100644
--- a/test/lib/TestMac.py
+++ b/test/lib/TestMac.py
@@ -29,7 +29,7 @@
     found_file, found_archs = match.groups()
     if found_file != file or set(found_archs.split()) != set(archs):
       print 'Expected file %s with arch %s, got %s with arch %s' % (
-          file, ' '.join(archs), found_file, ' '.join(found_archs))
+          file, ' '.join(archs), found_file, found_archs)
       test.fail_test()