This CL adds support for extension in GYP.

This CL adds the extension target type and adds the link flags to
compile .appex extensions.

BUG=gyp:435
R=justincohen@chromium.org, mark@chromium.org, pkl@chromium.org, sdefresne@chromium.org

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

git-svn-id: http://gyp.googlecode.com/svn/trunk@1954 78cadc50-ecff-11dd-a971-7dbc132099af
diff --git a/pylib/gyp/generator/xcode.py b/pylib/gyp/generator/xcode.py
index 7972459..b4d1e19 100644
--- a/pylib/gyp/generator/xcode.py
+++ b/pylib/gyp/generator/xcode.py
@@ -69,6 +69,7 @@
 # The Xcode-specific keys that exist on targets and aren't moved down to
 # configurations.
 generator_additional_non_configuration_keys = [
+  'ios_app_extension',
   'mac_bundle',
   'mac_bundle_resources',
   'mac_framework_headers',
@@ -644,14 +645,15 @@
     # com.googlecode.gyp.xcode.bundle, a pseudo-type that xcode.py interprets
     # to create a single-file mh_bundle.
     _types = {
-      'executable':             'com.apple.product-type.tool',
-      'loadable_module':        'com.googlecode.gyp.xcode.bundle',
-      'shared_library':         'com.apple.product-type.library.dynamic',
-      'static_library':         'com.apple.product-type.library.static',
-      'executable+bundle':      'com.apple.product-type.application',
-      'loadable_module+bundle': 'com.apple.product-type.bundle',
-      'loadable_module+xctest': 'com.apple.product-type.bundle.unit-test',
-      'shared_library+bundle':  'com.apple.product-type.framework',
+      'executable':                  'com.apple.product-type.tool',
+      'loadable_module':             'com.googlecode.gyp.xcode.bundle',
+      'shared_library':              'com.apple.product-type.library.dynamic',
+      'static_library':              'com.apple.product-type.library.static',
+      'executable+bundle':           'com.apple.product-type.application',
+      'loadable_module+bundle':      'com.apple.product-type.bundle',
+      'loadable_module+xctest':      'com.apple.product-type.bundle.unit-test',
+      'shared_library+bundle':       'com.apple.product-type.framework',
+      'executable+extension+bundle': 'com.apple.product-type.app-extension',
     }
 
     target_properties = {
@@ -662,6 +664,7 @@
     type = spec['type']
     is_xctest = int(spec.get('mac_xctest_bundle', 0))
     is_bundle = int(spec.get('mac_bundle', 0)) or is_xctest
+    is_extension = int(spec.get('ios_app_extension', 0))
     if type != 'none':
       type_bundle_key = type
       if is_xctest:
@@ -669,6 +672,10 @@
         assert type == 'loadable_module', (
             'mac_xctest_bundle targets must have type loadable_module '
             '(target %s)' % target_name)
+      elif is_extension:
+        assert is_bundle, ('ios_app_extension flag requires mac_bundle '
+            '(target %s)' % target_name)
+        type_bundle_key += '+extension+bundle'
       elif is_bundle:
         type_bundle_key += '+bundle'
 
diff --git a/pylib/gyp/xcode_emulation.py b/pylib/gyp/xcode_emulation.py
index 859cd5a..2f34bc6 100644
--- a/pylib/gyp/xcode_emulation.py
+++ b/pylib/gyp/xcode_emulation.py
@@ -218,6 +218,9 @@
   def _IsBundle(self):
     return int(self.spec.get('mac_bundle', 0)) != 0
 
+  def _IsIosAppExtension(self):
+    return int(self.spec.get('ios_app_extension', 0)) != 0
+
   def GetFrameworkVersion(self):
     """Returns the framework version of the current target. Only valid for
     bundles."""
@@ -237,7 +240,10 @@
           'WRAPPER_EXTENSION', default=default_wrapper_extension)
       return '.' + self.spec.get('product_extension', wrapper_extension)
     elif self.spec['type'] == 'executable':
-      return '.' + self.spec.get('product_extension', 'app')
+      if self._IsIosAppExtension():
+        return '.' + self.spec.get('product_extension', 'appex')
+      else:
+        return '.' + self.spec.get('product_extension', 'app')
     else:
       assert False, "Don't know extension for '%s', target '%s'" % (
           self.spec['type'], self.spec['target_name'])
@@ -292,6 +298,10 @@
 
   def GetProductType(self):
     """Returns the PRODUCT_TYPE of this target."""
+    if self._IsIosAppExtension():
+      assert self._IsBundle(), ('ios_app_extension flag requires mac_bundle '
+          '(target %s)' % self.spec['target_name'])
+      return 'com.apple.product-type.app-extension'
     if self._IsBundle():
       return {
         'executable': 'com.apple.product-type.application',
@@ -794,6 +804,18 @@
     for directory in framework_dirs:
       ldflags.append('-F' + directory.replace('$(SDKROOT)', sdk_root))
 
+    if sdk_root and self._IsIosAppExtension():
+      # Adds the link flags for extensions. These flags are common for all
+      # extensions and provide loader and main function.
+      # These flags reflect the compilation options used by xcode to compile
+      # extensions.
+      ldflags.append('-lpkstart')
+      ldflags.append(sdk_root +
+          '/System/Library/PrivateFrameworks/PlugInKit.framework/PlugInKit')
+      ldflags.append('-fapplication-extension')
+      ldflags.append('-Xlinker -rpath '
+          '-Xlinker @executable_path/../../Frameworks')
+
     self._Appendf(ldflags, 'CLANG_CXX_LIBRARY', '-stdlib=%s')
 
     self.configname = None
@@ -921,7 +943,7 @@
     """Return a shell command to codesign the iOS output binary so it can
     be deployed to a device.  This should be run as the very last step of the
     build."""
-    if not (self.isIOS and self.spec['type'] == "executable"):
+    if not (self.isIOS and self.spec['type'] == 'executable'):
       return []
 
     settings = self.xcode_settings[configname]
diff --git a/pylib/gyp/xcode_ninja.py b/pylib/gyp/xcode_ninja.py
index 0e5a70c..2a89fa9 100644
--- a/pylib/gyp/xcode_ninja.py
+++ b/pylib/gyp/xcode_ninja.py
@@ -90,6 +90,7 @@
           new_xcode_settings
 
   ninja_target['mac_bundle'] = old_spec.get('mac_bundle', 0)
+  ninja_target['ios_app_extension'] = old_spec.get('ios_app_extension', 0)
   ninja_target['type'] = old_spec['type']
   if ninja_toplevel:
     ninja_target['actions'] = [
diff --git a/pylib/gyp/xcodeproj_file.py b/pylib/gyp/xcodeproj_file.py
index 13eaf3a..2b91f5f 100644
--- a/pylib/gyp/xcodeproj_file.py
+++ b/pylib/gyp/xcodeproj_file.py
@@ -2238,10 +2238,12 @@
   # Mapping from Xcode product-types to settings.  The settings are:
   #  filetype : used for explicitFileType in the project file
   #  prefix : the prefix for the file name
-  #  suffix : the suffix for the filen ame
+  #  suffix : the suffix for the file name
   _product_filetypes = {
     'com.apple.product-type.application':       ['wrapper.application',
                                                  '', '.app'],
+    'com.apple.product-type.app-extension':     ['wrapper.app-extension',
+                                                 '', '.appex'],
     'com.apple.product-type.bundle':            ['wrapper.cfbundle',
                                                  '', '.bundle'],
     'com.apple.product-type.framework':         ['wrapper.framework',
diff --git a/test/ios/extension/ActionExtension/ActionViewController.h b/test/ios/extension/ActionExtension/ActionViewController.h
new file mode 100644
index 0000000..1c92509
--- /dev/null
+++ b/test/ios/extension/ActionExtension/ActionViewController.h
@@ -0,0 +1,9 @@
+// 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.
+
+#import <UIKit/UIKit.h>
+
+@interface ActionViewController : UIViewController
+
+@end
diff --git a/test/ios/extension/ActionExtension/ActionViewController.m b/test/ios/extension/ActionExtension/ActionViewController.m
new file mode 100644
index 0000000..d37bacd
--- /dev/null
+++ b/test/ios/extension/ActionExtension/ActionViewController.m
@@ -0,0 +1,31 @@
+// 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.
+
+#import "ActionViewController.h"
+#import <MobileCoreServices/MobileCoreServices.h>
+
+@interface ActionViewController ()
+
+@end
+
+@implementation ActionViewController
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+}
+
+- (void)didReceiveMemoryWarning {
+  [super didReceiveMemoryWarning];
+  // Dispose of any resources that can be recreated.
+}
+
+- (IBAction)done {
+  // Return any edited content to the host app.
+  // This template doesn't do anything, so we just echo the passed in items.
+  [self.extensionContext
+      completeRequestReturningItems:self.extensionContext.inputItems
+      completionHandler:nil];
+}
+
+@end
diff --git a/test/ios/extension/ActionExtension/Info.plist b/test/ios/extension/ActionExtension/Info.plist
new file mode 100644
index 0000000..f89cd79
--- /dev/null
+++ b/test/ios/extension/ActionExtension/Info.plist
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>en</string>
+	<key>CFBundleDisplayName</key>
+	<string>ActionExtension</string>
+	<key>CFBundleExecutable</key>
+	<string>${EXECUTABLE_NAME}</string>
+	<key>CFBundleIdentifier</key>
+	<string>com.google.gyptest.extension.ActionExtension</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>${PRODUCT_NAME}</string>
+	<key>CFBundlePackageType</key>
+	<string>XPC!</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>NSExtension</key>
+	<dict>
+		<key>NSExtensionAttributes</key>
+		<dict>
+			<key>NSExtensionActivationRule</key>
+			<string>TRUEPREDICATE</string>
+			<key>NSExtensionPointName</key>
+			<string>com.apple.ui-services</string>
+			<key>NSExtensionPointVersion</key>
+			<string>1.0</string>
+		</dict>
+		<key>NSExtensionMainStoryboard</key>
+		<string>MainInterface</string>
+		<key>NSExtensionPointIdentifier</key>
+		<string>com.apple.ui-services</string>
+	</dict>
+</dict>
+</plist>
diff --git a/test/ios/extension/ActionExtension/MainInterface.storyboard b/test/ios/extension/ActionExtension/MainInterface.storyboard
new file mode 100644
index 0000000..5aa5818
--- /dev/null
+++ b/test/ios/extension/ActionExtension/MainInterface.storyboard
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6148" systemVersion="14A229a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="ObA-dk-sSI">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6147"/>
+    </dependencies>
+    <scenes>
+        <!--Action View Controller - Image-->
+        <scene sceneID="7MM-of-jgj">
+            <objects>
+                <viewController title="Image" id="ObA-dk-sSI" customClass="ActionViewController" customModuleProvider="" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="qkL-Od-lgU"/>
+                        <viewControllerLayoutGuide type="bottom" id="n38-gi-rB5"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="zMn-AG-sqS">
+                        <rect key="frame" x="0.0" y="0.0" width="320" height="528"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9ga-4F-77Z">
+                                <rect key="frame" x="0.0" y="64" width="320" height="464"/>
+                            </imageView>
+                            <navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NOA-Dm-cuz">
+                                <rect key="frame" x="0.0" y="20" width="320" height="44"/>
+                                <items>
+                                    <navigationItem id="3HJ-uW-3hn">
+                                        <barButtonItem key="leftBarButtonItem" title="Done" style="done" id="WYi-yp-eM6">
+                                            <connections>
+                                                <action selector="done" destination="ObA-dk-sSI" id="Qdu-qn-U6V"/>
+                                            </connections>
+                                        </barButtonItem>
+                                    </navigationItem>
+                                </items>
+                            </navigationBar>
+                        </subviews>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <constraints>
+                            <constraint firstAttribute="trailing" secondItem="NOA-Dm-cuz" secondAttribute="trailing" id="A05-Pj-hrr"/>
+                            <constraint firstItem="9ga-4F-77Z" firstAttribute="top" secondItem="NOA-Dm-cuz" secondAttribute="bottom" id="Fps-3D-QQW"/>
+                            <constraint firstItem="NOA-Dm-cuz" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="HxO-8t-aoh"/>
+                            <constraint firstAttribute="trailing" secondItem="9ga-4F-77Z" secondAttribute="trailing" id="Ozw-Hg-0yh"/>
+                            <constraint firstItem="9ga-4F-77Z" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="XH5-ld-ONA"/>
+                            <constraint firstItem="n38-gi-rB5" firstAttribute="top" secondItem="9ga-4F-77Z" secondAttribute="bottom" id="eQg-nn-Zy4"/>
+                            <constraint firstItem="NOA-Dm-cuz" firstAttribute="top" secondItem="qkL-Od-lgU" secondAttribute="bottom" id="we0-1t-bgp"/>
+                        </constraints>
+                    </view>
+                    <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+                    <size key="freeformSize" width="320" height="528"/>
+                    <connections>
+                        <outlet property="imageView" destination="9ga-4F-77Z" id="5y6-5w-9QO"/>
+                        <outlet property="view" destination="zMn-AG-sqS" id="Qma-de-2ek"/>
+                    </connections>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="X47-rx-isc" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="252" y="-124"/>
+        </scene>
+    </scenes>
+    <simulatedMetricsContainer key="defaultSimulatedMetrics">
+        <simulatedStatusBarMetrics key="statusBar"/>
+        <simulatedOrientationMetrics key="orientation"/>
+        <simulatedScreenMetrics key="destination" type="retina4"/>
+    </simulatedMetricsContainer>
+</document>
diff --git a/test/ios/extension/ExtensionContainer/AppDelegate.h b/test/ios/extension/ExtensionContainer/AppDelegate.h
new file mode 100644
index 0000000..510e230
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/AppDelegate.h
@@ -0,0 +1,12 @@
+// 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.
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
diff --git a/test/ios/extension/ExtensionContainer/AppDelegate.m b/test/ios/extension/ExtensionContainer/AppDelegate.m
new file mode 100644
index 0000000..1197bc1
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/AppDelegate.m
@@ -0,0 +1,19 @@
+// 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.
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication*)application
+    didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+  // Override point for customization after application launch.
+  return YES;
+}
+
+@end
diff --git a/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard b/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..e8f3cfb
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/Base.lproj/Main.storyboard
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6162" systemVersion="14A238h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6160"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json b/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..f697f61
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,53 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json b/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json
new file mode 100644
index 0000000..4458b40
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/Images.xcassets/LaunchImage.launchimage/Contents.json
@@ -0,0 +1,51 @@
+{
+  "images" : [
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "iphone",
+      "subtype" : "retina4",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "1x"
+    },
+    {
+      "orientation" : "portrait",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    },
+    {
+      "orientation" : "landscape",
+      "idiom" : "ipad",
+      "extent" : "full-screen",
+      "minimum-system-version" : "7.0",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/test/ios/extension/ExtensionContainer/Info.plist b/test/ios/extension/ExtensionContainer/Info.plist
new file mode 100644
index 0000000..31ccf4c
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>CFBundleDevelopmentRegion</key>
+    <string>en</string>
+    <key>CFBundleExecutable</key>
+    <string>ExtensionContainer</string>
+    <key>CFBundleIdentifier</key>
+    <string>com.google.gyptest.extension</string>
+    <key>CFBundleInfoDictionaryVersion</key>
+    <string>6.0</string>
+    <key>CFBundleName</key>
+    <string>${PRODUCT_NAME}</string>
+    <key>CFBundlePackageType</key>
+    <string>APPL</string>
+    <key>CFBundleShortVersionString</key>
+    <string>1.0</string>
+    <key>CFBundleSignature</key>
+    <string>????</string>
+    <key>CFBundleVersion</key>
+    <string>1</string>
+    <key>LSRequiresIPhoneOS</key>
+    <true/>
+    <key>UIMainStoryboardFile</key>
+    <string>Main</string>
+    <key>UIRequiredDeviceCapabilities</key>
+    <array>
+        <string>armv7</string>
+    </array>
+</dict>
+</plist>
diff --git a/test/ios/extension/ExtensionContainer/ViewController.h b/test/ios/extension/ExtensionContainer/ViewController.h
new file mode 100644
index 0000000..fad7754
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/ViewController.h
@@ -0,0 +1,11 @@
+// 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.
+
+#import <UIKit/UIKit.h>
+
+@interface ViewController : UIViewController
+
+
+@end
+
diff --git a/test/ios/extension/ExtensionContainer/ViewController.m b/test/ios/extension/ExtensionContainer/ViewController.m
new file mode 100644
index 0000000..3810fa9
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/ViewController.m
@@ -0,0 +1,24 @@
+// 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.
+
+#import "ViewController.h"
+
+@interface ViewController ()
+
+
+@end
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+  [super viewDidLoad];
+  // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)didReceiveMemoryWarning {
+  [super didReceiveMemoryWarning];
+  // Dispose of any resources that can be recreated.
+}
+
+@end
diff --git a/test/ios/extension/ExtensionContainer/main.m b/test/ios/extension/ExtensionContainer/main.m
new file mode 100644
index 0000000..47aecb5
--- /dev/null
+++ b/test/ios/extension/ExtensionContainer/main.m
@@ -0,0 +1,13 @@
+// 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.
+//
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char* argv[]) {
+  @autoreleasepool {
+    return UIApplicationMain(argc, argv, nil,
+        NSStringFromClass([AppDelegate class]));
+  }
+}
diff --git a/test/ios/extension/extension.gyp b/test/ios/extension/extension.gyp
new file mode 100644
index 0000000..6fa468c
--- /dev/null
+++ b/test/ios/extension/extension.gyp
@@ -0,0 +1,83 @@
+# 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'],
+    ['CXX', '/usr/bin/clang++'],
+  ],
+  'targets': [
+    {
+      'target_name': 'ExtensionContainer',
+      'product_name': 'ExtensionContainer',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'mac_bundle_resources': [
+        'ExtensionContainer/Base.lproj/Main.storyboard',
+      ],
+      'sources': [
+        'ExtensionContainer/AppDelegate.h',
+        'ExtensionContainer/AppDelegate.m',
+        'ExtensionContainer/ViewController.h',
+        'ExtensionContainer/ViewController.m',
+        'ExtensionContainer/main.m',
+      ],
+      'copies': [
+        {
+          'destination': '<(PRODUCT_DIR)/ExtensionContainer.app/PlugIns',
+          'files': [
+            '<(PRODUCT_DIR)/ActionExtension.appex',
+      ]}],
+      'dependencies': [
+        'ActionExtension'
+      ],
+
+      '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': 'ExtensionContainer/Info.plist',
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'ARCHS': [ 'armv7' ],
+        'SDKROOT': 'iphoneos',
+        'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+      },
+    },
+    {
+      'target_name': 'ActionExtension',
+      'product_name': 'ActionExtension',
+      'type': 'executable',
+      'mac_bundle': 1,
+      'ios_app_extension': 1,
+      'sources': [
+        'ActionExtension/ActionViewController.h',
+        'ActionExtension/ActionViewController.m',
+      ],
+      'link_settings': {
+        'libraries': [
+          '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+          '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+          '$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
+        ],
+      },
+      'xcode_settings': {
+        'OTHER_CFLAGS': [
+          '-fobjc-abi-version=2',
+        ],
+        'INFOPLIST_FILE': 'ActionExtension/Info.plist',
+        'GCC_VERSION': 'com.apple.compilers.llvm.clang.1_0',
+        'ARCHS': [ 'armv7' ],
+        'SDKROOT': 'iphoneos',
+        'IPHONEOS_DEPLOYMENT_TARGET': '7.0',
+      },
+    },
+  ],
+}
+
diff --git a/test/ios/gyptest-extension.py b/test/ios/gyptest-extension.py
new file mode 100755
index 0000000..103eb3f
--- /dev/null
+++ b/test/ios/gyptest-extension.py
@@ -0,0 +1,28 @@
+#!/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 ios app extensions are built correctly.
+"""
+
+import TestGyp
+import TestMac
+
+import sys
+if sys.platform == 'darwin' and TestMac.Xcode.Version()>="0600":
+  test = TestGyp.TestGyp(formats=['ninja', 'xcode'])
+
+  test.run_gyp('extension.gyp', chdir='extension')
+
+  test.build('extension.gyp', 'ExtensionContainer', chdir='extension')
+
+  # Test that the extension is .appex
+  test.built_file_must_exist(
+      'ExtensionContainer.app/PlugIns/ActionExtension.appex',
+      chdir='extension')
+
+  test.pass_test()
+