From 50bd3aeec0045dbe2d7be5b1a0716afa7c496431 Mon Sep 17 00:00:00 2001 From: Alan Zeino Date: Wed, 17 Dec 2025 16:13:28 -0800 Subject: [PATCH] Update xcode_locator to support a selected Xcode not found by LSCopyApplicationURLsForBundleIdentifier LSCopyApplicationURLsForBundleIdentifier will not return an Xcode that macOS considers invalid, even if that Xcode works totally fine on that macOS version. This is a temporary fix until we roll out Xcode 26. --- tools/osx/xcode_locator.m | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tools/osx/xcode_locator.m b/tools/osx/xcode_locator.m index c602b0bb4bbd53..e4873b7ebd18ae 100644 --- a/tools/osx/xcode_locator.m +++ b/tools/osx/xcode_locator.m @@ -116,6 +116,21 @@ static void AddEntryToDictionary( return version; } +static NSString *SelectedXcode(void) { + NSTask *t = [NSTask new]; + t.launchPath = @"/usr/bin/xcode-select"; + t.arguments = @[ @"-p" ]; + NSPipe *p = [NSPipe pipe]; + t.standardOutput = p; + [t launch]; + [t waitUntilExit]; + NSString *devDir = [[[NSString alloc] + initWithData:[[p fileHandleForReading] readDataToEndOfFile] + encoding:NSUTF8StringEncoding] + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + return devDir; +} + // Searches for all available Xcodes in the system and returns a dictionary that // maps version identifiers of any form (X, X.Y, and X.Y.Z) to the directory // where the Xcode bundle lives. @@ -137,6 +152,21 @@ static void AddEntryToDictionary( fprintf(stderr, "error: %s\n", nsError.description.UTF8String); return nil; } + + NSString *selectedXcode = SelectedXcode(); + if ((selectedXcode.length > 0) && ![selectedXcode containsString:@"CommandLineTools"]) { + NSURL *selectedXcodeURL = [NSURL fileURLWithPath:selectedXcode]; + NSString *path = selectedXcodeURL.path; + if ([path hasSuffix:@"/Contents/Developer"]) { + path = [path substringToIndex: + path.length - @"/Contents/Developer".length]; + } + + NSURL *appURL = [NSURL fileURLWithPath:path isDirectory:YES]; + if (![array containsObject:appURL]) { + array = [array arrayByAddingObject:appURL]; + } + } // Scan all bundles but delay returning in case of errors until we are // done. This is to let us log details about all the bundles that were