<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[170189] trunk/Tools</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/170189">170189</a></dd>
<dt>Author</dt> <dd>dbates@webkit.org</dd>
<dt>Date</dt> <dd>2014-06-20 10:20:48 -0700 (Fri, 20 Jun 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Teach run-{safari, webkit-app} about iOS Simulator
https://bugs.webkit.org/show_bug.cgi?id=133986

Reviewed by David Kilzer.

Extract the logic from old-run-webkit-tests to install and launch {DumpRenderTree, WebKitTestRunnerApp}.app
into general-purpose routines in webkitdirs.pm so that they can be used both by script old-run-webkit-tests
and run-safari.

* Scripts/old-run-webkit-tests:
(installAndLaunchDumpToolAppUsingNotification): Extracted logic to install and launch {DumpRenderTree,
WebKitTestRunnerApp}.app into webkitdirs::installAndLaunchIOSWebKitAppInSimulator() and modified code
to call it.
(openIPhoneSimulator): Deleted; moved logic to webkitdirs::openIOSSimulator().
(quitIPhoneSimulator): Deleted; moved logic to webkitdirs::quitIOSSimulator().
* Scripts/run-webkit-app: Modified to call runIOSWebKitApp() when the iOS simulator SDK is used
(say, by specifying the optional command-line argument --simulator). For now, die() with an error
when the iOS device SDK is used as we don't support launching an app on the device at this time.
* Scripts/webkitdirs.pm:
(xcodeSDKVersion): Added.
(setupIOSWebKitEnvironment): Added.
(installedMobileSafariBundle): Added.
(mobileSafariBundle): Added.
(plistPathFromBundle): Added.
(appIdentiferFromBundle): Added.
(appDisplayNameFromBundle): Added.
(loadIPhoneSimulatorNotificationIfNeeded): Added.
(openIOSSimulator): Added.
(quitIOSSimulator): Added.
(iosSimulatorDeviceByName): Added.
(iosSimulatorRuntime): Added.
(findOrCreateSimulatorForIOSDevice): Added.
(runIOSWebKitAppInSimulator): Added.
(installAndLaunchIOSWebKitAppInSimulator): Added.
(runIOSWebKitApp): Added.
(runSafari): Modified to call runIOSWebKitAppInSimulator() the iOS simulator SDK is used. For now,
die() with an error when the iOS device SDK is used as we don't support launching Safari on the
device at this time.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsScriptsoldrunwebkittests">trunk/Tools/Scripts/old-run-webkit-tests</a></li>
<li><a href="#trunkToolsScriptsrunwebkitapp">trunk/Tools/Scripts/run-webkit-app</a></li>
<li><a href="#trunkToolsScriptswebkitdirspm">trunk/Tools/Scripts/webkitdirs.pm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (170188 => 170189)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2014-06-20 17:16:37 UTC (rev 170188)
+++ trunk/Tools/ChangeLog        2014-06-20 17:20:48 UTC (rev 170189)
</span><span class="lines">@@ -1,3 +1,44 @@
</span><ins>+2014-06-20  Daniel Bates  &lt;dabates@apple.com&gt;
+
+        Teach run-{safari, webkit-app} about iOS Simulator
+        https://bugs.webkit.org/show_bug.cgi?id=133986
+
+        Reviewed by David Kilzer.
+
+        Extract the logic from old-run-webkit-tests to install and launch {DumpRenderTree, WebKitTestRunnerApp}.app
+        into general-purpose routines in webkitdirs.pm so that they can be used both by script old-run-webkit-tests
+        and run-safari.
+
+        * Scripts/old-run-webkit-tests:
+        (installAndLaunchDumpToolAppUsingNotification): Extracted logic to install and launch {DumpRenderTree,
+        WebKitTestRunnerApp}.app into webkitdirs::installAndLaunchIOSWebKitAppInSimulator() and modified code
+        to call it.
+        (openIPhoneSimulator): Deleted; moved logic to webkitdirs::openIOSSimulator().
+        (quitIPhoneSimulator): Deleted; moved logic to webkitdirs::quitIOSSimulator().
+        * Scripts/run-webkit-app: Modified to call runIOSWebKitApp() when the iOS simulator SDK is used
+        (say, by specifying the optional command-line argument --simulator). For now, die() with an error
+        when the iOS device SDK is used as we don't support launching an app on the device at this time.
+        * Scripts/webkitdirs.pm:
+        (xcodeSDKVersion): Added.
+        (setupIOSWebKitEnvironment): Added.
+        (installedMobileSafariBundle): Added.
+        (mobileSafariBundle): Added.
+        (plistPathFromBundle): Added.
+        (appIdentiferFromBundle): Added.
+        (appDisplayNameFromBundle): Added.
+        (loadIPhoneSimulatorNotificationIfNeeded): Added.
+        (openIOSSimulator): Added.
+        (quitIOSSimulator): Added.
+        (iosSimulatorDeviceByName): Added.
+        (iosSimulatorRuntime): Added.
+        (findOrCreateSimulatorForIOSDevice): Added.
+        (runIOSWebKitAppInSimulator): Added.
+        (installAndLaunchIOSWebKitAppInSimulator): Added.
+        (runIOSWebKitApp): Added.
+        (runSafari): Modified to call runIOSWebKitAppInSimulator() the iOS simulator SDK is used. For now,
+        die() with an error when the iOS device SDK is used as we don't support launching Safari on the
+        device at this time.
+
</ins><span class="cx"> 2014-06-19  Anders Carlsson  &lt;andersca@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add WTF::Optional class
</span></span></pre></div>
<a id="trunkToolsScriptsoldrunwebkittests"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/old-run-webkit-tests (170188 => 170189)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/old-run-webkit-tests        2014-06-20 17:16:37 UTC (rev 170188)
+++ trunk/Tools/Scripts/old-run-webkit-tests        2014-06-20 17:20:48 UTC (rev 170189)
</span><span class="lines">@@ -128,9 +128,7 @@
</span><span class="cx"> sub validateSkippedArg($$;$);
</span><span class="cx"> sub writeToFile($$);
</span><span class="cx"> sub installAndLaunchDumpToolAppUsingNotification($$);
</span><del>-sub openIPhoneSimulator();
</del><span class="cx"> sub quitDumpToolUsingNotification();
</span><del>-sub quitIPhoneSimulator();
</del><span class="cx"> sub simulatorSessionUUID();
</span><span class="cx"> 
</span><span class="cx"> # Argument handling
</span><span class="lines">@@ -460,7 +458,7 @@
</span><span class="cx"> my $productDir = productDir();
</span><span class="cx"> $productDir .= &quot;/Programs&quot; if isGtk();
</span><span class="cx"> 
</span><del>-quitIPhoneSimulator() if isIOSWebKit();
</del><ins>+quitIOSSimulator() if isIOSWebKit();
</ins><span class="cx"> 
</span><span class="cx"> # Save the current directory before chaging it via chdirWebKit
</span><span class="cx"> my $currentDir = cwd();
</span><span class="lines">@@ -503,7 +501,7 @@
</span><span class="cx">     eval 'use DumpRenderTreeSupport;';
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-openIPhoneSimulator() if isIOSWebKit();
</del><ins>+openIOSSimulator() if isIOSWebKit();
</ins><span class="cx"> 
</span><span class="cx"> if (isAppleMacWebKit()) {
</span><span class="cx">     push @INC, $productDir;
</span><span class="lines">@@ -1164,7 +1162,7 @@
</span><span class="cx"> 
</span><span class="cx"> !$isDumpToolOpen || die &quot;Failed to close $dumpToolName.\n&quot;;
</span><span class="cx"> 
</span><del>-quitIPhoneSimulator() if isIOSWebKit();
</del><ins>+quitIOSSimulator() if isIOSWebKit();
</ins><span class="cx"> 
</span><span class="cx"> $isHttpdOpen = !closeHTTPD();
</span><span class="cx"> closeWebSocketServer();
</span><span class="lines">@@ -1362,105 +1360,19 @@
</span><span class="cx"> sub installAndLaunchDumpToolAppUsingNotification($$)
</span><span class="cx"> {
</span><span class="cx">     my ($args, $cleanEnv) = @_;
</span><del>-
-    my $iPhoneSimulatorNotification = new IPhoneSimulatorNotification;
-    $iPhoneSimulatorNotification-&gt;startObservingApplicationLaunchedNotification();
-
-    my $makeNSDictionaryFromHash = sub {
-        my ($dict) = @_;
-        my $result = NSMutableDictionary-&gt;alloc()-&gt;initWithCapacity_(scalar(keys %{$dict}));
-        for my $key (keys %{$dict}) {
-            $result-&gt;setObject_forKey_(NSString-&gt;stringWithCString_($dict-&gt;{$key}), NSString-&gt;stringWithCString_($key));
-        }
-        return $result-&gt;autorelease();
-    };
-
-    my $makeNSArrayFromArray = sub {
-        my ($array) = @_;
-        my $result = NSMutableArray-&gt;alloc()-&gt;initWithCapacity_(scalar(@{$array}));
-        for my $item (@{$array}) {
-            $result-&gt;addObject_(NSString-&gt;stringWithCString_($item));
-        }
-        return $result-&gt;autorelease();
-    };
-
-    my $deviceName = &quot;iPhone 5 WebKit Tester&quot;;
-    my $deviceType = &quot;com.apple.CoreSimulator.SimDeviceType.iPhone-5&quot;;
-
-    if (architecture() eq 'x86_64') {
-        $deviceName = &quot;iPhone 5s WebKit Tester&quot;;
-        $deviceType = &quot;com.apple.CoreSimulator.SimDeviceType.iPhone-5s&quot;;
-    }
-
-    chomp(my $sdkVersion = `xcrun --sdk iphonesimulator --show-sdk-version`);
-    $sdkVersion =~ s/\./-/;
-
-    my $runtime = &quot;com.apple.CoreSimulator.SimRuntime.iOS-$sdkVersion&quot;;
-
-    my @devices = iOSSimulatorDevices();
-    my $device = (grep {
-        $_-&gt;{name} eq $deviceName and $_-&gt;{runtime} eq $runtime and $_-&gt;{deviceType} eq $deviceType;
-    } @devices)[0];
-
-    if (not $device) {
-        print &quot;Creating simulator device: $deviceName\n&quot;;
-        $device = createiOSSimulatorDevice($deviceName, $deviceType, $runtime);
-    } else {
-        print &quot;Found simulator device with properties: &quot; . Dumper($device);
-    }
-
-    my $identifier = iOSDumpToolAppIdentifier();
-    my $applicationPath;
-
</del><ins>+    my $productDir = productDir();
+    my $appBundle;
</ins><span class="cx">     if ($useWebKitTestRunner) {
</span><del>-        $applicationPath = &quot;$productDir/WebKitTestRunnerApp.app&quot;;
</del><ins>+        $appBundle = &quot;$productDir/WebKitTestRunnerApp.app&quot;;
</ins><span class="cx">     } else {
</span><del>-        $applicationPath = &quot;$productDir/DumpRenderTree.app&quot;;
</del><ins>+        $appBundle = &quot;$productDir/DumpRenderTree.app&quot;;
</ins><span class="cx">     }
</span><del>-
-    my $dict = {
-        applicationArguments =&gt; &amp;$makeNSArrayFromArray($args),
-        applicationEnvironment =&gt; &amp;$makeNSDictionaryFromHash($cleanEnv),
-        applicationIdentifier =&gt; NSString-&gt;stringWithCString_($identifier),
-        applicationPath =&gt; NSString-&gt;stringWithCString_($applicationPath),
-        deviceUDID =&gt; NSString-&gt;stringWithCString_($device-&gt;{UDID}),
-        sessionUUID =&gt; NSString-&gt;stringWithCString_(simulatorSessionUUID()),
-    };
-    $iPhoneSimulatorNotification-&gt;postStartSessionNotification($dict);
-
-    while (!$iPhoneSimulatorNotification-&gt;hasReceivedApplicationLaunchedNotification()) {
-        my $date = NSDate-&gt;alloc()-&gt;initWithTimeIntervalSinceNow_(0.1);
-        NSRunLoop-&gt;currentRunLoop-&gt;runUntilDate_($date);
-        $date-&gt;release();
-    }
-
-    print &quot;$identifier has launched.\n&quot;;
-
-    $iPhoneSimulatorNotification-&gt;stopObservingApplicationLaunchedNotification();
-
-    return $iPhoneSimulatorNotification-&gt;applicationLaunchedApplicationPID();
</del><ins>+    my $simulatorOptions = {applicationArguments =&gt; $args, applicationEnvironment =&gt; $cleanEnv, sessionUUID =&gt; simulatorSessionUUID()};
+    my $pid = installAndLaunchIOSWebKitAppInSimulator($appBundle, findOrCreateSimulatorForIOSDevice(&quot;WebKit Tester&quot;), $simulatorOptions);
+    print appDisplayNameFromBundle($appBundle) . &quot; has launched.\n&quot;;
+    return $pid;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub openIPhoneSimulator()
-{
-    my $iPhoneSimulatorNotification = new IPhoneSimulatorNotification;
-    $iPhoneSimulatorNotification-&gt;startObservingReadyNotification();
-
-    my $deviceName = architecture() eq 'i386' ? &quot;iPhone 5&quot; : &quot;iPhone 5s&quot;;
-
-    system &quot;open&quot;, &quot;-a&quot;, $simulatorApp, &quot;--args&quot;, &quot;-SessionOnLaunch&quot;, &quot;NO&quot;, &quot;-SimulateDevice&quot;, $deviceName;
-
-    die $! if exitStatus($?);
-
-    while (!$iPhoneSimulatorNotification-&gt;hasReceivedReadyNotification()) {
-        my $date = NSDate-&gt;alloc()-&gt;initWithTimeIntervalSinceNow_(0.1);
-        NSRunLoop-&gt;currentRunLoop-&gt;runUntilDate_($date);
-        $date-&gt;release();
-    }
-
-    $iPhoneSimulatorNotification-&gt;stopObservingReadyNotification();
-}
-
</del><span class="cx"> sub quitDumpToolUsingNotification()
</span><span class="cx"> {
</span><span class="cx">     my $iPhoneSimulatorNotification = new IPhoneSimulatorNotification;
</span><span class="lines">@@ -1488,11 +1400,6 @@
</span><span class="cx">     $iPhoneSimulatorNotification-&gt;stopObservingApplicationQuitNotification();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub quitIPhoneSimulator()
-{
-    system &quot;osascript&quot;, &quot;-e&quot;, &quot;tell application \&quot;iOS Simulator\&quot; to quit&quot;;
-}
-
</del><span class="cx"> sub simulatorSessionUUID()
</span><span class="cx"> {
</span><span class="cx">     return &quot;theAwesomeUniqueSessionIdentifierForDumpRenderTree&quot;;
</span></span></pre></div>
<a id="trunkToolsScriptsrunwebkitapp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/run-webkit-app (170188 => 170189)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/run-webkit-app        2014-06-20 17:16:37 UTC (rev 170188)
+++ trunk/Tools/Scripts/run-webkit-app        2014-06-20 17:20:48 UTC (rev 170189)
</span><span class="lines">@@ -43,4 +43,7 @@
</span><span class="cx"> checkFrameworks();
</span><span class="cx"> 
</span><span class="cx"> my $appPath = shift(@ARGV);
</span><ins>+if (isIOSWebKit()) {
+    exit exitStatus(runIOSWebKitApp($appPath));
+}
</ins><span class="cx"> exit exitStatus(runMacWebKitApp($appPath, USE_OPEN_COMMAND));
</span></span></pre></div>
<a id="trunkToolsScriptswebkitdirspm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/Scripts/webkitdirs.pm (170188 => 170189)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/Scripts/webkitdirs.pm        2014-06-20 17:16:37 UTC (rev 170188)
+++ trunk/Tools/Scripts/webkitdirs.pm        2014-06-20 17:20:48 UTC (rev 170189)
</span><span class="lines">@@ -52,6 +52,7 @@
</span><span class="cx">        &amp;XcodeOptionString
</span><span class="cx">        &amp;XcodeOptionStringNoConfig
</span><span class="cx">        &amp;XcodeOptions
</span><ins>+       &amp;appDisplayNameFromBundle
</ins><span class="cx">        &amp;baseProductDir
</span><span class="cx">        &amp;chdirWebKit
</span><span class="cx">        &amp;checkFrameworks
</span><span class="lines">@@ -59,10 +60,16 @@
</span><span class="cx">        &amp;cmakeBasedPortName
</span><span class="cx">        &amp;currentSVNRevision
</span><span class="cx">        &amp;debugSafari
</span><ins>+       &amp;findOrCreateSimulatorForIOSDevice
+       &amp;installAndLaunchIOSWebKitAppInSimulator
+       &amp;iosSimulatorDeviceByName
</ins><span class="cx">        &amp;nmPath
</span><ins>+       &amp;openIOSSimulator
</ins><span class="cx">        &amp;passedConfiguration
</span><span class="cx">        &amp;printHelpAndExitForRunAndDebugWebKitAppIfNeeded
</span><span class="cx">        &amp;productDir
</span><ins>+       &amp;quitIOSSimulator
+       &amp;runIOSWebKitApp
</ins><span class="cx">        &amp;runMacWebKitApp
</span><span class="cx">        &amp;safariPath
</span><span class="cx">        &amp;setConfiguration
</span><span class="lines">@@ -93,6 +100,7 @@
</span><span class="cx"> my $currentSVNRevision;
</span><span class="cx"> my $debugger;
</span><span class="cx"> my $iPhoneSimulatorVersion;
</span><ins>+my $didLoadIPhoneSimulatorNotification;
</ins><span class="cx"> my $nmPath;
</span><span class="cx"> my $osXVersion;
</span><span class="cx"> my $generateDsym;
</span><span class="lines">@@ -437,7 +445,18 @@
</span><span class="cx">     return $sdkPath;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub xcodeSDKVersion
+{
+    determineXcodeSDK();
</ins><span class="cx"> 
</span><ins>+    die &quot;Can't find the SDK version because no Xcode SDK was specified&quot; if !$xcodeSDK;
+
+    chomp(my $sdkVersion = `xcrun --sdk $xcodeSDK --show-sdk-version`);
+    die &quot;Failed to get SDK version from xcrun&quot; if exitStatus($?);
+
+    return $sdkVersion;
+}
+
</ins><span class="cx"> sub programFilesPath
</span><span class="cx"> {
</span><span class="cx">     return $programFilesPath if defined $programFilesPath;
</span><span class="lines">@@ -2116,6 +2135,229 @@
</span><span class="cx">     setUpGuardMallocIfNeeded();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub setupIOSWebKitEnvironment($)
+{
+    my ($dyldFrameworkPath) = @_;
+    $dyldFrameworkPath = File::Spec-&gt;rel2abs($dyldFrameworkPath);
+
+    $ENV{DYLD_FRAMEWORK_PATH} = $dyldFrameworkPath;
+    $ENV{DYLD_LIBRARY_PATH} = $dyldFrameworkPath;
+
+    setUpGuardMallocIfNeeded();
+}
+
+sub installedMobileSafariBundle()
+{
+    return File::Spec-&gt;catfile(XcodeSDKPath(), &quot;Applications&quot;, &quot;MobileSafari.app&quot;);
+}
+
+sub mobileSafariBundle()
+{
+    determineConfigurationProductDir();
+
+    # Use MobileSafari.app in product directory if present.
+    if (isAppleMacWebKit() &amp;&amp; -d &quot;$configurationProductDir/MobileSafari.app&quot;) {
+        return &quot;$configurationProductDir/MobileSafari.app&quot;;
+    }
+    return installedMobileSafariBundle();
+}
+
+sub plistPathFromBundle($)
+{
+    my ($appBundle) = @_;
+    return &quot;$appBundle/Info.plist&quot; if -f &quot;$appBundle/Info.plist&quot;; # iOS app bundle
+    return &quot;$appBundle/Contents/Info.plist&quot; if &quot;$appBundle/Contents/Info.plist&quot;; # Mac app bundle
+    return &quot;&quot;;
+}
+
+sub appIdentiferFromBundle($)
+{
+    my ($appBundle) = @_;
+    my $plistPath = plistPathFromBundle($appBundle);
+    chomp(my $bundleIdentifer = `defaults read '$plistPath' CFBundleIdentifier 2&gt; /dev/null`);
+    return $bundleIdentifer;
+}
+
+sub appDisplayNameFromBundle($)
+{
+    my ($appBundle) = @_;
+    my $plistPath = plistPathFromBundle($appBundle);
+    chomp(my $bundleDisplayName = `defaults read '$plistPath' CFBundleDisplayName 2&gt; /dev/null`);
+    return $bundleDisplayName;
+}
+
+sub loadIPhoneSimulatorNotificationIfNeeded()
+{
+    return if $didLoadIPhoneSimulatorNotification;
+    push(@INC, productDir() . &quot;/lib/perl5/darwin-thread-multi-2level&quot;);
+    require IPhoneSimulatorNotification;
+    $didLoadIPhoneSimulatorNotification = 1;
+}
+
+sub openIOSSimulator()
+{
+    chomp(my $developerDirectory = $ENV{DEVELOPER_DIR} || `xcode-select --print-path`);
+    my $iosSimulatorPath = File::Spec-&gt;catfile($developerDirectory, &quot;Applications&quot;, &quot;iOS Simulator.app&quot;);
+
+    loadIPhoneSimulatorNotificationIfNeeded();
+
+    my $iPhoneSimulatorNotification = new IPhoneSimulatorNotification;
+    $iPhoneSimulatorNotification-&gt;startObservingReadyNotification();
+    system(&quot;open&quot;, &quot;-a&quot;, $iosSimulatorPath, &quot;--args&quot;, &quot;-SessionOnLaunch&quot;, &quot;NO&quot;) == 0 or die &quot;Failed to open $iosSimulatorPath: $!&quot;;
+    while (!$iPhoneSimulatorNotification-&gt;hasReceivedReadyNotification()) {
+        my $date = NSDate-&gt;alloc()-&gt;initWithTimeIntervalSinceNow_(0.1);
+        NSRunLoop-&gt;currentRunLoop-&gt;runUntilDate_($date);
+        $date-&gt;release();
+    }
+    $iPhoneSimulatorNotification-&gt;stopObservingReadyNotification();
+}
+
+sub quitIOSSimulator()
+{
+    return system {&quot;osascript&quot;} &quot;osascript&quot;, &quot;-e&quot;, 'tell application &quot;iOS Simulator&quot; to quit';
+}
+
+sub iosSimulatorDeviceByName($)
+{
+    my ($simulatorName) = @_;
+    my @devices = grep {$_-&gt;{name} eq $simulatorName} iOSSimulatorDevices();
+    my $deviceToUse = $devices[0];
+    if (@devices &gt; 1) {
+        print &quot;Warning: Found more than one simulator device named '$simulatorName'.\n&quot;;
+        print &quot;         Using simulator device with UDID: $deviceToUse-&gt;{UDID}.\n&quot;;
+        print &quot;         To see the list of simulator devices, run:\n&quot;;
+        print &quot;         xcrun --sdk iphonesimulator simctl list\n&quot;;
+    }
+    return $deviceToUse;
+}
+
+sub iosSimulatorRuntime()
+{
+    my $xcodeSDKVersion = xcodeSDKVersion();
+    $xcodeSDKVersion =~ s/\./-/;
+    return &quot;com.apple.CoreSimulator.SimRuntime.iOS-$xcodeSDKVersion&quot;;
+}
+
+sub findOrCreateSimulatorForIOSDevice($)
+{
+    my ($simulatorNameSuffix) = @_;
+    my $simulatorName;
+    my $simulatorDeviceType;
+    if (architecture() eq &quot;x86_64&quot;) {
+        $simulatorName = &quot;iPhone 5s &quot; . $simulatorNameSuffix;
+        $simulatorDeviceType = &quot;com.apple.CoreSimulator.SimDeviceType.iPhone-5s&quot;;
+    } else {
+        $simulatorName = &quot;iPhone 5 &quot; . $simulatorNameSuffix;
+        $simulatorDeviceType = &quot;com.apple.CoreSimulator.SimDeviceType.iPhone-5&quot;;
+    }
+    my $simulatedDevice = iosSimulatorDeviceByName($simulatorName);
+    return $simulatedDevice if $simulatedDevice;
+    return createiOSSimulatorDevice($simulatorName, $simulatorDeviceType, iosSimulatorRuntime());
+}
+
+sub runIOSWebKitAppInSimulator($;$)
+{
+    my ($appBundle, $simulatorOptions) = @_;
+    my $productDir = productDir();
+    my $appDisplayName = appDisplayNameFromBundle($appBundle);
+    print &quot;Starting $appDisplayName with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n&quot;;
+
+    $simulatorOptions = {} unless $simulatorOptions;
+
+    my %simulatorENV;
+    %simulatorENV = %{$simulatorOptions-&gt;{applicationEnvironment}} if $simulatorOptions-&gt;{applicationEnvironment};
+    {
+        local %ENV; # Shadow global-scope %ENV so that changes to it will not be seen outside of this scope.
+        setupIOSWebKitEnvironment($productDir);
+        %simulatorENV = %ENV;
+    }
+    $simulatorOptions-&gt;{applicationEnvironment} = \%simulatorENV;
+    return installAndLaunchIOSWebKitAppInSimulator($appBundle, findOrCreateSimulatorForIOSDevice(&quot;For WebKit Development&quot;), $simulatorOptions) &lt;= 0;
+}
+
+# Launches the iOS WebKit-based application in the specified simulator device and dynamically
+# linked against the built WebKit. The application will be installed if applicable.
+#
+# Args:
+#   $appBundle: the path to the app bundle to launch.
+#   $simulatedDevice: the simulator device to use to run the app.
+#   $simulatorOptions: a hash reference representing optional simulator options.
+#     sessionUUID: a unique identifer to use for the iOS Simulator session. Defaults to an identifer
+#                  of the form &quot;theAwesomeUniqueSessionIdentifierForX&quot; where X is the display name of
+#                  the specified app.
+#     applicationArguments: an array reference representing the arguments to pass to the app (defaults to \@ARGV).
+#     applicationEnvironment: a hash reference representing the environment variables to use when launching the app (defaults to {}).
+#
+# Returns the process identifier of the launched app.
+sub installAndLaunchIOSWebKitAppInSimulator($$;$)
+{
+    my ($appBundle, $simulatedDevice, $simulatorOptions) = @_;
+
+    loadIPhoneSimulatorNotificationIfNeeded();
+
+    my $makeNSDictionaryFromHash = sub {
+        my ($dict) = @_;
+        my $result = NSMutableDictionary-&gt;alloc()-&gt;initWithCapacity_(scalar(keys %{$dict}));
+        for my $key (keys %{$dict}) {
+            $result-&gt;setObject_forKey_(NSString-&gt;stringWithCString_($dict-&gt;{$key}), NSString-&gt;stringWithCString_($key));
+        }
+        return $result-&gt;autorelease();
+    };
+    my $makeNSArrayFromArray = sub {
+        my ($array) = @_;
+        my $result = NSMutableArray-&gt;alloc()-&gt;initWithCapacity_(scalar(@{$array}));
+        for my $item (@{$array}) {
+            $result-&gt;addObject_(NSString-&gt;stringWithCString_($item));
+        }
+        return $result-&gt;autorelease();
+    };
+
+    my $simulatorENVHashRef = {};
+    $simulatorENVHashRef = $simulatorOptions-&gt;{applicationEnvironment} if $simulatorOptions &amp;&amp; $simulatorOptions-&gt;{applicationEnvironment};
+    my $applicationArguments = \@ARGV;
+    $applicationArguments = $simulatorOptions-&gt;{applicationArguments} if $simulatorOptions &amp;&amp; $simulatorOptions-&gt;{applicationArguments};
+    my $sessionUUID;
+    if ($simulatorOptions &amp;&amp; $simulatorOptions-&gt;{sessionUUID}) {
+        $sessionUUID = $simulatorOptions-&gt;{sessionUUID};
+    } else {
+        $sessionUUID = &quot;theAwesomeUniqueSessionIdentifierFor&quot; . appDisplayNameFromBundle($appBundle);
+    }
+    # FIXME: We should have the iOS application adopt the files descriptors for our standard output and error streams.
+    my $sessionInfo = {
+        applicationArguments =&gt; &amp;$makeNSArrayFromArray($applicationArguments),
+        applicationEnvironment =&gt; &amp;$makeNSDictionaryFromHash($simulatorENVHashRef),
+        applicationIdentifier =&gt; NSString-&gt;stringWithCString_(appIdentiferFromBundle($appBundle)),
+        applicationPath =&gt; NSString-&gt;stringWithCString_($appBundle),
+        deviceUDID =&gt; NSString-&gt;stringWithCString_($simulatedDevice-&gt;{UDID}),
+        sessionUUID =&gt; NSString-&gt;stringWithCString_($sessionUUID),
+    };
+
+    openIOSSimulator();
+
+    my $iPhoneSimulatorNotification = new IPhoneSimulatorNotification;
+    $iPhoneSimulatorNotification-&gt;startObservingApplicationLaunchedNotification();
+    $iPhoneSimulatorNotification-&gt;postStartSessionNotification($sessionInfo);
+    while (!$iPhoneSimulatorNotification-&gt;hasReceivedApplicationLaunchedNotification()) {
+        my $date = NSDate-&gt;alloc()-&gt;initWithTimeIntervalSinceNow_(0.1);
+        NSRunLoop-&gt;currentRunLoop-&gt;runUntilDate_($date);
+        $date-&gt;release();
+    }
+    $iPhoneSimulatorNotification-&gt;stopObservingApplicationLaunchedNotification();
+    return $iPhoneSimulatorNotification-&gt;applicationLaunchedApplicationPID();
+}
+
+sub runIOSWebKitApp($)
+{
+    my ($appBundle) = @_;
+    if (willUseIOSDeviceSDKWhenBuilding()) {
+        die &quot;Only running Safari in iOS Simulator is supported now.&quot;;
+    }
+    if (willUseIOSSimulatorSDKWhenBuilding()) {
+        return runIOSWebKitAppInSimulator($appBundle);
+    }
+    die &quot;Not using an iOS SDK.&quot;
+}
+
</ins><span class="cx"> sub runMacWebKitApp($;$)
</span><span class="cx"> {
</span><span class="cx">     my ($appPath, $useOpenCommand) = @_;
</span><span class="lines">@@ -2189,6 +2431,9 @@
</span><span class="cx"> 
</span><span class="cx"> sub runSafari
</span><span class="cx"> {
</span><ins>+    if (isIOSWebKit()) {
+        return runIOSWebKitApp(mobileSafariBundle());
+    }
</ins><span class="cx"> 
</span><span class="cx">     if (isAppleMacWebKit()) {
</span><span class="cx">         return runMacWebKitApp(safariPath());
</span></span></pre>
</div>
</div>

</body>
</html>