diff --git a/packages/flutter_tools/lib/src/build_system/targets/darwin.dart b/packages/flutter_tools/lib/src/build_system/targets/darwin.dart index 688d182e1e4..780dcf30e50 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/darwin.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/darwin.dart @@ -5,7 +5,6 @@ import 'package:meta/meta.dart'; import '../../artifacts.dart'; -import '../../base/file_system.dart'; import '../../base/io.dart'; import '../../build_info.dart'; import '../../globals.dart' as globals show stdio; @@ -114,61 +113,6 @@ abstract class UnpackDarwin extends Target { } } -abstract class ReleaseUnpackDarwinDsym extends Target { - const ReleaseUnpackDarwinDsym(); - - BuildMode get buildMode => BuildMode.release; - - @visibleForOverriding - TargetPlatform get targetPlatform; - - Artifact get dsymArtifact; - - @override - List get inputs => [ - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/darwin.dart', - ), - Source.artifact(dsymArtifact, platform: targetPlatform, mode: buildMode), - ]; - - @override - List get dependencies => []; - - Future copyFrameworkDsym( - Environment environment, { - EnvironmentType? environmentType, - }) async { - // Copy Flutter framework dSYM (debug symbol) bundle, if present. - final Directory frameworkDsym = environment.fileSystem.directory( - environment.artifacts.getArtifactPath( - dsymArtifact, - platform: targetPlatform, - mode: buildMode, - environmentType: environmentType, - ), - ); - if (frameworkDsym.existsSync()) { - final ProcessResult result = await environment.processManager.run([ - 'rsync', - '-av', - '--delete', - '--filter', - '- .DS_Store/', - '--chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r', - frameworkDsym.path, - environment.outputDir.path, - ]); - if (result.exitCode != 0) { - throw Exception( - 'Failed to copy framework dSYM (exit ${result.exitCode}:\n' - '${result.stdout}\n---\n${result.stderr}', - ); - } - } - } -} - /// Log warning message to the Xcode build logs. Log will show as yellow with an icon. /// /// If the issue occurs in a specific file, include the [filePath] as an absolute path. diff --git a/packages/flutter_tools/lib/src/build_system/targets/ios.dart b/packages/flutter_tools/lib/src/build_system/targets/ios.dart index e2609509297..1c2dae43c85 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -285,6 +285,7 @@ abstract class UnpackIOS extends UnpackDarwin { targetPlatform: TargetPlatform.ios, buildMode: buildMode, ); + await _copyFrameworkDysm(environment, sdkRoot: sdkRoot, environmentType: environmentType); final File frameworkBinary = environment.outputDir .childDirectory(FlutterDarwinPlatform.ios.frameworkName) @@ -296,6 +297,40 @@ abstract class UnpackIOS extends UnpackDarwin { await thinFramework(environment, frameworkBinaryPath, archs); await _signFramework(environment, frameworkBinary, buildMode); } + + Future _copyFrameworkDysm( + Environment environment, { + required String sdkRoot, + EnvironmentType? environmentType, + }) async { + // Copy Flutter framework dSYM (debug symbol) bundle, if present. + final Directory frameworkDsym = environment.fileSystem.directory( + environment.artifacts.getArtifactPath( + Artifact.flutterFrameworkDsym, + platform: TargetPlatform.ios, + mode: buildMode, + environmentType: environmentType, + ), + ); + if (frameworkDsym.existsSync()) { + final ProcessResult result = await environment.processManager.run([ + 'rsync', + '-av', + '--delete', + '--filter', + '- .DS_Store/', + '--chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r', + frameworkDsym.path, + environment.outputDir.path, + ]); + if (result.exitCode != 0) { + throw Exception( + 'Failed to copy framework dSYM (exit ${result.exitCode}:\n' + '${result.stdout}\n---\n${result.stderr}', + ); + } + } + } } /// Unpack the release prebuilt engine framework. @@ -307,9 +342,6 @@ class ReleaseUnpackIOS extends UnpackIOS { @override BuildMode get buildMode => BuildMode.release; - - @override - List get dependencies => [...super.dependencies, const ReleaseUnpackIOSDsym()]; } /// Unpack the profile prebuilt engine framework. @@ -334,45 +366,6 @@ class DebugUnpackIOS extends UnpackIOS { BuildMode get buildMode => BuildMode.debug; } -class ReleaseUnpackIOSDsym extends ReleaseUnpackDarwinDsym { - const ReleaseUnpackIOSDsym(); - - @override - String get name => 'release_unpack_ios_dsym'; - - @override - TargetPlatform get targetPlatform => TargetPlatform.ios; - - @override - Artifact get dsymArtifact => Artifact.flutterFrameworkDsym; - - @override - List get inputs => [ - ...super.inputs, - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart', - ), - ]; - - @override - List get outputs => const [ - Source.pattern('{OUTPUT_DIR}/Flutter.framework.dSYM/Contents/Resources/DWARF/Flutter'), - ]; - - @override - Future build(Environment environment) async { - final String? sdkRoot = environment.defines[kSdkRoot]; - if (sdkRoot == null) { - throw MissingDefineException(kSdkRoot, name); - } - final EnvironmentType? environmentType = environmentTypeFromSdkroot( - sdkRoot, - environment.fileSystem, - ); - await copyFrameworkDsym(environment, environmentType: environmentType); - } -} - // TODO(gaaclarke): Remove this after a reasonable amount of time where the // UISceneDelegate migration being on stable. This incurs a minor build time // cost. diff --git a/packages/flutter_tools/lib/src/build_system/targets/macos.dart b/packages/flutter_tools/lib/src/build_system/targets/macos.dart index 2df1e60bd23..dbffaa465c9 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -7,6 +7,7 @@ import 'package:unified_analytics/unified_analytics.dart'; import '../../artifacts.dart'; import '../../base/build.dart'; import '../../base/file_system.dart'; +import '../../base/io.dart'; import '../../base/process.dart'; import '../../build_info.dart'; import '../../darwin/darwin.dart'; @@ -107,13 +108,56 @@ class ReleaseUnpackMacOS extends UnpackMacOS { @override String get name => 'release_unpack_macos'; + @override + List get outputs => + super.outputs + + const [ + Source.pattern( + '{OUTPUT_DIR}/FlutterMacOS.framework.dSYM/Contents/Resources/DWARF/FlutterMacOS', + ), + ]; + @override List get inputs => super.inputs + const [Source.artifact(Artifact.flutterMacOSXcframework, mode: BuildMode.release)]; @override - List get dependencies => [...super.dependencies, const ReleaseUnpackMacOSDsym()]; + Future build(Environment environment) async { + await super.build(environment); + + // Copy Flutter framework dSYM (debug symbol) bundle, if present. + final String? buildModeEnvironment = environment.defines[kBuildMode]; + if (buildModeEnvironment == null) { + throw MissingDefineException(kBuildMode, 'unpack_macos'); + } + final buildMode = BuildMode.fromCliName(buildModeEnvironment); + final Directory frameworkDsym = environment.fileSystem.directory( + environment.artifacts.getArtifactPath( + Artifact.flutterMacOSFrameworkDsym, + platform: TargetPlatform.darwin, + mode: buildMode, + ), + ); + if (frameworkDsym.existsSync()) { + final ProcessResult result = await environment.processManager.run([ + 'rsync', + '-av', + '--delete', + '--filter', + '- .DS_Store/', + '--chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r', + frameworkDsym.path, + environment.outputDir.path, + ]); + if (result.exitCode != 0) { + throw Exception( + 'Failed to copy framework dSYM (exit ${result.exitCode}:\n' + '${result.stdout}\n---\n${result.stderr}', + ); + } + } + } } /// Unpack the profile prebuilt engine framework. @@ -144,39 +188,6 @@ class DebugUnpackMacOS extends UnpackMacOS { ]; } -class ReleaseUnpackMacOSDsym extends ReleaseUnpackDarwinDsym { - const ReleaseUnpackMacOSDsym(); - - @override - String get name => 'release_unpack_macos_dsym'; - - @override - TargetPlatform get targetPlatform => TargetPlatform.darwin; - - @override - Artifact get dsymArtifact => Artifact.flutterMacOSFrameworkDsym; - - @override - List get inputs => [ - ...super.inputs, - const Source.pattern( - '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/macos.dart', - ), - ]; - - @override - List get outputs => const [ - Source.pattern( - '{OUTPUT_DIR}/FlutterMacOS.framework.dSYM/Contents/Resources/DWARF/FlutterMacOS', - ), - ]; - - @override - Future build(Environment environment) async { - await copyFrameworkDsym(environment); - } -} - /// Create an App.framework for debug macOS targets. /// /// This framework needs to exist for the Xcode project to link/bundle, diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart index 23f359aa525..8ec8bd76194 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/ios_test.dart @@ -694,8 +694,7 @@ void main() { group('copies Flutter.framework', () { late Directory outputDir; late File binary; - late FakeCommand copyPhysicalDebugFrameworkCommand; - late FakeCommand copyPhysicalReleaseFrameworkCommand; + late FakeCommand copyPhysicalFrameworkCommand; late FakeCommand copyPhysicalFrameworkDsymCommand; late FakeCommand copyPhysicalFrameworkDsymCommandFailure; late FakeCommand lipoCommandNonFatResult; @@ -708,7 +707,7 @@ void main() { outputDir = fileSystem.directory('output'); binary = outputDir.childDirectory('Flutter.framework').childFile('Flutter'); - copyPhysicalDebugFrameworkCommand = FakeCommand( + copyPhysicalFrameworkCommand = FakeCommand( command: [ 'rsync', '-av', @@ -720,18 +719,6 @@ void main() { outputDir.path, ], ); - copyPhysicalReleaseFrameworkCommand = FakeCommand( - command: [ - 'rsync', - '-av', - '--delete', - '--filter', - '- .DS_Store/', - '--chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r', - 'Artifact.flutterFramework.TargetPlatform.ios.release.EnvironmentType.physical', - outputDir.path, - ], - ); copyPhysicalFrameworkDsymCommand = FakeCommand( command: [ @@ -741,7 +728,7 @@ void main() { '--filter', '- .DS_Store/', '--chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r', - 'Artifact.flutterFrameworkDsym.TargetPlatform.ios.release.EnvironmentType.physical', + 'Artifact.flutterFrameworkDsym.TargetPlatform.ios.debug.EnvironmentType.physical', outputDir.path, ], ); @@ -754,7 +741,7 @@ void main() { '--filter', '- .DS_Store/', '--chmod=Du=rwx,Dgo=rx,Fu=rw,Fgo=r', - 'Artifact.flutterFrameworkDsym.TargetPlatform.ios.release.EnvironmentType.physical', + 'Artifact.flutterFrameworkDsym.TargetPlatform.ios.debug.EnvironmentType.physical', outputDir.path, ], exitCode: 1, @@ -827,7 +814,7 @@ void main() { outputDir: outputDir, defines: {kIosArchs: 'arm64', kSdkRoot: 'path/to/iPhoneOS.sdk'}, ); - processManager.addCommand(copyPhysicalDebugFrameworkCommand); + processManager.addCommand(copyPhysicalFrameworkCommand); await expectLater( const DebugUnpackIOS().build(environment), throwsA( @@ -846,7 +833,7 @@ void main() { artifacts.getArtifactPath( Artifact.flutterFrameworkDsym, platform: TargetPlatform.ios, - mode: BuildMode.release, + mode: BuildMode.debug, environmentType: EnvironmentType.physical, ), ); @@ -861,9 +848,12 @@ void main() { outputDir: outputDir, defines: {kIosArchs: 'arm64', kSdkRoot: 'path/to/iPhoneOS.sdk'}, ); - processManager.addCommands([copyPhysicalFrameworkDsymCommandFailure]); + processManager.addCommands([ + copyPhysicalFrameworkCommand, + copyPhysicalFrameworkDsymCommandFailure, + ]); await expectLater( - const ReleaseUnpackIOSDsym().build(environment), + const DebugUnpackIOS().build(environment), throwsA( isException.having( (Exception exception) => exception.toString(), @@ -888,7 +878,7 @@ void main() { ); processManager.addCommands([ - copyPhysicalDebugFrameworkCommand, + copyPhysicalFrameworkCommand, FakeCommand( command: ['lipo', '-info', binary.path], stdout: 'Architectures in the fat file:', @@ -928,7 +918,7 @@ void main() { ); processManager.addCommands([ - copyPhysicalDebugFrameworkCommand, + copyPhysicalFrameworkCommand, FakeCommand( command: ['lipo', '-info', binary.path], stdout: 'Architectures in the fat file:', @@ -1062,7 +1052,7 @@ void main() { ); processManager.addCommands([ - copyPhysicalDebugFrameworkCommand, + copyPhysicalFrameworkCommand, lipoCommandNonFatResult, lipoVerifyArm64Command, xattrCommand, @@ -1092,7 +1082,7 @@ void main() { ); processManager.addCommands([ - copyPhysicalDebugFrameworkCommand, + copyPhysicalFrameworkCommand, FakeCommand( command: ['lipo', '-info', binary.path], stdout: 'Architectures in the fat file:', @@ -1132,7 +1122,7 @@ void main() { ); processManager.addCommands([ - copyPhysicalDebugFrameworkCommand, + copyPhysicalFrameworkCommand, lipoCommandNonFatResult, lipoVerifyArm64Command, xattrCommand, @@ -1161,7 +1151,7 @@ void main() { ); processManager.addCommands([ - copyPhysicalDebugFrameworkCommand, + copyPhysicalFrameworkCommand, lipoCommandNonFatResult, lipoVerifyArm64Command, xattrCommand, @@ -1196,13 +1186,13 @@ void main() { expect(processManager, hasNoRemainingExpectations); }); - testWithoutContext('codesigns framework in release mode', () async { + testWithoutContext('codesigns framework', () async { binary.createSync(recursive: true); final Directory dSYM = fileSystem.directory( artifacts.getArtifactPath( Artifact.flutterFrameworkDsym, platform: TargetPlatform.ios, - mode: BuildMode.release, + mode: BuildMode.debug, environmentType: EnvironmentType.physical, ), ); @@ -1223,41 +1213,8 @@ void main() { ); processManager.addCommands([ + copyPhysicalFrameworkCommand, copyPhysicalFrameworkDsymCommand, - copyPhysicalReleaseFrameworkCommand, - lipoCommandNonFatResult, - lipoVerifyArm64Command, - xattrCommand, - FakeCommand(command: ['codesign', '--force', '--sign', 'ABC123', binary.path]), - ]); - const Target target = ReleaseUnpackIOS(); - for (final Target dep in target.dependencies) { - await dep.build(environment); - } - await target.build(environment); - - expect(processManager, hasNoRemainingExpectations); - }); - - testWithoutContext('codesigns framework in debug mode', () async { - binary.createSync(recursive: true); - - final environment = Environment.test( - fileSystem.currentDirectory, - processManager: processManager, - artifacts: artifacts, - logger: logger, - fileSystem: fileSystem, - outputDir: outputDir, - defines: { - kIosArchs: 'arm64', - kSdkRoot: 'path/to/iPhoneOS.sdk', - kCodesignIdentity: 'ABC123', - }, - ); - - processManager.addCommands([ - copyPhysicalDebugFrameworkCommand, lipoCommandNonFatResult, lipoVerifyArm64Command, xattrCommand, @@ -1272,11 +1229,7 @@ void main() { ], ), ]); - const Target target = DebugUnpackIOS(); - for (final Target dep in target.dependencies) { - await dep.build(environment); - } - await target.build(environment); + await const DebugUnpackIOS().build(environment); expect(processManager, hasNoRemainingExpectations); }); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart index 1138365d94f..aa31e06bfcd 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/macos_test.dart @@ -329,17 +329,13 @@ void main() { binary.createSync(recursive: true); frameworkDsym.createSync(recursive: true); processManager.addCommands([ - copyFrameworkDsymCommand, releaseCopyFrameworkCommand, lipoInfoNonFatCommand, lipoVerifyX86_64Command, + copyFrameworkDsymCommand, ]); - const Target target = ReleaseUnpackMacOS(); - for (final Target dep in target.dependencies) { - await dep.build(environment..defines[kBuildMode] = 'release'); - } - await target.build(environment..defines[kBuildMode] = 'release'); + await const ReleaseUnpackMacOS().build(environment..defines[kBuildMode] = 'release'); expect(processManager, hasNoRemainingExpectations); }, @@ -367,10 +363,16 @@ void main() { ], exitCode: 1, ); - processManager.addCommands([failedCopyFrameworkDsymCommand]); + processManager.addCommands([ + releaseCopyFrameworkCommand, + lipoInfoFatCommand, + lipoVerifyX86_64Command, + lipoExtractX86_64Command, + failedCopyFrameworkDsymCommand, + ]); await expectLater( - const ReleaseUnpackMacOSDsym().build(environment..defines[kBuildMode] = 'release'), + const ReleaseUnpackMacOS().build(environment..defines[kBuildMode] = 'release'), throwsA( isException.having( (Exception exception) => exception.toString(), diff --git a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart index fcf8e73beb3..9a2f792b6c8 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/ios_content_validation_test.dart @@ -88,8 +88,6 @@ void main() { late Directory buildPath; late Directory buildAppFrameworkDsym; late File buildAppFrameworkDsymBinary; - late Directory flutterFrameworkDsym; - late File flutterFrameworkDsymBinary; late ProcessResult buildResult; setUpAll(() { @@ -139,11 +137,6 @@ void main() { buildAppFrameworkDsymBinary = buildAppFrameworkDsym.childFile( 'Contents/Resources/DWARF/App', ); - - flutterFrameworkDsym = buildPath.childDirectory('Flutter.framework.dSYM'); - flutterFrameworkDsymBinary = flutterFrameworkDsym.childFile( - 'Contents/Resources/DWARF/Flutter', - ); }); testWithoutContext('flutter build ios builds a valid app', () { @@ -171,7 +164,6 @@ void main() { expect(outputAppFramework.childFile('Info.plist'), exists); expect(buildAppFrameworkDsymBinary.existsSync(), buildMode != BuildMode.debug); - expect(flutterFrameworkDsymBinary.existsSync(), buildMode != BuildMode.debug); final File vmSnapshot = fileSystem.file( fileSystem.path.join(outputAppFramework.path, 'flutter_assets', 'vm_snapshot_data'), @@ -216,36 +208,22 @@ void main() { if (buildMode == BuildMode.debug) { expect(symbols, isEmpty); } else { - expect(symbols, equals(AppleTestUtils.requiredAppSymbols)); + expect(symbols, equals(AppleTestUtils.requiredSymbols)); } - - final List flutterSymbols = AppleTestUtils.getExportedSymbols( - outputFlutterFrameworkBinary.path, - ); - expect(flutterSymbols, containsAll(AppleTestUtils.expectedFlutterSymbols)); }); testWithoutContext('check symbols in dSYM', () { if (buildMode == BuildMode.debug) { // dSYM is not created for a debug build. expect(buildAppFrameworkDsymBinary.existsSync(), isFalse); - expect(flutterFrameworkDsymBinary.existsSync(), isFalse); } else { - final List appSymbols = AppleTestUtils.getExportedSymbols( + final List symbols = AppleTestUtils.getExportedSymbols( buildAppFrameworkDsymBinary.path, ); - expect(appSymbols, containsAll(AppleTestUtils.requiredAppSymbols)); + expect(symbols, containsAll(AppleTestUtils.requiredSymbols)); // The actual number of symbols is going to vary but there should // be "many" in the dSYM. At the time of writing, it was 7656. - expect(appSymbols.length, greaterThanOrEqualTo(5000)); - - final List flutterSymbols = AppleTestUtils.getExportedSymbols( - flutterFrameworkDsymBinary.path, - ); - expect(flutterSymbols, containsAll(AppleTestUtils.expectedFlutterSymbols)); - // The actual number of symbols is going to vary but there should - // be "many" in the dSYM. At the time of writing, it was 35940. - expect(flutterSymbols.length, greaterThanOrEqualTo(35000)); + expect(symbols.length, greaterThanOrEqualTo(5000)); } }); diff --git a/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart b/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart index 524ba6838f0..c578a26f037 100644 --- a/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart +++ b/packages/flutter_tools/test/host_cross_arch.shard/macos_content_validation_test.dart @@ -203,14 +203,12 @@ void main() { } else { // Check framework dSYM file copied. _checkFatBinary(frameworkDsymBinary, buildModeLower, 'dSYM companion file'); - final List symbols = AppleTestUtils.getExportedSymbols(frameworkDsymBinary.path); - expect(symbols, containsAll(AppleTestUtils.expectedFlutterSymbols)); // Check extracted dSYM file. _checkFatBinary(libDsymBinary, buildModeLower, 'dSYM companion file'); - expect(libSymbols, equals(AppleTestUtils.requiredAppSymbols)); + expect(libSymbols, equals(AppleTestUtils.requiredSymbols)); final List dSymSymbols = AppleTestUtils.getExportedSymbols(libDsymBinary.path); - expect(dSymSymbols, containsAll(AppleTestUtils.requiredAppSymbols)); + expect(dSymSymbols, containsAll(AppleTestUtils.requiredSymbols)); // The actual number of symbols is going to vary but there should // be "many" in the dSYM. At the time of writing, it was 19195. expect(dSymSymbols.length, greaterThanOrEqualTo(15000)); diff --git a/packages/flutter_tools/test/integration.shard/test_utils.dart b/packages/flutter_tools/test/integration.shard/test_utils.dart index cf43b3b0d6c..b004394619a 100644 --- a/packages/flutter_tools/test/integration.shard/test_utils.dart +++ b/packages/flutter_tools/test/integration.shard/test_utils.dart @@ -101,19 +101,13 @@ Future pollForServiceExtensionValue({ } abstract final class AppleTestUtils { - static const requiredAppSymbols = [ + static const requiredSymbols = [ '_kDartIsolateSnapshotData', '_kDartIsolateSnapshotInstructions', '_kDartVmSnapshotData', '_kDartVmSnapshotInstructions', ]; - /// A small subset of expected symbols for the Flutter/FlutterMacOS framework - static const expectedFlutterSymbols = [ - r'_OBJC_CLASS_$_FlutterViewController', - r'_OBJC_CLASS_$_FlutterEngine', - ]; - static List getExportedSymbols(String dwarfPath) { final ProcessResult nm = processManager.runSync([ 'nm',