Skip to content

Conversation

@loic-sharma
Copy link
Member

@loic-sharma loic-sharma commented Sep 6, 2024

CI test: https://ci.chromium.org/ui/p/flutter/builders/try.shadow/Mac_ios%20rrect_blur_perf_ios__timeline_summary/7/overview

[2024-09-06 14:04:59.964433] [STDOUT] stdout:            error: [   +2 ms] Target profile_unpack_ios failed: Exception: Binary /opt/s/w/ir/x/w/rc/tmp97gptb8v/flutter sdk/dev/benchmarks/macrobenchmarks/build/ios/Profile-iphoneos/Flutter.framework/Flutter does not contain x86_64. Running lipo -info:
[2024-09-06 14:04:59.964444] [STDOUT] stdout:                       Non-fat file: /opt/s/w/ir/x/w/rc/tmp97gptb8v/flutter sdk/dev/benchmarks/macrobenchmarks/build/ios/Profile-iphoneos/Flutter.framework/Flutter is architecture: arm64
[2024-09-06 14:04:59.964453] [STDOUT] stdout: 
[2024-09-06 14:04:59.964464] [STDOUT] stdout:                       #0      UnpackIOS._thinFramework (package:flutter_tools/src/build_system/targets/ios.dart:380:7)
[2024-09-06 14:04:59.964492] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964507] [STDOUT] stdout:                       #1      UnpackIOS.build (package:flutter_tools/src/build_system/targets/ios.dart:298:5)
[2024-09-06 14:04:59.964520] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964530] [STDOUT] stdout:                       #2      _BuildInstance._invokeInternal (package:flutter_tools/src/build_system/build_system.dart:891:9)
[2024-09-06 14:04:59.964542] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964553] [STDOUT] stdout:                       #3      FlutterBuildSystem.build (package:flutter_tools/src/build_system/build_system.dart:651:16)
[2024-09-06 14:04:59.964581] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964595] [STDOUT] stdout:                       #4      AssembleCommand.runCommand (package:flutter_tools/src/commands/assemble.dart:329:32)
[2024-09-06 14:04:59.964605] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964613] [STDOUT] stdout:                       #5      FlutterCommand.run.<anonymous closure> (package:flutter_tools/src/runner/flutter_command.dart:1450:27)
[2024-09-06 14:04:59.964622] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964629] [STDOUT] stdout:                       #6      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:153:19)
[2024-09-06 14:04:59.964637] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964645] [STDOUT] stdout:                       #7      CommandRunner.runCommand (package:args/command_runner.dart:212:13)
[2024-09-06 14:04:59.964652] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964661] [STDOUT] stdout:                       #8      FlutterCommandRunner.runCommand.<anonymous closure> (package:flutter_tools/src/runner/flutter_command_runner.dart:421:9)
[2024-09-06 14:04:59.964670] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964679] [STDOUT] stdout:                       #9      AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:153:19)
[2024-09-06 14:04:59.964688] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964697] [STDOUT] stdout:                       #10     FlutterCommandRunner.runCommand (package:flutter_tools/src/runner/flutter_command_runner.dart:364:5)
[2024-09-06 14:04:59.964705] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964714] [STDOUT] stdout:                       #11     run.<anonymous closure>.<anonymous closure> (package:flutter_tools/runner.dart:130:9)
[2024-09-06 14:04:59.964723] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964732] [STDOUT] stdout:                       #12     AppContext.run.<anonymous closure> (package:flutter_tools/src/base/context.dart:153:19)
[2024-09-06 14:04:59.964741] [STDOUT] stdout:                       <asynchronous suspension>
[2024-09-06 14:04:59.964749] [STDOUT] stdout:                       #13     main (package:flutter_tools/executable.dart:94:3)
[2024-09-06 14:04:59.964758] [STDOUT] stdout:                       <asynchronous suspension>

@github-actions github-actions bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Sep 6, 2024
auto-submit bot pushed a commit that referenced this pull request Sep 11, 2024
#154645)

### Problem

Enabling the Swift Package Manager feature caused post-submit tests to fail on Mac x64 hosts:

<details>
<summary>Example error...</summary>

https://ci.chromium.org/ui/p/flutter/builders/prod/Mac_ios%20rrect_blur_perf_ios__timeline_summary/575/overview

```
� ... flutter --verbose assemble ... -dIosArchs=x86_64 ... profile_unpack_ios

Target profile_unpack_ios failed:
Exception: Binary ... build/ios/Profile-iphoneos/Flutter.framework/Flutter does not contain x86_64.

Running lipo -info:
Non-fat file: ... build/ios/Profile-iphoneos/Flutter.framework/Flutter is architecture: arm64

#0      UnpackIOS._thinFramework (package:flutter_tools/src/build_system/targets/ios.dart:351:7)
<asynchronous suspension>
#1      UnpackIOS.build (package:flutter_tools/src/build_system/targets/ios.dart:298:5)
<asynchronous suspension>
...
```

