Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: testing/iossim/iossim.mm

Issue 10828070: Don't directly link to the private Xcode framework, instead find it at runtime (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « testing/iossim/iossim.gyp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import <Foundation/Foundation.h> 5 #import <Foundation/Foundation.h>
6 #include <asl.h> 6 #include <asl.h>
7 #include <libgen.h> 7 #include <libgen.h>
8 #include <stdarg.h> 8 #include <stdarg.h>
9 #include <stdio.h> 9 #include <stdio.h>
10 10
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 // If this timeout occurs iossim will likely exit with non-zero status; the 63 // If this timeout occurs iossim will likely exit with non-zero status; the
64 // exception being if the app is invoked and completes execution before the 64 // exception being if the app is invoked and completes execution before the
65 // session is started (this case is handled in session:didStart:withError). 65 // session is started (this case is handled in session:didStart:withError).
66 const NSTimeInterval kSessionStartTimeoutSeconds = 30; 66 const NSTimeInterval kSessionStartTimeoutSeconds = 30;
67 67
68 // While the simulated app is running, its stdout is redirected to a file which 68 // While the simulated app is running, its stdout is redirected to a file which
69 // is polled by iossim and written to iossim's stdout using the following 69 // is polled by iossim and written to iossim's stdout using the following
70 // polling interval. 70 // polling interval.
71 const NSTimeInterval kOutputPollIntervalSeconds = 0.1; 71 const NSTimeInterval kOutputPollIntervalSeconds = 0.1;
72 72
73 // The path within the developer dir of the private Simulator frameworks.
74 NSString* const kSimulatorFrameworkRelativePath =
75 @"Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/"
76 @"iPhoneSimulatorRemoteClient.framework";
77 NSString* const kDevToolsFoundationRelativePath =
78 @"../OtherFrameworks/DevToolsFoundation.framework";
79
73 const char* gToolName = "iossim"; 80 const char* gToolName = "iossim";
74 81
75 void LogError(NSString* format, ...) { 82 void LogError(NSString* format, ...) {
76 va_list list; 83 va_list list;
77 va_start(list, format); 84 va_start(list, format);
78 85
79 NSString* message = 86 NSString* message =
80 [[[NSString alloc] initWithFormat:format arguments:list] autorelease]; 87 [[[NSString alloc] initWithFormat:format arguments:list] autorelease];
81 88
82 fprintf(stderr, "%s: ERROR: %s\n", gToolName, [message UTF8String]); 89 fprintf(stderr, "%s: ERROR: %s\n", gToolName, [message UTF8String]);
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after
241 if (entryFound) { 248 if (entryFound) {
242 LogError(@"Simulated app crashed or exited with non-zero status"); 249 LogError(@"Simulated app crashed or exited with non-zero status");
243 exit(EXIT_FAILURE); 250 exit(EXIT_FAILURE);
244 } 251 }
245 exit(EXIT_SUCCESS); 252 exit(EXIT_SUCCESS);
246 } 253 }
247 @end 254 @end
248 255
249 namespace { 256 namespace {
250 257
258 // Finds the developer dir via xcode-select or the DEVELOPER_DIR environment
259 // variable.
260 NSString* FindDeveloperDir() {
261 // Check the env first.
262 NSDictionary* env = [[NSProcessInfo processInfo] environment];
263 NSString* developerDir = [env objectForKey:@"DEVELOPER_DIR"];
264 if ([developerDir length] > 0)
265 return developerDir;
266
267 // Go look for it via xcode-select.
268 NSTask* xcodeSelectTask = [[[NSTask alloc] init] autorelease];
269 [xcodeSelectTask setLaunchPath:@"/usr/bin/xcode-select"];
270 [xcodeSelectTask setArguments:[NSArray arrayWithObject:@"-print-path"]];
271
272 NSPipe* outputPipe = [NSPipe pipe];
273 [xcodeSelectTask setStandardOutput:outputPipe];
274 NSFileHandle* outputFile = [outputPipe fileHandleForReading];
275
276 [xcodeSelectTask launch];
277 NSData* outputData = [outputFile readDataToEndOfFile];
278 [xcodeSelectTask terminate];
279
280 NSString* output =
281 [[[NSString alloc] initWithData:outputData
282 encoding:NSUTF8StringEncoding] autorelease];
283 output = [output stringByTrimmingCharactersInSet:
284 [NSCharacterSet whitespaceAndNewlineCharacterSet]];
285 if ([output length] == 0)
286 output = nil;
287 return output;
288 }
289
290 // Loads the Simulator framework from the given developer dir.
291 NSBundle* LoadSimulatorFramework(NSString* developerDir) {
292 // The Simulator framework depends on some of the other Xcode private
293 // frameworks; manually load them first so everything can be linked up.
294 NSString* devToolsFoundationPath = [developerDir
295 stringByAppendingPathComponent:kDevToolsFoundationRelativePath];
296 NSBundle* devToolsFoundationBundle =
297 [NSBundle bundleWithPath:devToolsFoundationPath];
298 if (![devToolsFoundationBundle load])
299 return nil;
300 NSString* simBundlePath = [developerDir
301 stringByAppendingPathComponent:kSimulatorFrameworkRelativePath];
302 NSBundle* simBundle = [NSBundle bundleWithPath:simBundlePath];
303 if (![simBundle load])
304 return nil;
305 return simBundle;
306 }
307
308 // Helper to find a class by name and die if it isn't found.
309 Class FindClassByName(NSString* nameOfClass) {
310 Class theClass = NSClassFromString(nameOfClass);
311 if (!theClass) {
312 LogError(@"Failed to find class %@ at runtime.", nameOfClass);
313 exit(EXIT_FAILURE);
314 }
315 return theClass;
316 }
317
251 // Converts the given app path to an application spec, which requires an 318 // Converts the given app path to an application spec, which requires an
252 // absolute path. 319 // absolute path.
253 DTiPhoneSimulatorApplicationSpecifier* BuildAppSpec(NSString* appPath) { 320 DTiPhoneSimulatorApplicationSpecifier* BuildAppSpec(NSString* appPath) {
321 Class applicationSpecifierClass =
322 FindClassByName(@"DTiPhoneSimulatorApplicationSpecifier");
254 if (![appPath isAbsolutePath]) { 323 if (![appPath isAbsolutePath]) {
255 NSString* cwd = [[NSFileManager defaultManager] currentDirectoryPath]; 324 NSString* cwd = [[NSFileManager defaultManager] currentDirectoryPath];
256 appPath = [cwd stringByAppendingPathComponent:appPath]; 325 appPath = [cwd stringByAppendingPathComponent:appPath];
257 } 326 }
258 appPath = [appPath stringByStandardizingPath]; 327 appPath = [appPath stringByStandardizingPath];
259 return [DTiPhoneSimulatorApplicationSpecifier 328 return [applicationSpecifierClass specifierWithApplicationPath:appPath];
260 specifierWithApplicationPath:appPath];
261 } 329 }
262 330
263 // Returns the system root for the given SDK version. If sdkVersion is nil, the 331 // Returns the system root for the given SDK version. If sdkVersion is nil, the
264 // default system root is returned. Will return nil if the sdkVersion is not 332 // default system root is returned. Will return nil if the sdkVersion is not
265 // valid. 333 // valid.
266 DTiPhoneSimulatorSystemRoot* BuildSystemRoot(NSString* sdkVersion) { 334 DTiPhoneSimulatorSystemRoot* BuildSystemRoot(NSString* sdkVersion) {
267 DTiPhoneSimulatorSystemRoot* systemRoot = 335 Class systemRootClass = FindClassByName(@"DTiPhoneSimulatorSystemRoot");
268 [DTiPhoneSimulatorSystemRoot defaultRoot]; 336 DTiPhoneSimulatorSystemRoot* systemRoot = [systemRootClass defaultRoot];
269 if (sdkVersion) 337 if (sdkVersion)
270 systemRoot = [DTiPhoneSimulatorSystemRoot rootWithSDKVersion:sdkVersion]; 338 systemRoot = [systemRootClass rootWithSDKVersion:sdkVersion];
271 339
272 return systemRoot; 340 return systemRoot;
273 } 341 }
274 342
275 // Builds a config object for starting the specified app. 343 // Builds a config object for starting the specified app.
276 DTiPhoneSimulatorSessionConfig* BuildSessionConfig( 344 DTiPhoneSimulatorSessionConfig* BuildSessionConfig(
277 DTiPhoneSimulatorApplicationSpecifier* appSpec, 345 DTiPhoneSimulatorApplicationSpecifier* appSpec,
278 DTiPhoneSimulatorSystemRoot* systemRoot, 346 DTiPhoneSimulatorSystemRoot* systemRoot,
279 NSString* stdoutPath, 347 NSString* stdoutPath,
280 NSString* stderrPath, 348 NSString* stderrPath,
281 NSArray* appArgs, 349 NSArray* appArgs,
282 NSDictionary* appEnv, 350 NSDictionary* appEnv,
283 NSNumber* deviceFamily) { 351 NSNumber* deviceFamily) {
352 Class sessionConfigClass = FindClassByName(@"DTiPhoneSimulatorSessionConfig");
284 DTiPhoneSimulatorSessionConfig* sessionConfig = 353 DTiPhoneSimulatorSessionConfig* sessionConfig =
285 [[[DTiPhoneSimulatorSessionConfig alloc] init] autorelease]; 354 [[[sessionConfigClass alloc] init] autorelease];
286 sessionConfig.applicationToSimulateOnStart = appSpec; 355 sessionConfig.applicationToSimulateOnStart = appSpec;
287 sessionConfig.simulatedSystemRoot = systemRoot; 356 sessionConfig.simulatedSystemRoot = systemRoot;
288 sessionConfig.localizedClientName = @"chromium"; 357 sessionConfig.localizedClientName = @"chromium";
289 sessionConfig.simulatedApplicationStdErrPath = stderrPath; 358 sessionConfig.simulatedApplicationStdErrPath = stderrPath;
290 sessionConfig.simulatedApplicationStdOutPath = stdoutPath; 359 sessionConfig.simulatedApplicationStdOutPath = stdoutPath;
291 sessionConfig.simulatedApplicationLaunchArgs = appArgs; 360 sessionConfig.simulatedApplicationLaunchArgs = appArgs;
292 sessionConfig.simulatedApplicationLaunchEnvironment = appEnv; 361 sessionConfig.simulatedApplicationLaunchEnvironment = appEnv;
293 sessionConfig.simulatedDeviceFamily = deviceFamily; 362 sessionConfig.simulatedDeviceFamily = deviceFamily;
294 return sessionConfig; 363 return sessionConfig;
295 } 364 }
296 365
297 // Builds a simulator session that will use the given delegate. 366 // Builds a simulator session that will use the given delegate.
298 DTiPhoneSimulatorSession* BuildSession(SimulatorDelegate* delegate) { 367 DTiPhoneSimulatorSession* BuildSession(SimulatorDelegate* delegate) {
368 Class sessionClass = FindClassByName(@"DTiPhoneSimulatorSession");
299 DTiPhoneSimulatorSession* session = 369 DTiPhoneSimulatorSession* session =
300 [[[DTiPhoneSimulatorSession alloc] init] autorelease]; 370 [[[sessionClass alloc] init] autorelease];
301 session.delegate = delegate; 371 session.delegate = delegate;
302 return session; 372 return session;
303 } 373 }
304 374
305 // Creates a temporary directory with a unique name based on the provided 375 // Creates a temporary directory with a unique name based on the provided
306 // template. The template should not contain any path separators and be suffixed 376 // template. The template should not contain any path separators and be suffixed
307 // with X's, which will be substituted with a unique alphanumeric string (see 377 // with X's, which will be substituted with a unique alphanumeric string (see
308 // 'man mkdtemp' for details). The directory will be created as a subdirectory 378 // 'man mkdtemp' for details). The directory will be created as a subdirectory
309 // of NSTemporaryDirectory(). For example, if dirNameTemplate is 'test-XXX', 379 // of NSTemporaryDirectory(). For example, if dirNameTemplate is 'test-XXX',
310 // this method would return something like '/path/to/tempdir/test-3n2'. 380 // this method would return something like '/path/to/tempdir/test-3n2'.
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 " Will create a new directory if not specified.\n" 455 " Will create a new directory if not specified.\n"
386 " -e Specifies an environment key=value pair that will be" 456 " -e Specifies an environment key=value pair that will be"
387 " set in the simulated application's environment.\n"); 457 " set in the simulated application's environment.\n");
388 } 458 }
389 459
390 } // namespace 460 } // namespace
391 461
392 int main(int argc, char* const argv[]) { 462 int main(int argc, char* const argv[]) {
393 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 463 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
394 464
395 char* toolName = basename(argv[0]); 465 // basename() may modify the passed in string and it returns a pointer to an
396 if (toolName != NULL) 466 // internal buffer. Give it a copy to modify, and copy what it returns.
397 gToolName = toolName; 467 char* worker = strdup(argv[0]);
468 char* toolName = basename(worker);
469 if (toolName != NULL) {
470 toolName = strdup(toolName);
471 if (toolName != NULL)
472 gToolName = toolName;
473 }
474 if (worker != NULL)
475 free(worker);
398 476
399 NSString* appPath = nil; 477 NSString* appPath = nil;
400 NSString* appName = nil; 478 NSString* appName = nil;
401 NSString* sdkVersion = nil; 479 NSString* sdkVersion = nil;
402 NSString* deviceName = @"iPhone"; 480 NSString* deviceName = @"iPhone";
403 NSString* simHomePath = nil; 481 NSString* simHomePath = nil;
404 NSMutableArray* appArgs = [NSMutableArray array]; 482 NSMutableArray* appArgs = [NSMutableArray array];
405 NSMutableDictionary* appEnv = [NSMutableDictionary dictionary]; 483 NSMutableDictionary* appEnv = [NSMutableDictionary dictionary];
406 484
407 // Parse the optional arguments 485 // Parse the optional arguments
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 appName = [appPath lastPathComponent]; 527 appName = [appPath lastPathComponent];
450 while (++optind < argc) { 528 while (++optind < argc) {
451 [appArgs addObject:[NSString stringWithUTF8String:argv[optind]]]; 529 [appArgs addObject:[NSString stringWithUTF8String:argv[optind]]];
452 } 530 }
453 } else { 531 } else {
454 LogError(@"Unable to parse command line arguments."); 532 LogError(@"Unable to parse command line arguments.");
455 PrintUsage(); 533 PrintUsage();
456 exit(EXIT_FAILURE); 534 exit(EXIT_FAILURE);
457 } 535 }
458 536
537 NSString* developerDir = FindDeveloperDir();
538 if (!developerDir) {
539 LogError(@"Unable to find developer directory.");
540 exit(EXIT_FAILURE);
541 }
542
543 NSBundle* simulatorFramework = LoadSimulatorFramework(developerDir);
544 if (!simulatorFramework) {
545 LogError(@"Failed to load the Simulator Framework.");
546 exit(EXIT_FAILURE);
547 }
548
459 // Make sure the app path provided is legit. 549 // Make sure the app path provided is legit.
460 DTiPhoneSimulatorApplicationSpecifier* appSpec = BuildAppSpec(appPath); 550 DTiPhoneSimulatorApplicationSpecifier* appSpec = BuildAppSpec(appPath);
461 if (!appSpec) { 551 if (!appSpec) {
462 LogError(@"Invalid app path: %@", appPath); 552 LogError(@"Invalid app path: %@", appPath);
463 exit(EXIT_FAILURE); 553 exit(EXIT_FAILURE);
464 } 554 }
465 555
466 // Make sure the SDK path provided is legit (or nil). 556 // Make sure the SDK path provided is legit (or nil).
467 DTiPhoneSimulatorSystemRoot* systemRoot = BuildSystemRoot(sdkVersion); 557 DTiPhoneSimulatorSystemRoot* systemRoot = BuildSystemRoot(sdkVersion);
468 if (!systemRoot) { 558 if (!systemRoot) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 596
507 // Create the config and simulator session. 597 // Create the config and simulator session.
508 DTiPhoneSimulatorSessionConfig* config = BuildSessionConfig(appSpec, 598 DTiPhoneSimulatorSessionConfig* config = BuildSessionConfig(appSpec,
509 systemRoot, 599 systemRoot,
510 stdioPath, 600 stdioPath,
511 stdioPath, 601 stdioPath,
512 appArgs, 602 appArgs,
513 appEnv, 603 appEnv,
514 deviceFamily); 604 deviceFamily);
515 SimulatorDelegate* delegate = 605 SimulatorDelegate* delegate =
516 [[[SimulatorDelegate alloc] initWithStdioPath:stdioPath] autorelease]; 606 [[[SimulatorDelegate alloc] initWithStdioPath:stdioPath] autorelease];
517 DTiPhoneSimulatorSession* session = BuildSession(delegate); 607 DTiPhoneSimulatorSession* session = BuildSession(delegate);
518 608
519 // Start the simulator session. 609 // Start the simulator session.
520 NSError* error; 610 NSError* error;
521 BOOL started = [session requestStartWithConfig:config 611 BOOL started = [session requestStartWithConfig:config
522 timeout:kSessionStartTimeoutSeconds 612 timeout:kSessionStartTimeoutSeconds
523 error:&error]; 613 error:&error];
524 614
525 // Spin the runtime indefinitely. When the delegate gets the message that the 615 // Spin the runtime indefinitely. When the delegate gets the message that the
526 // app has quit it will exit this program. 616 // app has quit it will exit this program.
527 if (started) 617 if (started)
528 [[NSRunLoop mainRunLoop] run]; 618 [[NSRunLoop mainRunLoop] run];
529 else 619 else
530 LogError(@"Simulator failed to start: %@", [error localizedDescription]); 620 LogError(@"Simulator failed to start: %@", [error localizedDescription]);
531 621
532 // Note that this code is only executed if the simulator fails to start 622 // Note that this code is only executed if the simulator fails to start
533 // because once the main run loop is started, only the delegate calling 623 // because once the main run loop is started, only the delegate calling
534 // exit() will end the program. 624 // exit() will end the program.
535 [pool drain]; 625 [pool drain];
536 return EXIT_FAILURE; 626 return EXIT_FAILURE;
537 } 627 }
OLDNEW
« no previous file with comments | « testing/iossim/iossim.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698