Fix Xcode 26+ xctestrun DYLD_FRAMEWORK_PATH for simulator builds#3005
Fix Xcode 26+ xctestrun DYLD_FRAMEWORK_PATH for simulator builds#3005cdeil wants to merge 1 commit intoleancodepl:masterfrom
Conversation
Xcode 26.4+ includes _Testing_Foundation.framework which is loaded by libXCTestSwiftSupport.dylib at app launch via @rpath. The xctestrun generated by xcodebuild sets TestingEnvironmentVariables correctly but omits __PLATFORMS__/.../Frameworks from UITargetAppEnvironmentVariables, causing the Runner app to crash with 'Library missing' at launch. Patch the xctestrun plist after build-for-testing to add the missing platform Developer frameworks directory to DYLD_FRAMEWORK_PATH. Fixes leancodepl#3003
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses a critical issue affecting simulator builds with Xcode 26.4 and newer, where test runner apps would crash due to a missing framework. The changes introduce a mechanism to correctly configure the DYLD_FRAMEWORK_PATH within the xctestrun file, ensuring that necessary testing frameworks are discoverable during app launch. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a fix for Xcode 26.4+ simulator tests by patching the xctestrun file to include the platform Developer frameworks path, addressing a "Library missing" crash. The review highlights an issue where the current patching mechanism does not correctly handle cases where the DYLD_FRAMEWORK_PATH key is initially missing, suggesting a more robust approach using PlistBuddy's Add command. Additionally, the scheme parameter is passed to and present in the _patchXcTestRunFrameworkPath method but is unused, and its removal is suggested for improved code clarity.
| final readResult = await _processManager.run([ | ||
| '/usr/libexec/PlistBuddy', | ||
| '-c', | ||
| 'Print :$plistKey', | ||
| xctestRunPath, | ||
| ], runInShell: true); | ||
|
|
||
| final currentPath = readResult.stdOut.trim(); | ||
| if (currentPath.contains('__PLATFORMS__')) { | ||
| _logger.detail('xctestrun already patched with platform frameworks path'); | ||
| return; | ||
| } | ||
|
|
||
| // Append the platform frameworks path. | ||
| final newPath = currentPath.isEmpty | ||
| ? platformsFrameworks | ||
| : '$currentPath:$platformsFrameworks'; | ||
| final setResult = await _processManager.run([ | ||
| '/usr/libexec/PlistBuddy', | ||
| '-c', | ||
| 'Set :$plistKey $newPath', | ||
| xctestRunPath, | ||
| ], runInShell: true); | ||
|
|
||
| if (setResult.exitCode == 0) { | ||
| _logger.detail( | ||
| 'Patched xctestrun: added platform frameworks to ' | ||
| 'UITargetAppEnvironmentVariables.DYLD_FRAMEWORK_PATH', | ||
| ); | ||
| } else { | ||
| _logger.warn( | ||
| 'Failed to patch xctestrun DYLD_FRAMEWORK_PATH: ' | ||
| '${setResult.stdErr}', | ||
| ); | ||
| } |
There was a problem hiding this comment.
The current implementation for patching the .xctestrun file does not correctly handle cases where the DYLD_FRAMEWORK_PATH key is missing. If PlistBuddy -c Print fails, readResult.stdOut will be empty, and the code will then attempt to use PlistBuddy -c Set, which will also fail because Set cannot create a new key. This prevents the patch from being applied when the key doesn't exist initially.
A more robust approach is to check the exit code of the Print command. If it fails, use the Add command to create the key. If it succeeds, you can proceed with the existing logic to check and update the key's value using Set.
final readResult = await _processManager.run([
'/usr/libexec/PlistBuddy',
'-c',
'Print :$plistKey',
xctestRunPath,
], runInShell: true);
final ProcessResult setResult;
if (readResult.exitCode == 0) {
// Key exists.
final currentPath = readResult.stdOut.trim();
if (currentPath.contains('__PLATFORMS__')) {
_logger.detail('xctestrun already patched with platform frameworks path');
return;
}
// Append the platform frameworks path.
final newPath = currentPath.isEmpty
? platformsFrameworks
: '$currentPath:$platformsFrameworks';
setResult = await _processManager.run([
'/usr/libexec/PlistBuddy',
'-c',
'Set :$plistKey $newPath',
xctestRunPath,
], runInShell: true);
} else {
// Key does not exist, add it.
setResult = await _processManager.run([
'/usr/libexec/PlistBuddy',
'-c',
'Add :$plistKey string $platformsFrameworks',
xctestRunPath,
], runInShell: true);
}
if (setResult.exitCode == 0) {
_logger.detail(
'Patched xctestrun: added platform frameworks to '
'UITargetAppEnvironmentVariables.DYLD_FRAMEWORK_PATH',
);
} else {
_logger.warn(
'Failed to patch xctestrun DYLD_FRAMEWORK_PATH: '
'${setResult.stdErr}',
);
}| scheme: options.scheme, | ||
| sdkVersion: sdkVersion, | ||
| ); | ||
| await _patchXcTestRunFrameworkPath(xctestRunFile, options.scheme); |
There was a problem hiding this comment.
The scheme argument is passed to _patchXcTestRunFrameworkPath but is not used within the method. To improve clarity and maintainability, it should be removed from this call. This change should be made in conjunction with removing the parameter from the method definition.
| await _patchXcTestRunFrameworkPath(xctestRunFile, options.scheme); | |
| await _patchXcTestRunFrameworkPath(xctestRunFile); |
| /// This causes Runner to crash at launch with DYLD "Library missing". | ||
| Future<void> _patchXcTestRunFrameworkPath( | ||
| String xctestRunPath, | ||
| String scheme, |
Xcode 26.4+ includes _Testing_Foundation.framework which is loaded by libXCTestSwiftSupport.dylib at app launch via @rpath. The xctestrun generated by xcodebuild sets TestingEnvironmentVariables correctly but omits PLATFORMS/.../Frameworks from UITargetAppEnvironmentVariables, causing the Runner app to crash with 'Library missing' at launch.
Patch the xctestrun plist after build-for-testing to add the missing platform Developer frameworks directory to DYLD_FRAMEWORK_PATH.
Fixes #3003