</details>

### Reproduction

On a mac x64 host:

1. Switch to the latest master channel: `flutter channel master ; flutter upgrade`
1. Disable the Swift Package Manager feature: `flutter config --no-enable-swift-package-manager`
2. Create a Flutter project
2. [Edit the Xcode project manually to add the prepare pre-action](https://docs.flutter.dev/packages-and-plugins/swift-package-manager/for-app-developers#step-2-add-run-prepare-flutter-framework-script-pre-action)
3. Run `flutter run` (`flutter build ios` does not reproduce this issue).

### Background

Previously, the Flutter framework was unpacked in the Xcode target's build. Unfortunately, this happens after Swift packages are built; this prevented Swift packages from using the Flutter framework.

To fix this, we added an Xcode pre-action that unpacks the Flutter framework _before_ Swift Package Manager builds packages. The Xcode target still runs the Flutter framework unpack step, but this step no-ops if the unpack step has the exact same inputs. 

```mermaid
flowchart LR
  A[flutter run -d iphone] --> B(Build Xcode project)
  B --> C(Xcode 'prepare framework' pre-action)
  B --> G[Build Swift packages]
  B --> D(Build 'Runner' target)
  C --> E[Unpack Flutter framework #1]
  D --> F["
  Unpack Flutter framework #2
  (No-ops if inputs are same as #1)
  "]
```

#150052 added an optimization that made it more likely the second unpack step no-ops by fixing a case where the target architecture input could be different:

> When using SwiftPM, we use `flutter assemble` in an Xcode Pre-action to run the `debug_unpack_macos` (or profile/release) target. This target is also later used in a Run Script build phase. Depending on `ARCHS` build setting, the Flutter/FlutterMacOS binary is thinned. In the Run Script build phase, `ARCHS` is filtered to the active arch. However, in the Pre-action it doesn't always filter to the active arch. As a workaround, assume arm64 if the [`NATIVE_ARCH`](https://developer.apple.com/documentation/xcode/build-settings-reference/#NATIVEARCH) is arm, otherwise assume x86_64.

This optimization is only applied if [`ONLY_ACTIVE_ARCH`](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW157) is `YES`.

> [!IMPORTANT]
> [`ONLY_ACTIVE_ARCH`](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW157)'s name is misleading. It specifies whether the product includes only object code for the native architecture.
>
> A value of `YES` means the product includes only code for the native architecture ([NATIVE_ARCH](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW59)).
>
> A value of `NO` means the product includes code for the architectures specified in [ARCHS (Architectures)](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW62).

### Problem

`buildXcodeProject` incorrectly always sets `ONLY_ACTIVE_ARCH` to `YES` if the Xcode built is for a single architecture:

https://github.com/flutter/flutter/blob/6abef222514e8039bde5c47ab7864abbc4caf7e8/packages/flutter_tools/lib/src/ios/mac.dart#L353-L361

This is incorrect! If the host architecture is `x64` but the target architecture is `arm64`, [`ONLY_ACTIVE_ARCH`](https://developer.apple.com/library/archive/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html#//apple_ref/doc/uid/TP40003931-CH3-SW157) should be `NO`.

This caused the prepare pre-action to incorrectly use x64 as the target architecture for arm64 devices on an x64 host, which in turn caused builds to fail if Swift Package Manager was enabled.

### Solution

This change updates `buildXcodeProject` to set `ONLY_ACTIVE_ARCH` correctly.

This change also updates the prepare pre-action's to be more conservative in applying the optimization that filters the target architecture. This ensures that the build still works (but without the optimization) if `ONLY_ACTIVE_ARCH` is incorrectly set.

Follow-up PR: #154649

This unblocks: #151567

### DeviceLab test

This problem reproduces if you `flutter run` to an iPhone Arm64 device from an x64 mac host with the Swift Package Manager feature enabled.

I ran an affected DeviceLab test to verify the fix works as expected:

Description | CI test | Result
-- | -- | --
SwiftPM enabled without this fix: #154750 | [Link](https://ci.chromium.org/ui/p/flutter/builders/try.shadow/Mac_ios%20rrect_blur_perf_ios__timeline_summary/7/overview) | � 
SwiftPM enabled with this fix: #154749 | [Link](https://ci.chromium.org/ui/p/flutter/builders/try.shadow/Mac_ios%20rrect_blur_perf_ios__timeline_summary/8/overview) | â�
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant