Skip to content

Fix Xcode 26+ xctestrun DYLD_FRAMEWORK_PATH for simulator builds#3005

Open
cdeil wants to merge 1 commit intoleancodepl:masterfrom
cdeil:issue-3003-fix
Open

Fix Xcode 26+ xctestrun DYLD_FRAMEWORK_PATH for simulator builds#3005
cdeil wants to merge 1 commit intoleancodepl:masterfrom
cdeil:issue-3003-fix

Conversation

@cdeil
Copy link
Copy Markdown

@cdeil cdeil commented Mar 26, 2026

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

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
@github-actions github-actions Bot added the package: patrol_cli Related to the patrol_cli package label Mar 26, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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

  • Xcode 26.4+ Simulator Build Fix: Implemented a patch to modify the xctestrun plist after build-for-testing to include the missing platform Developer frameworks directory in DYLD_FRAMEWORK_PATH for simulator builds, preventing crashes caused by _Testing_Foundation.framework not being found.

🧠 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 Assist

The 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 /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

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 .gemini/ folder in the base of the repository. Detailed instructions can be found here.

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

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +345 to +379
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}',
);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The scheme parameter is unused within this method's body, as the plistKey is hardcoded. To improve code clarity, it should be removed from the method signature. Remember to also update the call site at line 158.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: patrol_cli Related to the patrol_cli package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Runner app crashes on iOS Simulator with Xcode 26.4 — _Testing_Foundation.framework not found

1 participant