diff --git a/packages/flutter_tools/lib/src/aot.dart b/packages/flutter_tools/lib/src/aot.dart index faceac48e2..750d20d25e 100644 --- a/packages/flutter_tools/lib/src/aot.dart +++ b/packages/flutter_tools/lib/src/aot.dart @@ -14,6 +14,8 @@ import 'base/process.dart'; import 'build_info.dart'; import 'build_system/build_system.dart'; import 'build_system/targets/dart.dart'; +import 'build_system/targets/ios.dart'; +import 'cache.dart'; import 'dart/package_map.dart'; import 'globals.dart' as globals; import 'ios/bitcode.dart'; @@ -39,18 +41,17 @@ class AotBuilder { throwToolExit('No AOT build platform specified'); } - // This code is currently dead, but will be updated as we move iOS to assemble. - // See also: https://github.com/flutter/flutter/issues/32925 if (_canUseAssemble(platform) && extraGenSnapshotOptions?.isEmpty != false && extraFrontEndOptions?.isEmpty != false) { - assert(false); await _buildWithAssemble( targetFile: mainDartFile, outputDir: outputPath, targetPlatform: platform, buildMode: buildMode, quiet: quiet, + iosArchs: iosBuildArchs ?? defaultIOSArchs, + bitcode: bitcode ?? kBitcodeEnabledDefault, ); return; } @@ -175,12 +176,13 @@ class AotBuilder { bool _canUseAssemble(TargetPlatform targetPlatform) { switch (targetPlatform) { + case TargetPlatform.ios: + return true; case TargetPlatform.android_arm: case TargetPlatform.android_arm64: case TargetPlatform.android_x86: case TargetPlatform.darwin_x64: case TargetPlatform.android_x64: - case TargetPlatform.ios: case TargetPlatform.linux_x64: case TargetPlatform.windows_x64: case TargetPlatform.fuchsia_arm64: @@ -197,11 +199,10 @@ class AotBuilder { BuildMode buildMode, String targetFile, String outputDir, - bool quiet + bool quiet, + Iterable iosArchs, + bool bitcode, }) async { - // This code is currently dead, but will be updated as we move iOS to assemble. - // See also: https://github.com/flutter/flutter/issues/32925 - assert(false); Status status; if (!quiet) { final String typeName = globals.artifacts.getEngineType(targetPlatform, buildMode); @@ -211,10 +212,14 @@ class AotBuilder { ); } final FlutterProject flutterProject = FlutterProject.current(); - const Target target = null; + final Target target = buildMode == BuildMode.profile + ? const AotAssemblyProfile() + : const AotAssemblyRelease(); - final BuildResult result = await buildSystem.build(target, Environment.test( - flutterProject.directory, + final BuildResult result = await buildSystem.build(target, Environment( + projectDir: flutterProject.directory, + cacheDir: globals.cache.getRoot(), + flutterRootDir: globals.fs.directory(Cache.flutterRoot), outputDir: globals.fs.directory(outputDir), buildDir: flutterProject.directory .childDirectory('.dart_tool') @@ -223,6 +228,8 @@ class AotBuilder { kBuildMode: getNameForBuildMode(buildMode), kTargetPlatform: getNameForTargetPlatform(targetPlatform), kTargetFile: targetFile, + kIosArchs: iosArchs.map(getNameForDarwinArch).join(','), + kBitcodeFlag: bitcode.toString() } )); status?.stop(); 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 032e270c69..79f19d06f4 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -25,7 +25,7 @@ abstract class AotAssemblyBase extends Target { @override Future build(Environment environment) async { final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: false); - final String buildOutputPath = environment.buildDir.path; + final String buildOutputPath = environment.outputDir.path; if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'aot_assembly'); } @@ -41,50 +41,37 @@ abstract class AotAssemblyBase extends Target { throw Exception('aot_assembly is only supported for iOS applications'); } - // If we're building for a single architecture (common), then skip the lipo. - if (iosArchs.length == 1) { - final int snapshotExitCode = await snapshotter.build( + // If we're building multiple iOS archs the binaries need to be lipo'd + // together. + final List> pending = >[]; + for (final DarwinArch iosArch in iosArchs) { + pending.add(snapshotter.build( platform: targetPlatform, buildMode: buildMode, mainPath: environment.buildDir.childFile('app.dill').path, packagesPath: environment.projectDir.childFile('.packages').path, - outputPath: environment.outputDir.path, - darwinArch: iosArchs.single, + outputPath: globals.fs.path.join(buildOutputPath, getNameForDarwinArch(iosArch)), + darwinArch: iosArch, bitcode: bitcode, - ); - if (snapshotExitCode != 0) { - throw Exception('AOT snapshotter exited with code $snapshotExitCode'); - } - } else { - // If we're building multiple iOS archs the binaries need to be lipo'd - // together. - final List> pending = >[]; - for (final DarwinArch iosArch in iosArchs) { - pending.add(snapshotter.build( - platform: targetPlatform, - buildMode: buildMode, - mainPath: environment.buildDir.childFile('app.dill').path, - packagesPath: environment.projectDir.childFile('.packages').path, - outputPath: globals.fs.path.join(buildOutputPath, getNameForDarwinArch(iosArch)), - darwinArch: iosArch, - bitcode: bitcode, - )); - } - final List results = await Future.wait(pending); - if (results.any((int result) => result != 0)) { - throw Exception('AOT snapshotter exited with code ${results.join()}'); - } - final ProcessResult result = await globals.processManager.run([ - 'lipo', - ...iosArchs.map((DarwinArch iosArch) => - globals.fs.path.join(buildOutputPath, getNameForDarwinArch(iosArch), 'App.framework', 'App')), - '-create', - '-output', - globals.fs.path.join(environment.outputDir.path, 'App.framework', 'App'), - ]); - if (result.exitCode != 0) { - throw Exception('lipo exited with code ${result.exitCode}'); - } + quiet: true, + )); + } + final List results = await Future.wait(pending); + if (results.any((int result) => result != 0)) { + throw Exception('AOT snapshotter exited with code ${results.join()}'); + } + final String resultPath = globals.fs.path.join(environment.outputDir.path, 'App.framework', 'App'); + globals.fs.directory(resultPath).parent.createSync(recursive: true); + final ProcessResult result = await globals.processManager.run([ + 'lipo', + ...iosArchs.map((DarwinArch iosArch) => + globals.fs.path.join(buildOutputPath, getNameForDarwinArch(iosArch), 'App.framework', 'App')), + '-create', + '-output', + resultPath, + ]); + if (result.exitCode != 0) { + throw Exception('lipo exited with code ${result.exitCode}.\n${result.stderr}'); } } } @@ -103,10 +90,13 @@ class AotAssemblyRelease extends AotAssemblyBase { Source.pattern('{PROJECT_DIR}/.packages'), Source.artifact(Artifact.engineDartBinary), Source.artifact(Artifact.skyEnginePath), - Source.artifact(Artifact.genSnapshot, - platform: TargetPlatform.ios, - mode: BuildMode.release, - ), + // TODO(jonahwilliams): cannot reference gen_snapshot with artifacts since + // it resolves to a file (ios/gen_snapshot) that never exists. This was + // split into gen_snapshot_arm64 and gen_snapshot_armv7. + // Source.artifact(Artifact.genSnapshot, + // platform: TargetPlatform.ios, + // mode: BuildMode.release, + // ), ]; @override @@ -135,10 +125,13 @@ class AotAssemblyProfile extends AotAssemblyBase { Source.pattern('{PROJECT_DIR}/.packages'), Source.artifact(Artifact.engineDartBinary), Source.artifact(Artifact.skyEnginePath), - Source.artifact(Artifact.genSnapshot, - platform: TargetPlatform.ios, - mode: BuildMode.profile, - ), + // TODO(jonahwilliams): cannot reference gen_snapshot with artifacts since + // it resolves to a file (ios/gen_snapshot) that never exists. This was + // split into gen_snapshot_arm64 and gen_snapshot_armv7. + // Source.artifact(Artifact.genSnapshot, + // platform: TargetPlatform.ios, + // mode: BuildMode.profile, + // ), ]; @override