From b21e780aee3da0d24c88bb27a833cbc32322de4b Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 19 Mar 2020 14:52:42 -0700 Subject: [PATCH] [flutter_tools] refactor AotBuilder, removing globals and duplicated kernel compilation (#52896) Reland of #52091 --- packages/flutter_tools/lib/src/aot.dart | 176 ++- .../flutter_tools/lib/src/base/build.dart | 179 +-- .../flutter_tools/lib/src/base/logger.dart | 6 +- .../lib/src/build_system/targets/android.dart | 9 +- .../lib/src/build_system/targets/dart.dart | 13 +- .../lib/src/build_system/targets/ios.dart | 12 +- .../lib/src/build_system/targets/macos.dart | 10 +- .../lib/src/commands/build_aot.dart | 6 - .../lib/src/commands/build_ios_framework.dart | 1 - .../flutter_tools/lib/src/context_runner.dart | 2 - .../flutter_tools/lib/src/ios/xcodeproj.dart | 4 +- .../test/general.shard/base/build_test.dart | 1156 +++++++---------- .../build_system/targets/macos_test.dart | 32 - 13 files changed, 659 insertions(+), 947 deletions(-) diff --git a/packages/flutter_tools/lib/src/aot.dart b/packages/flutter_tools/lib/src/aot.dart index 77796f9b6f..24a0511ca5 100644 --- a/packages/flutter_tools/lib/src/aot.dart +++ b/packages/flutter_tools/lib/src/aot.dart @@ -6,15 +6,18 @@ import 'dart:async'; import 'package:meta/meta.dart'; -import 'base/build.dart'; import 'base/common.dart'; -import 'base/io.dart'; import 'base/logger.dart'; -import 'base/process.dart'; import 'build_info.dart'; -import 'dart/package_map.dart'; +import 'build_system/build_system.dart'; +import 'build_system/targets/dart.dart'; +import 'build_system/targets/icon_tree_shaker.dart'; +import 'build_system/targets/ios.dart'; +import 'cache.dart'; +import 'convert.dart'; import 'globals.dart' as globals; import 'ios/bitcode.dart'; +import 'project.dart'; /// Builds AOT snapshots given a platform, build mode and a path to a Dart /// library. @@ -26,18 +29,41 @@ class AotBuilder { @required String mainDartFile, bool bitcode = kBitcodeEnabledDefault, bool quiet = true, - bool reportTimings = false, Iterable iosBuildArchs = defaultIOSArchs, }) async { if (platform == null) { throwToolExit('No AOT build platform specified'); } - - if (bitcode) { - if (platform != TargetPlatform.ios) { - throwToolExit('Bitcode is only supported on iOS (TargetPlatform is $platform).'); - } - await validateBitcode(buildInfo.mode, platform); + Target target; + bool expectSo = false; + switch (platform) { + case TargetPlatform.android: + case TargetPlatform.darwin_x64: + case TargetPlatform.linux_x64: + case TargetPlatform.windows_x64: + case TargetPlatform.fuchsia_arm64: + case TargetPlatform.tester: + case TargetPlatform.web_javascript: + case TargetPlatform.android_x86: + throwToolExit('$platform is not supported in AOT.'); + break; + case TargetPlatform.fuchsia_x64: + throwToolExit( + "To build release for fuchsia, use 'flutter build fuchsia --release'" + ); + break; + case TargetPlatform.ios: + target = buildInfo.isRelease + ? const AotAssemblyRelease() + : const AotAssemblyProfile(); + break; + case TargetPlatform.android_arm: + case TargetPlatform.android_arm64: + case TargetPlatform.android_x64: + expectSo = true; + target = buildInfo.isRelease + ? const AotElfRelease() + : const AotElfProfile(); } Status status; @@ -48,102 +74,46 @@ class AotBuilder { timeout: timeoutConfiguration.slowOperation, ); } - try { - final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: reportTimings); - // Compile to kernel. - final String kernelOut = await snapshotter.compileKernel( - platform: platform, - buildMode: buildInfo.mode, - mainPath: mainDartFile, - packagesPath: PackageMap.globalPackagesPath, - trackWidgetCreation: buildInfo.trackWidgetCreation, - outputPath: outputPath, - extraFrontEndOptions: buildInfo.extraFrontEndOptions, - dartDefines: buildInfo.dartDefines - ); - if (kernelOut == null) { - throwToolExit('Compiler terminated unexpectedly.'); - return; + final Environment environment = Environment( + projectDir: globals.fs.currentDirectory, + outputDir: globals.fs.directory(outputPath), + buildDir: FlutterProject.current().dartTool.childDirectory('flutter_build'), + cacheDir: null, + flutterRootDir: globals.fs.directory(Cache.flutterRoot), + defines: { + kTargetFile: mainDartFile ?? globals.fs.path.join('lib', 'main.dart'), + kBuildMode: getNameForBuildMode(buildInfo.mode), + kTargetPlatform: getNameForTargetPlatform(platform), + kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(), + kDartDefines: jsonEncode(buildInfo.dartDefines), + kBitcodeFlag: bitcode.toString(), + if (buildInfo?.extraGenSnapshotOptions?.isNotEmpty ?? false) + kExtraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions.join(','), + if (buildInfo?.extraFrontEndOptions?.isNotEmpty ?? false) + kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(','), + if (platform == TargetPlatform.ios) + kIosArchs: iosBuildArchs.map(getNameForDarwinArch).join(' ') } - - // Build AOT snapshot. - if (platform == TargetPlatform.ios) { - // Determine which iOS architectures to build for. - final Map iosBuilds = {}; - for (final DarwinArch arch in iosBuildArchs) { - iosBuilds[arch] = globals.fs.path.join(outputPath, getNameForDarwinArch(arch)); - } - - // Generate AOT snapshot and compile to arch-specific App.framework. - final Map> exitCodes = >{}; - iosBuilds.forEach((DarwinArch iosArch, String outputPath) { - exitCodes[iosArch] = snapshotter.build( - platform: platform, - darwinArch: iosArch, - buildMode: buildInfo.mode, - mainPath: kernelOut, - packagesPath: PackageMap.globalPackagesPath, - outputPath: outputPath, - extraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions, - bitcode: bitcode, - quiet: quiet, - splitDebugInfo: null, - dartObfuscation: false, - ).then((int buildExitCode) { - return buildExitCode; - }); - }); - - // Merge arch-specific App.frameworks into a multi-arch App.framework. - if ((await Future.wait(exitCodes.values)).every((int buildExitCode) => buildExitCode == 0)) { - final Iterable dylibs = iosBuilds.values.map( - (String outputDir) => globals.fs.path.join(outputDir, 'App.framework', 'App')); - globals.fs.directory(globals.fs.path.join(outputPath, 'App.framework')).createSync(); - await processUtils.run( - [ - 'lipo', - ...dylibs, - '-create', - '-output', globals.fs.path.join(outputPath, 'App.framework', 'App'), - ], - throwOnError: true, - ); - } else { - status?.cancel(); - exitCodes.forEach((DarwinArch iosArch, Future exitCodeFuture) async { - final int buildExitCode = await exitCodeFuture; - globals.printError('Snapshotting ($iosArch) exited with non-zero exit code: $buildExitCode'); - }); - } - } else { - // Android AOT snapshot. - final int snapshotExitCode = await snapshotter.build( - platform: platform, - buildMode: buildInfo.mode, - mainPath: kernelOut, - packagesPath: PackageMap.globalPackagesPath, - outputPath: outputPath, - extraGenSnapshotOptions: buildInfo.extraGenSnapshotOptions, - bitcode: false, - splitDebugInfo: null, - dartObfuscation: false, - ); - if (snapshotExitCode != 0) { - status?.cancel(); - throwToolExit('Snapshotting exited with non-zero exit code: $snapshotExitCode'); - } - } - } on ProcessException catch (error) { - // Catch the String exceptions thrown from the `runSync` methods below. - status?.cancel(); - globals.printError(error.toString()); - return; - } + ); + final BuildResult result = await buildSystem.build(target, environment); status?.stop(); - if (outputPath == null) { - throwToolExit(null); + if (!result.success) { + for (final ExceptionMeasurement measurement in result.exceptions.values) { + globals.printError(measurement.exception.toString()); + } + throwToolExit('The aot build failed.'); + } + + if (expectSo) { + environment.buildDir.childFile('app.so') + .copySync(globals.fs.path.join(outputPath, 'app.so')); + } else { + globals.fs.directory(globals.fs.path.join(outputPath, 'App.framework')) + .createSync(recursive: true); + environment.buildDir.childDirectory('App.framework').childFile('App') + .copySync(globals.fs.path.join(outputPath, 'App.framework', 'App')); } final String builtMessage = 'Built to $outputPath${globals.fs.path.separator}.'; diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart index a1f05391fd..235765a1e3 100644 --- a/packages/flutter_tools/lib/src/base/build.dart +++ b/packages/flutter_tools/lib/src/base/build.dart @@ -3,23 +3,17 @@ // found in the LICENSE file. import 'dart:async'; - import 'package:meta/meta.dart'; +import 'package:process/process.dart'; import '../artifacts.dart'; import '../build_info.dart'; -import '../bundle.dart'; -import '../compile.dart'; -import '../globals.dart' as globals; import '../macos/xcode.dart'; -import '../project.dart'; -import 'context.dart'; import 'file_system.dart'; +import 'logger.dart'; import 'process.dart'; -GenSnapshot get genSnapshot => context.get(); - /// A snapshot build configuration. class SnapshotType { SnapshotType(this.platform, this.mode) @@ -34,10 +28,18 @@ class SnapshotType { /// Interface to the gen_snapshot command-line tool. class GenSnapshot { - const GenSnapshot(); + GenSnapshot({ + @required Artifacts artifacts, + @required ProcessManager processManager, + @required Logger logger, + }) : _artifacts = artifacts, + _processUtils = ProcessUtils(logger: logger, processManager: processManager); - static String getSnapshotterPath(SnapshotType snapshotType) { - return globals.artifacts.getArtifactPath( + final Artifacts _artifacts; + final ProcessUtils _processUtils; + + String getSnapshotterPath(SnapshotType snapshotType) { + return _artifacts.getArtifactPath( Artifact.genSnapshot, platform: snapshotType.platform, mode: snapshotType.mode); } @@ -51,6 +53,7 @@ class GenSnapshot { 'Warning: This VM has been configured to obfuscate symbol information which violates the Dart standard.', ' See dartbug.com/30524 for more information.', }; + Future run({ @required SnapshotType snapshotType, DarwinArch darwinArch, @@ -68,7 +71,7 @@ class GenSnapshot { snapshotterPath += '_' + getNameForDarwinArch(darwinArch); } - return processUtils.stream( + return _processUtils.stream( [snapshotterPath, ...args], mapFunction: (String line) => kIgnoredWarnings.contains(line) ? null : line, ); @@ -76,7 +79,26 @@ class GenSnapshot { } class AOTSnapshotter { - AOTSnapshotter({this.reportTimings = false}); + AOTSnapshotter({ + this.reportTimings = false, + @required Logger logger, + @required FileSystem fileSystem, + @required Xcode xcode, + @required ProcessManager processManager, + @required Artifacts artifacts, + }) : _logger = logger, + _fileSystem = fileSystem, + _xcode = xcode, + _genSnapshot = GenSnapshot( + artifacts: artifacts, + processManager: processManager, + logger: logger, + ); + + final Logger _logger; + final FileSystem _fileSystem; + final Xcode _xcode; + final GenSnapshot _genSnapshot; /// If true then AOTSnapshotter would report timings for individual building /// steps (Dart front-end parsing and snapshot generation) in a stable @@ -97,40 +119,43 @@ class AOTSnapshotter { @required bool dartObfuscation, bool quiet = false, }) async { + // TODO(cbracken): replace IOSArch with TargetPlatform.ios_{armv7,arm64}. + assert(platform != TargetPlatform.ios || darwinArch != null); if (bitcode && platform != TargetPlatform.ios) { - globals.printError('Bitcode is only supported for iOS.'); + _logger.printError('Bitcode is only supported for iOS.'); return 1; } if (!_isValidAotPlatform(platform, buildMode)) { - globals.printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.'); + _logger.printError('${getNameForTargetPlatform(platform)} does not support AOT compilation.'); return 1; } - // TODO(cbracken): replace IOSArch with TargetPlatform.ios_{armv7,arm64}. - assert(platform != TargetPlatform.ios || darwinArch != null); - final Directory outputDir = globals.fs.directory(outputPath); + final Directory outputDir = _fileSystem.directory(outputPath); outputDir.createSync(recursive: true); final List genSnapshotArgs = [ '--deterministic', ]; if (extraGenSnapshotOptions != null && extraGenSnapshotOptions.isNotEmpty) { - globals.printTrace('Extra gen_snapshot options: $extraGenSnapshotOptions'); + _logger.printTrace('Extra gen_snapshot options: $extraGenSnapshotOptions'); genSnapshotArgs.addAll(extraGenSnapshotOptions); } - final String assembly = globals.fs.path.join(outputDir.path, 'snapshot_assembly.S'); + final String assembly = _fileSystem.path.join(outputDir.path, 'snapshot_assembly.S'); if (platform == TargetPlatform.ios || platform == TargetPlatform.darwin_x64) { - // Assembly AOT snapshot. - genSnapshotArgs.add('--snapshot_kind=app-aot-assembly'); - genSnapshotArgs.add('--assembly=$assembly'); - genSnapshotArgs.add('--strip'); + genSnapshotArgs.addAll([ + '--snapshot_kind=app-aot-assembly', + '--assembly=$assembly', + '--strip' + ]); } else { - final String aotSharedLibrary = globals.fs.path.join(outputDir.path, 'app.so'); - genSnapshotArgs.add('--snapshot_kind=app-aot-elf'); - genSnapshotArgs.add('--elf=$aotSharedLibrary'); - genSnapshotArgs.add('--strip'); + final String aotSharedLibrary = _fileSystem.path.join(outputDir.path, 'app.so'); + genSnapshotArgs.addAll([ + '--snapshot_kind=app-aot-elf', + '--elf=$aotSharedLibrary', + '--strip' + ]); } if (platform == TargetPlatform.android_arm || darwinArch == DarwinArch.armv7) { @@ -150,7 +175,7 @@ class AOTSnapshotter { final String debugFilename = 'app.$archName.symbols'; final bool shouldSplitDebugInfo = splitDebugInfo?.isNotEmpty ?? false; if (shouldSplitDebugInfo) { - globals.fs.directory(splitDebugInfo) + _fileSystem.directory(splitDebugInfo) .createSync(recursive: true); } @@ -161,7 +186,7 @@ class AOTSnapshotter { '--lazy-async-stacks', if (shouldSplitDebugInfo) ...[ '--dwarf-stack-traces', - '--save-debugging-info=${globals.fs.path.join(splitDebugInfo, debugFilename)}' + '--save-debugging-info=${_fileSystem.path.join(splitDebugInfo, debugFilename)}' ], if (dartObfuscation) '--obfuscate', @@ -170,15 +195,13 @@ class AOTSnapshotter { genSnapshotArgs.add(mainPath); final SnapshotType snapshotType = SnapshotType(platform, buildMode); - final int genSnapshotExitCode = - await _timedStep('snapshot(CompileTime)', 'aot-snapshot', - () => genSnapshot.run( + final int genSnapshotExitCode = await _genSnapshot.run( snapshotType: snapshotType, additionalArgs: genSnapshotArgs, darwinArch: darwinArch, - )); + ); if (genSnapshotExitCode != 0) { - globals.printError('Dart snapshot generator failed with exit code $genSnapshotExitCode'); + _logger.printError('Dart snapshot generator failed with exit code $genSnapshotExitCode'); return genSnapshotExitCode; } @@ -212,7 +235,7 @@ class AOTSnapshotter { }) async { final String targetArch = getNameForDarwinArch(appleArch); if (!quiet) { - globals.printStatus('Building App.framework for $targetArch...'); + _logger.printStatus('Building App.framework for $targetArch...'); } final List commonBuildOptions = [ @@ -222,15 +245,15 @@ class AOTSnapshotter { ]; const String embedBitcodeArg = '-fembed-bitcode'; - final String assemblyO = globals.fs.path.join(outputPath, 'snapshot_assembly.o'); + final String assemblyO = _fileSystem.path.join(outputPath, 'snapshot_assembly.o'); List isysrootArgs; if (isIOS) { - final String iPhoneSDKLocation = await globals.xcode.sdkLocation(SdkType.iPhone); + final String iPhoneSDKLocation = await _xcode.sdkLocation(SdkType.iPhone); if (iPhoneSDKLocation != null) { isysrootArgs = ['-isysroot', iPhoneSDKLocation]; } } - final RunResult compileResult = await globals.xcode.cc([ + final RunResult compileResult = await _xcode.cc([ '-arch', targetArch, if (isysrootArgs != null) ...isysrootArgs, if (bitcode) embedBitcodeArg, @@ -240,13 +263,13 @@ class AOTSnapshotter { assemblyO, ]); if (compileResult.exitCode != 0) { - globals.printError('Failed to compile AOT snapshot. Compiler terminated with exit code ${compileResult.exitCode}'); + _logger.printError('Failed to compile AOT snapshot. Compiler terminated with exit code ${compileResult.exitCode}'); return compileResult; } - final String frameworkDir = globals.fs.path.join(outputPath, 'App.framework'); - globals.fs.directory(frameworkDir).createSync(recursive: true); - final String appLib = globals.fs.path.join(frameworkDir, 'App'); + final String frameworkDir = _fileSystem.path.join(outputPath, 'App.framework'); + _fileSystem.directory(frameworkDir).createSync(recursive: true); + final String appLib = _fileSystem.path.join(frameworkDir, 'App'); final List linkArgs = [ ...commonBuildOptions, '-dynamiclib', @@ -258,64 +281,13 @@ class AOTSnapshotter { '-o', appLib, assemblyO, ]; - final RunResult linkResult = await globals.xcode.clang(linkArgs); + final RunResult linkResult = await _xcode.clang(linkArgs); if (linkResult.exitCode != 0) { - globals.printError('Failed to link AOT snapshot. Linker terminated with exit code ${compileResult.exitCode}'); + _logger.printError('Failed to link AOT snapshot. Linker terminated with exit code ${compileResult.exitCode}'); } return linkResult; } - /// Compiles a Dart file to kernel. - /// - /// Returns the output kernel file path, or null on failure. - Future compileKernel({ - @required TargetPlatform platform, - @required BuildMode buildMode, - @required String mainPath, - @required String packagesPath, - @required String outputPath, - @required bool trackWidgetCreation, - @required List dartDefines, - List extraFrontEndOptions = const [], - }) async { - final FlutterProject flutterProject = FlutterProject.current(); - final Directory outputDir = globals.fs.directory(outputPath); - outputDir.createSync(recursive: true); - - globals.printTrace('Compiling Dart to kernel: $mainPath'); - - if ((extraFrontEndOptions != null) && extraFrontEndOptions.isNotEmpty) { - globals.printTrace('Extra front-end options: $extraFrontEndOptions'); - } - - final String depfilePath = globals.fs.path.join(outputPath, 'kernel_compile.d'); - final KernelCompiler kernelCompiler = await kernelCompilerFactory.create(flutterProject); - final CompilerOutput compilerOutput = - await _timedStep('frontend(CompileTime)', 'aot-kernel', - () => kernelCompiler.compile( - sdkRoot: globals.artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath, mode: buildMode), - mainPath: mainPath, - packagesPath: packagesPath, - outputFilePath: getKernelPathForTransformerOptions( - globals.fs.path.join(outputPath, 'app.dill'), - trackWidgetCreation: trackWidgetCreation, - ), - depFilePath: depfilePath, - extraFrontEndOptions: extraFrontEndOptions, - linkPlatformKernelIn: true, - aot: true, - buildMode: buildMode, - trackWidgetCreation: trackWidgetCreation, - dartDefines: dartDefines, - )); - - // Write path to frontend_server, since things need to be re-generated when that changes. - final String frontendPath = globals.artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk); - globals.fs.directory(outputPath).childFile('frontend_server.d').writeAsStringSync('frontend_server.d: $frontendPath\n'); - - return compilerOutput?.outputFilename; - } - bool _isValidAotPlatform(TargetPlatform platform, BuildMode buildMode) { if (buildMode == BuildMode.debug) { return false; @@ -328,19 +300,4 @@ class AOTSnapshotter { TargetPlatform.darwin_x64, ].contains(platform); } - - /// This method is used to measure duration of an action and emit it into - /// verbose output from flutter_tool for other tools (e.g. benchmark runner) - /// to find. - /// Important: external performance tracking tools expect format of this - /// output to be stable. - Future _timedStep(String marker, String analyticsVar, FutureOr Function() action) async { - final Stopwatch sw = Stopwatch()..start(); - final T value = await action(); - if (reportTimings) { - globals.printStatus('$marker: ${sw.elapsedMilliseconds} ms.'); - } - globals.flutterUsage.sendTiming('build', analyticsVar, Duration(milliseconds: sw.elapsedMilliseconds)); - return value; - } } diff --git a/packages/flutter_tools/lib/src/base/logger.dart b/packages/flutter_tools/lib/src/base/logger.dart index 0d9283311f..d946e22c8c 100644 --- a/packages/flutter_tools/lib/src/base/logger.dart +++ b/packages/flutter_tools/lib/src/base/logger.dart @@ -697,7 +697,7 @@ abstract class Status { @required Duration timeout, @required TimeoutConfiguration timeoutConfiguration, @required Stopwatch stopwatch, - @required AnsiTerminal terminal, + @required Terminal terminal, VoidCallback onFinish, SlowWarningCallback slowWarningCallback, }) { @@ -877,7 +877,7 @@ class AnsiSpinner extends Status { @required Duration timeout, @required TimeoutConfiguration timeoutConfiguration, @required Stopwatch stopwatch, - @required AnsiTerminal terminal, + @required Terminal terminal, VoidCallback onFinish, this.slowWarningCallback, Stdio stdio, @@ -893,7 +893,7 @@ class AnsiSpinner extends Status { final String _backspaceChar = '\b'; final String _clearChar = ' '; final Stdio _stdio; - final AnsiTerminal _terminal; + final Terminal _terminal; bool timedOut = false; diff --git a/packages/flutter_tools/lib/src/build_system/targets/android.dart b/packages/flutter_tools/lib/src/build_system/targets/android.dart index ed677b2589..d832c50f58 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/android.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/android.dart @@ -210,7 +210,14 @@ class AndroidAot extends AotElfBase { @override Future build(Environment environment) async { - final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: false); + final AOTSnapshotter snapshotter = AOTSnapshotter( + reportTimings: false, + fileSystem: globals.fs, + logger: globals.logger, + xcode: globals.xcode, + processManager: globals.processManager, + artifacts: globals.artifacts, + ); final Directory output = environment.buildDir.childDirectory(_androidAbiName); final String splitDebugInfo = environment.defines[kSplitDebugInfo]; if (environment.defines[kBuildMode] == null) { diff --git a/packages/flutter_tools/lib/src/build_system/targets/dart.dart b/packages/flutter_tools/lib/src/build_system/targets/dart.dart index afa08b77ff..a67e834293 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/dart.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/dart.dart @@ -204,9 +204,7 @@ class KernelSnapshot extends Target { final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]); // This configuration is all optional. - final List extraFrontEndOptions = [ - ...?environment.defines[kExtraFrontEndOptions]?.split(',') - ]; + final List extraFrontEndOptions = environment.defines[kExtraFrontEndOptions]?.split(','); final List fileSystemRoots = environment.defines[kFileSystemRoots]?.split(','); final String fileSystemScheme = environment.defines[kFileSystemScheme]; @@ -261,7 +259,14 @@ abstract class AotElfBase extends Target { @override Future build(Environment environment) async { - final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: false); + final AOTSnapshotter snapshotter = AOTSnapshotter( + reportTimings: false, + fileSystem: globals.fs, + logger: globals.logger, + xcode: globals.xcode, + processManager: globals.processManager, + artifacts: globals.artifacts, + ); final String outputPath = environment.buildDir.path; if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'aot_elf'); 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 990716cf8a..20e685ab0d 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/ios.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/ios.dart @@ -28,7 +28,14 @@ abstract class AotAssemblyBase extends Target { @override Future build(Environment environment) async { - final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: false); + final AOTSnapshotter snapshotter = AOTSnapshotter( + reportTimings: false, + fileSystem: globals.fs, + logger: globals.logger, + xcode: globals.xcode, + artifacts: globals.artifacts, + processManager: globals.processManager, + ); final String buildOutputPath = environment.buildDir.path; if (environment.defines[kBuildMode] == null) { throw MissingDefineException(kBuildMode, 'aot_assembly'); @@ -36,6 +43,8 @@ abstract class AotAssemblyBase extends Target { if (environment.defines[kTargetPlatform] == null) { throw MissingDefineException(kTargetPlatform, 'aot_assembly'); } + final List extraGenSnapshotOptions = environment + .defines[kExtraGenSnapshotOptions]?.split(',') ?? const []; final bool bitcode = environment.defines[kBitcodeFlag] == 'true'; final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]); final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]); @@ -65,6 +74,7 @@ abstract class AotAssemblyBase extends Target { quiet: true, splitDebugInfo: splitDebugInfo, dartObfuscation: dartObfuscation, + extraGenSnapshotOptions: extraGenSnapshotOptions, )); } final List results = await Future.wait(pending); 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 a4d5c9dfe3..5104d99901 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/macos.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/macos.dart @@ -202,7 +202,15 @@ class CompileMacOSFramework extends Target { } final String splitDebugInfo = environment.defines[kSplitDebugInfo]; final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true'; - final int result = await AOTSnapshotter(reportTimings: false).build( + final AOTSnapshotter snapshotter = AOTSnapshotter( + reportTimings: false, + fileSystem: globals.fs, + logger: globals.logger, + xcode: globals.xcode, + artifacts: globals.artifacts, + processManager: globals.processManager + ); + final int result = await snapshotter.build( bitcode: false, buildMode: buildMode, mainPath: environment.buildDir.childFile('app.dill').path, diff --git a/packages/flutter_tools/lib/src/commands/build_aot.dart b/packages/flutter_tools/lib/src/commands/build_aot.dart index fb5694255d..f54ec5c51e 100644 --- a/packages/flutter_tools/lib/src/commands/build_aot.dart +++ b/packages/flutter_tools/lib/src/commands/build_aot.dart @@ -27,11 +27,6 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen allowed: ['android-arm', 'android-arm64', 'ios', 'android-x64'], ) ..addFlag('quiet', defaultsTo: false) - ..addFlag('report-timings', - negatable: false, - defaultsTo: false, - help: 'Report timing information about build steps in machine readable form,', - ) ..addMultiOption('ios-arch', splitCommas: true, defaultsTo: defaultIOSArchs.map(getNameForDarwinArch), @@ -80,7 +75,6 @@ class BuildAotCommand extends BuildSubCommand with TargetPlatformBasedDevelopmen mainDartFile: findMainDartFile(targetFile), bitcode: boolArg('bitcode'), quiet: boolArg('quiet'), - reportTimings: boolArg('report-timings'), iosBuildArchs: stringsArg('ios-arch').map(getIOSArchForName), ); return FlutterCommandResult.success(); diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart index dd0943776d..1784a906d3 100644 --- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart +++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart @@ -436,7 +436,6 @@ end mainDartFile: globals.fs.path.absolute(targetFile), quiet: true, bitcode: true, - reportTimings: false, iosBuildArchs: [DarwinArch.armv7, DarwinArch.arm64], ); } finally { diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index 07ad8c8a03..beb2100248 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -11,7 +11,6 @@ import 'android/gradle_utils.dart'; import 'application_package.dart'; import 'artifacts.dart'; import 'asset.dart'; -import 'base/build.dart'; import 'base/config.dart'; import 'base/context.dart'; import 'base/io.dart'; @@ -125,7 +124,6 @@ Future runInContext( FuchsiaDeviceTools: () => FuchsiaDeviceTools(), FuchsiaSdk: () => FuchsiaSdk(), FuchsiaWorkflow: () => FuchsiaWorkflow(), - GenSnapshot: () => const GenSnapshot(), GradleUtils: () => GradleUtils(), HotRunnerConfig: () => HotRunnerConfig(), IMobileDevice: () => IMobileDevice(), diff --git a/packages/flutter_tools/lib/src/ios/xcodeproj.dart b/packages/flutter_tools/lib/src/ios/xcodeproj.dart index 3bd514163a..09081ecf28 100644 --- a/packages/flutter_tools/lib/src/ios/xcodeproj.dart +++ b/packages/flutter_tools/lib/src/ios/xcodeproj.dart @@ -249,7 +249,7 @@ class XcodeProjectInterpreter { @required ProcessManager processManager, @required Logger logger, @required FileSystem fileSystem, - @required AnsiTerminal terminal, + @required Terminal terminal, }) : _platform = platform, _fileSystem = fileSystem, _terminal = terminal, @@ -259,7 +259,7 @@ class XcodeProjectInterpreter { final Platform _platform; final FileSystem _fileSystem; final ProcessUtils _processUtils; - final AnsiTerminal _terminal; + final Terminal _terminal; final Logger _logger; static const String _executable = '/usr/bin/xcodebuild'; diff --git a/packages/flutter_tools/test/general.shard/base/build_test.dart b/packages/flutter_tools/test/general.shard/base/build_test.dart index 6ea4d69114..00a4625a0a 100644 --- a/packages/flutter_tools/test/general.shard/base/build_test.dart +++ b/packages/flutter_tools/test/general.shard/base/build_test.dart @@ -2,75 +2,70 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:async'; -import 'dart:convert'; - import 'package:file/memory.dart'; -import 'package:flutter_tools/src/android/android_sdk.dart'; +import 'package:mockito/mockito.dart'; +import 'package:platform/platform.dart'; + import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/base/build.dart'; -import 'package:flutter_tools/src/base/context.dart'; -import 'package:flutter_tools/src/base/file_system.dart'; -import 'package:flutter_tools/src/base/io.dart'; -import 'package:flutter_tools/src/base/process.dart'; +import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/macos/xcode.dart'; -import 'package:flutter_tools/src/version.dart'; -import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:mockito/mockito.dart'; -import 'package:process/process.dart'; import '../../src/common.dart'; import '../../src/context.dart'; -class MockFlutterVersion extends Mock implements FlutterVersion {} -class MockAndroidSdk extends Mock implements AndroidSdk {} -class MockArtifacts extends Mock implements Artifacts {} -class MockXcode extends Mock implements Xcode {} -class MockProcessManager extends Mock implements ProcessManager {} -class MockProcess extends Mock implements Process {} +const FakeCommand kSdkPathCommand = FakeCommand( + command: [ + 'xcrun', + '--sdk', + 'iphoneos', + '--show-sdk-path' + ] +); -class _FakeGenSnapshot implements GenSnapshot { - _FakeGenSnapshot({ - this.succeed = true, - }); +const List kDefaultClang = [ + '-miphoneos-version-min=8.0', + '-dynamiclib', + '-Xlinker', + '-rpath', + '-Xlinker', + '@executable_path/Frameworks', + '-Xlinker', + '-rpath', + '-Xlinker', + '@loader_path/Frameworks', + '-install_name', + '@rpath/App.framework/App', + '-isysroot', + '', + '-o', + 'build/foo/App.framework/App', + 'build/foo/snapshot_assembly.o', +]; - final bool succeed; - Map outputs = {}; - int _callCount = 0; - SnapshotType _snapshotType; - String _depfilePath; - List _additionalArgs; - - int get callCount => _callCount; - - SnapshotType get snapshotType => _snapshotType; - - String get depfilePath => _depfilePath; - - List get additionalArgs => _additionalArgs; - - @override - Future run({ - SnapshotType snapshotType, - String depfilePath, - DarwinArch darwinArch, - Iterable additionalArgs = const [], - }) async { - _callCount += 1; - _snapshotType = snapshotType; - _depfilePath = depfilePath; - _additionalArgs = additionalArgs.toList(); - - if (!succeed) { - return 1; - } - outputs.forEach((String filePath, String fileContent) { - globals.fs.file(filePath).writeAsString(fileContent); - }); - return 0; - } -} +const List kBitcodeClang = [ + '-miphoneos-version-min=8.0', + '-dynamiclib', + '-Xlinker', + '-rpath', + '-Xlinker', + '@executable_path/Frameworks', + '-Xlinker', + '-rpath', + '-Xlinker', + '@loader_path/Frameworks', + '-install_name', + '@rpath/App.framework/App', + '-fembed-bitcode', + '-isysroot', + '', + '-o', + 'build/foo/App.framework/App', + 'build/foo/snapshot_assembly.o', +]; void main() { group('SnapshotType', () { @@ -81,181 +76,137 @@ void main() { ); }); test('does not throw, if target platform is null', () { - expect(SnapshotType(null, BuildMode.release), isNotNull); + expect(() => SnapshotType(null, BuildMode.release), returnsNormally); }); }); group('GenSnapshot', () { GenSnapshot genSnapshot; MockArtifacts mockArtifacts; - MockProcessManager mockProcessManager; - MockProcess mockProc; + FakeProcessManager processManager; + BufferLogger logger; setUp(() async { - genSnapshot = const GenSnapshot(); mockArtifacts = MockArtifacts(); - mockProcessManager = MockProcessManager(); - mockProc = MockProcess(); + logger = BufferLogger.test(); + processManager = FakeProcessManager.list(< FakeCommand>[]); + genSnapshot = GenSnapshot( + artifacts: mockArtifacts, + logger: logger, + processManager: processManager, + ); + when(mockArtifacts.getArtifactPath( + any, + platform: anyNamed('platform'), + mode: anyNamed('mode'), + )).thenReturn('gen_snapshot'); }); - final Map contextOverrides = { - Artifacts: () => mockArtifacts, - ProcessManager: () => mockProcessManager, - }; + testWithoutContext('android_x64', () async { + processManager.addCommand(const FakeCommand( + command: ['gen_snapshot', '--additional_arg'] + )); - testUsingContext('android_x64', () async { - when(mockArtifacts.getArtifactPath(Artifact.genSnapshot, - platform: TargetPlatform.android_x64, mode: BuildMode.release)) - .thenReturn('gen_snapshot'); - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) => Future.value(mockProc)); - when(mockProc.stdout).thenAnswer((_) => const Stream>.empty()); - when(mockProc.stderr).thenAnswer((_) => const Stream>.empty()); - await genSnapshot.run( - snapshotType: - SnapshotType(TargetPlatform.android_x64, BuildMode.release), - darwinArch: null, - additionalArgs: ['--additional_arg']); - verify(mockProcessManager.start( - [ - 'gen_snapshot', - '--additional_arg', - ], - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'), - )).called(1); - }, overrides: contextOverrides); + final int result = await genSnapshot.run( + snapshotType: SnapshotType(TargetPlatform.android_x64, BuildMode.release), + darwinArch: null, + additionalArgs: ['--additional_arg'], + ); + expect(result, 0); + }); - testUsingContext('iOS armv7', () async { - when(mockArtifacts.getArtifactPath(Artifact.genSnapshot, - platform: TargetPlatform.ios, mode: BuildMode.release)) - .thenReturn('gen_snapshot'); - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) => Future.value(mockProc)); - when(mockProc.stdout).thenAnswer((_) => const Stream>.empty()); - when(mockProc.stderr).thenAnswer((_) => const Stream>.empty()); - await genSnapshot.run( - snapshotType: SnapshotType(TargetPlatform.ios, BuildMode.release), - darwinArch: DarwinArch.armv7, - additionalArgs: ['--additional_arg']); - verify(mockProcessManager.start( - [ - 'gen_snapshot_armv7', - '--additional_arg', - ], - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment')), - ).called(1); - }, overrides: contextOverrides); + testWithoutContext('iOS armv7', () async { + processManager.addCommand(const FakeCommand( + command: ['gen_snapshot_armv7', '--additional_arg'] + )); - testUsingContext('iOS arm64', () async { - when(mockArtifacts.getArtifactPath(Artifact.genSnapshot, - platform: TargetPlatform.ios, mode: BuildMode.release)) - .thenReturn('gen_snapshot'); - when(mockProcessManager.start(any, - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) => Future.value(mockProc)); - when(mockProc.stdout).thenAnswer((_) => const Stream>.empty()); - when(mockProc.stderr).thenAnswer((_) => const Stream>.empty()); - await genSnapshot.run( - snapshotType: SnapshotType(TargetPlatform.ios, BuildMode.release), - darwinArch: DarwinArch.arm64, - additionalArgs: ['--additional_arg']); - verify(mockProcessManager.start( - [ - 'gen_snapshot_arm64', - '--additional_arg', - ], - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'), - )).called(1); - }, overrides: contextOverrides); + final int result = await genSnapshot.run( + snapshotType: SnapshotType(TargetPlatform.ios, BuildMode.release), + darwinArch: DarwinArch.armv7, + additionalArgs: ['--additional_arg'], + ); + expect(result, 0); + }); - testUsingContext('--strip filters outputs', () async { - when(mockArtifacts.getArtifactPath(Artifact.genSnapshot, - platform: TargetPlatform.android_x64, mode: BuildMode.release)) - .thenReturn('gen_snapshot'); - when(mockProcessManager.start( - ['gen_snapshot', '--strip'], - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .thenAnswer((_) => Future.value(mockProc)); - when(mockProc.stdout).thenAnswer((_) => const Stream>.empty()); - when(mockProc.stderr) - .thenAnswer((_) => Stream.fromIterable([ - '--ABC\n', - 'Warning: Generating ELF library without DWARF debugging information.\n', - '--XYZ\n', - ]) - .transform>(utf8.encoder)); - await genSnapshot.run( - snapshotType: - SnapshotType(TargetPlatform.android_x64, BuildMode.release), - darwinArch: null, - additionalArgs: ['--strip']); - verify(mockProcessManager.start( - ['gen_snapshot', '--strip'], - workingDirectory: anyNamed('workingDirectory'), - environment: anyNamed('environment'))) - .called(1); - expect(testLogger.errorText, contains('ABC')); - expect(testLogger.errorText, isNot(contains('ELF library'))); - expect(testLogger.errorText, contains('XYZ')); - }, overrides: contextOverrides); + testWithoutContext('iOS arm64', () async { + processManager.addCommand(const FakeCommand( + command: ['gen_snapshot_arm64', '--additional_arg'] + )); + + final int result = await genSnapshot.run( + snapshotType: SnapshotType(TargetPlatform.ios, BuildMode.release), + darwinArch: DarwinArch.arm64, + additionalArgs: ['--additional_arg'], + ); + expect(result, 0); + }); + + testWithoutContext('--strip filters error output from gen_snapshot', () async { + processManager.addCommand(FakeCommand( + command: const ['gen_snapshot', '--strip'], + stderr: 'ABC\n${GenSnapshot.kIgnoredWarnings.join('\n')}\nXYZ\n' + )); + + final int result = await genSnapshot.run( + snapshotType: SnapshotType(TargetPlatform.android_x64, BuildMode.release), + darwinArch: null, + additionalArgs: ['--strip'], + ); + + expect(result, 0); + expect(logger.errorText, contains('ABC')); + for (final String ignoredWarning in GenSnapshot.kIgnoredWarnings) { + expect(logger.errorText, isNot(contains(ignoredWarning))); + } + expect(logger.errorText, contains('XYZ')); + }); }); - group('Snapshotter - AOT', () { - const String kSnapshotDart = 'snapshot.dart'; - const String kSDKPath = '/path/to/sdk'; - String skyEnginePath; - - _FakeGenSnapshot genSnapshot; - MemoryFileSystem fs; + group('AOTSnapshotter', () { + MemoryFileSystem fileSystem; AOTSnapshotter snapshotter; - AOTSnapshotter snapshotterWithTimings; - MockAndroidSdk mockAndroidSdk; MockArtifacts mockArtifacts; - MockXcode mockXcode; + FakeProcessManager processManager; + Logger logger; setUp(() async { - fs = MemoryFileSystem(); - fs.file(kSnapshotDart).createSync(); - fs.file('.packages').writeAsStringSync('sky_engine:file:///flutter/bin/cache/pkg/sky_engine/lib/'); - - skyEnginePath = fs.path.fromUri(Uri.file('/flutter/bin/cache/pkg/sky_engine')); - fs.directory(fs.path.join(skyEnginePath, 'lib', 'ui')).createSync(recursive: true); - fs.directory(fs.path.join(skyEnginePath, 'sdk_ext')).createSync(recursive: true); - fs.file(fs.path.join(skyEnginePath, '.packages')).createSync(); - fs.file(fs.path.join(skyEnginePath, 'lib', 'ui', 'ui.dart')).createSync(); - fs.file(fs.path.join(skyEnginePath, 'sdk_ext', 'vmservice_io.dart')).createSync(); - - genSnapshot = _FakeGenSnapshot(); - snapshotter = AOTSnapshotter(); - snapshotterWithTimings = AOTSnapshotter(reportTimings: true); - mockAndroidSdk = MockAndroidSdk(); + final Platform platform = FakePlatform(operatingSystem: 'macos'); + logger = BufferLogger.test(); + fileSystem = MemoryFileSystem.test(); mockArtifacts = MockArtifacts(); - mockXcode = MockXcode(); - when(mockXcode.sdkLocation(any)).thenAnswer((_) => Future.value(kSDKPath)); + processManager = FakeProcessManager.list([]); + snapshotter = AOTSnapshotter( + fileSystem: fileSystem, + logger: logger, + xcode: Xcode( + fileSystem: fileSystem, + logger: logger, + platform: FakePlatform(operatingSystem: 'macos'), + processManager: processManager, + xcodeProjectInterpreter: XcodeProjectInterpreter( + platform: platform, + processManager: processManager, + logger: logger, + fileSystem: fileSystem, + terminal: Terminal.test(), + ), + ), + artifacts: mockArtifacts, + processManager: processManager, + ); + when(mockArtifacts.getArtifactPath( + Artifact.genSnapshot, + platform: anyNamed('platform'), + mode: anyNamed('mode')), + ).thenReturn('gen_snapshot'); }); - final Map contextOverrides = { - AndroidSdk: () => mockAndroidSdk, - Artifacts: () => mockArtifacts, - FileSystem: () => fs, - ProcessManager: () => FakeProcessManager.any(), - GenSnapshot: () => genSnapshot, - Xcode: () => mockXcode, - }; + testWithoutContext('does not build iOS with debug build mode', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); - testUsingContext('iOS debug AOT snapshot is invalid', () async { - final String outputPath = globals.fs.path.join('build', 'foo'); expect(await snapshotter.build( platform: TargetPlatform.ios, + darwinArch: DarwinArch.arm64, buildMode: BuildMode.debug, mainPath: 'main.dill', packagesPath: '.packages', @@ -264,10 +215,11 @@ void main() { splitDebugInfo: null, dartObfuscation: false, ), isNot(equals(0))); - }, overrides: contextOverrides); + }); + + testWithoutContext('does not build android-arm with debug build mode', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); - testUsingContext('Android arm debug AOT snapshot is invalid', () async { - final String outputPath = globals.fs.path.join('build', 'foo'); expect(await snapshotter.build( platform: TargetPlatform.android_arm, buildMode: BuildMode.debug, @@ -278,10 +230,11 @@ void main() { splitDebugInfo: null, dartObfuscation: false, ), isNot(0)); - }, overrides: contextOverrides); + }); + + testWithoutContext('does not build android-arm64 with debug build mode', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); - testUsingContext('Android arm64 debug AOT snapshot is invalid', () async { - final String outputPath = globals.fs.path.join('build', 'foo'); expect(await snapshotter.build( platform: TargetPlatform.android_arm64, buildMode: BuildMode.debug, @@ -292,22 +245,50 @@ void main() { splitDebugInfo: null, dartObfuscation: false, ), isNot(0)); - }, overrides: contextOverrides); + }); - testUsingContext('iOS profile AOT with bitcode uses right flags', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - final String assembly = globals.fs.path.join(outputPath, 'snapshot_assembly.S'); - genSnapshot.outputs = { - assembly: 'blah blah\n.section __DWARF\nblah blah\n', - }; - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); + testWithoutContext('builds iOS with bitcode', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S'); + processManager.addCommand(FakeCommand( + command: [ + 'gen_snapshot_armv7', + '--deterministic', + '--snapshot_kind=app-aot-assembly', + '--assembly=$assembly', + '--strip', + '--no-sim-use-hardfp', + '--no-use-integer-division', + '--no-causal-async-stacks', + '--lazy-async-stacks', + 'main.dill', + ] + )); + processManager.addCommand(kSdkPathCommand); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'cc', + '-arch', + 'armv7', + '-isysroot', + '', + '-fembed-bitcode', + '-c', + 'build/foo/snapshot_assembly.S', + '-o', + 'build/foo/snapshot_assembly.o', + ] + )); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'clang', + '-arch', + 'armv7', + ...kBitcodeClang, + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.ios, @@ -322,169 +303,53 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.ios); - expect(genSnapshot.snapshotType.mode, BuildMode.profile); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=$assembly', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); + expect(processManager.hasRemainingExpectations, false); + }); - final VerificationResult toVerifyCC = verify(mockXcode.cc(captureAny)); - expect(toVerifyCC.callCount, 1); - final dynamic ccArgs = toVerifyCC.captured.first; - expect(ccArgs, contains('-fembed-bitcode')); - expect(ccArgs, contains('-isysroot')); - expect(ccArgs, contains(kSDKPath)); - - final VerificationResult toVerifyClang = verify(mockXcode.clang(captureAny)); - expect(toVerifyClang.callCount, 1); - final dynamic clangArgs = toVerifyClang.captured.first; - expect(clangArgs, contains('-fembed-bitcode')); - expect(clangArgs, contains('-isysroot')); - expect(clangArgs, contains(kSDKPath)); - - final File assemblyFile = globals.fs.file(assembly); - expect(assemblyFile.existsSync(), true); - expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true); - }, overrides: contextOverrides); - - testUsingContext('iOS release AOT with bitcode uses right flags', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - final String assembly = globals.fs.path.join(outputPath, 'snapshot_assembly.S'); - genSnapshot.outputs = { - assembly: 'blah blah\n', - }; - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); - - final int genSnapshotExitCode = await snapshotter.build( - platform: TargetPlatform.ios, - buildMode: BuildMode.release, - mainPath: 'main.dill', - packagesPath: '.packages', - outputPath: outputPath, - darwinArch: DarwinArch.armv7, - bitcode: true, - splitDebugInfo: null, - dartObfuscation: false, - ); - - expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.ios); - expect(genSnapshot.snapshotType.mode, BuildMode.release); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=$assembly', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); - - final VerificationResult toVerifyCC = verify(mockXcode.cc(captureAny)); - expect(toVerifyCC.callCount, 1); - final dynamic ccArgs = toVerifyCC.captured.first; - expect(ccArgs, contains('-fembed-bitcode')); - expect(ccArgs, contains('-isysroot')); - expect(ccArgs, contains(kSDKPath)); - - final VerificationResult toVerifyClang = verify(mockXcode.clang(captureAny)); - expect(toVerifyClang.callCount, 1); - final dynamic clangArgs = toVerifyClang.captured.first; - expect(clangArgs, contains('-fembed-bitcode')); - expect(clangArgs, contains('-isysroot')); - expect(clangArgs, contains(kSDKPath)); - - final File assemblyFile = globals.fs.file(assembly); - expect(assemblyFile.existsSync(), true); - }, overrides: contextOverrides); - - testUsingContext('builds iOS armv7 profile AOT snapshot', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - final String assembly = globals.fs.path.join(outputPath, 'snapshot_assembly.S'); - genSnapshot.outputs = { - assembly: 'blah blah\n.section __DWARF\nblah blah\n', - }; - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); - - final int genSnapshotExitCode = await snapshotter.build( - platform: TargetPlatform.ios, - buildMode: BuildMode.profile, - mainPath: 'main.dill', - packagesPath: '.packages', - outputPath: outputPath, - darwinArch: DarwinArch.armv7, - bitcode: false, - splitDebugInfo: null, - dartObfuscation: false, - ); - - expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.ios); - expect(genSnapshot.snapshotType.mode, BuildMode.profile); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=$assembly', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); - verifyNever(mockXcode.cc(argThat(contains('-fembed-bitcode')))); - verifyNever(mockXcode.clang(argThat(contains('-fembed-bitcode')))); - - verify(mockXcode.cc(argThat(contains('-isysroot')))).called(1); - verify(mockXcode.clang(argThat(contains('-isysroot')))).called(1); - - final File assemblyFile = globals.fs.file(assembly); - expect(assemblyFile.existsSync(), true); - expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true); - }, overrides: contextOverrides); - - testUsingContext('builds iOS armv7 profile AOT snapshot with dwarStackTraces', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - final String assembly = globals.fs.path.join(outputPath, 'snapshot_assembly.S'); - genSnapshot.outputs = { - assembly: 'blah blah\n.section __DWARF\nblah blah\n', - }; - final String debugPath = globals.fs.path.join('foo', 'app.ios-armv7.symbols'); - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); + testWithoutContext('builds iOS armv7 snapshot with dwarStackTraces', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S'); + final String debugPath = fileSystem.path.join('foo', 'app.ios-armv7.symbols'); + processManager.addCommand(FakeCommand( + command: [ + 'gen_snapshot_armv7', + '--deterministic', + '--snapshot_kind=app-aot-assembly', + '--assembly=$assembly', + '--strip', + '--no-sim-use-hardfp', + '--no-use-integer-division', + '--no-causal-async-stacks', + '--lazy-async-stacks', + '--dwarf-stack-traces', + '--save-debugging-info=$debugPath', + 'main.dill', + ] + )); + processManager.addCommand(kSdkPathCommand); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'cc', + '-arch', + 'armv7', + '-isysroot', + '', + '-c', + 'build/foo/snapshot_assembly.S', + '-o', + 'build/foo/snapshot_assembly.o', + ] + )); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'clang', + '-arch', + 'armv7', + ...kDefaultClang, + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.ios, @@ -499,47 +364,51 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.ios); - expect(genSnapshot.snapshotType.mode, BuildMode.profile); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=$assembly', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - '--dwarf-stack-traces', - '--save-debugging-info=$debugPath', - 'main.dill', - ]); - verifyNever(mockXcode.cc(argThat(contains('-fembed-bitcode')))); - verifyNever(mockXcode.clang(argThat(contains('-fembed-bitcode')))); + expect(processManager.hasRemainingExpectations, false); + }); - verify(mockXcode.cc(argThat(contains('-isysroot')))).called(1); - verify(mockXcode.clang(argThat(contains('-isysroot')))).called(1); - - final File assemblyFile = globals.fs.file(assembly); - expect(assemblyFile.existsSync(), true); - expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true); - }, overrides: contextOverrides); - - testUsingContext('builds iOS armv7 profile AOT snapshot with obfuscate', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - final String assembly = globals.fs.path.join(outputPath, 'snapshot_assembly.S'); - genSnapshot.outputs = { - assembly: 'blah blah\n.section __DWARF\nblah blah\n', - }; - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); + testWithoutContext('builds iOS armv7 snapshot with obfuscate', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + final String assembly = fileSystem.path.join(outputPath, 'snapshot_assembly.S'); + processManager.addCommand(FakeCommand( + command: [ + 'gen_snapshot_armv7', + '--deterministic', + '--snapshot_kind=app-aot-assembly', + '--assembly=$assembly', + '--strip', + '--no-sim-use-hardfp', + '--no-use-integer-division', + '--no-causal-async-stacks', + '--lazy-async-stacks', + '--obfuscate', + 'main.dill', + ] + )); + processManager.addCommand(kSdkPathCommand); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'cc', + '-arch', + 'armv7', + '-isysroot', + '', + '-c', + 'build/foo/snapshot_assembly.S', + '-o', + 'build/foo/snapshot_assembly.o', + ] + )); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'clang', + '-arch', + 'armv7', + ...kDefaultClang, + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.ios, @@ -554,86 +423,50 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.ios); - expect(genSnapshot.snapshotType.mode, BuildMode.profile); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=$assembly', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - '--obfuscate', - 'main.dill', - ]); - verifyNever(mockXcode.cc(argThat(contains('-fembed-bitcode')))); - verifyNever(mockXcode.clang(argThat(contains('-fembed-bitcode')))); + expect(processManager.hasRemainingExpectations, false); + }); - verify(mockXcode.cc(argThat(contains('-isysroot')))).called(1); - verify(mockXcode.clang(argThat(contains('-isysroot')))).called(1); - final File assemblyFile = globals.fs.file(assembly); - expect(assemblyFile.existsSync(), true); - expect(assemblyFile.readAsStringSync().contains('.section __DWARF'), true); - }, overrides: contextOverrides); - - testUsingContext('builds iOS arm64 profile AOT snapshot', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - genSnapshot.outputs = { - globals.fs.path.join(outputPath, 'snapshot_assembly.S'): '', - }; - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); - - final int genSnapshotExitCode = await snapshotter.build( - platform: TargetPlatform.ios, - buildMode: BuildMode.profile, - mainPath: 'main.dill', - packagesPath: '.packages', - outputPath: outputPath, - darwinArch: DarwinArch.arm64, - bitcode: false, - splitDebugInfo: null, - dartObfuscation: false, - ); - - expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.ios); - expect(genSnapshot.snapshotType.mode, BuildMode.profile); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=${globals.fs.path.join(outputPath, 'snapshot_assembly.S')}', - '--strip', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); - }, overrides: contextOverrides); - - testUsingContext('builds iOS release armv7 AOT snapshot', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - genSnapshot.outputs = { - globals.fs.path.join(outputPath, 'snapshot_assembly.S'): '', - }; - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); + testWithoutContext('builds iOS armv7 snapshot', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + processManager.addCommand(FakeCommand( + command: [ + 'gen_snapshot_armv7', + '--deterministic', + '--snapshot_kind=app-aot-assembly', + '--assembly=${fileSystem.path.join(outputPath, 'snapshot_assembly.S')}', + '--strip', + '--no-sim-use-hardfp', + '--no-use-integer-division', + '--no-causal-async-stacks', + '--lazy-async-stacks', + 'main.dill', + ] + )); + processManager.addCommand(kSdkPathCommand); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'cc', + '-arch', + 'armv7', + '-isysroot', + '', + '-c', + 'build/foo/snapshot_assembly.S', + '-o', + 'build/foo/snapshot_assembly.o', + ] + )); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'clang', + '-arch', + 'armv7', + ...kDefaultClang, + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.ios, @@ -648,35 +481,47 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.ios); - expect(genSnapshot.snapshotType.mode, BuildMode.release); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=${globals.fs.path.join(outputPath, 'snapshot_assembly.S')}', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); - }, overrides: contextOverrides); + expect(processManager.hasRemainingExpectations, false); + }); - testUsingContext('builds iOS release arm64 AOT snapshot', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - genSnapshot.outputs = { - globals.fs.path.join(outputPath, 'snapshot_assembly.S'): '', - }; - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); + testWithoutContext('builds iOS arm64 snapshot', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + processManager.addCommand(FakeCommand( + command: [ + 'gen_snapshot_arm64', + '--deterministic', + '--snapshot_kind=app-aot-assembly', + '--assembly=${fileSystem.path.join(outputPath, 'snapshot_assembly.S')}', + '--strip', + '--no-causal-async-stacks', + '--lazy-async-stacks', + 'main.dill', + ] + )); + processManager.addCommand(kSdkPathCommand); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'cc', + '-arch', + 'arm64', + '-isysroot', + '', + '-c', + 'build/foo/snapshot_assembly.S', + '-o', + 'build/foo/snapshot_assembly.o', + ] + )); + processManager.addCommand(const FakeCommand( + command: [ + 'xcrun', + 'clang', + '-arch', + 'arm64', + ...kDefaultClang, + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.ios, @@ -691,25 +536,25 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.ios); - expect(genSnapshot.snapshotType.mode, BuildMode.release); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-assembly', - '--assembly=${globals.fs.path.join(outputPath, 'snapshot_assembly.S')}', - '--strip', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); - }, overrides: contextOverrides); + expect(processManager.hasRemainingExpectations, false); + }); - testUsingContext('builds shared library for android-arm', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); + testWithoutContext('builds shared library for android-arm (32bit)', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + processManager.addCommand(const FakeCommand( + command: [ + 'gen_snapshot', + '--deterministic', + '--snapshot_kind=app-aot-elf', + '--elf=build/foo/app.so', + '--strip', + '--no-sim-use-hardfp', + '--no-use-integer-division', + '--no-causal-async-stacks', + '--lazy-async-stacks', + 'main.dill', + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.android_arm, @@ -723,28 +568,28 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.android_arm); - expect(genSnapshot.snapshotType.mode, BuildMode.release); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-elf', - '--elf=build/foo/app.so', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); - }, overrides: contextOverrides); + expect(processManager.hasRemainingExpectations, false); + }); - testUsingContext('builds shared library for android-arm with dwarf stack traces', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - final String debugPath = globals.fs.path.join('foo', 'app.android-arm.symbols'); - globals.fs.directory(outputPath).createSync(recursive: true); + testWithoutContext('builds shared library for android-arm with dwarf stack traces', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + final String debugPath = fileSystem.path.join('foo', 'app.android-arm.symbols'); + processManager.addCommand(FakeCommand( + command: [ + 'gen_snapshot', + '--deterministic', + '--snapshot_kind=app-aot-elf', + '--elf=build/foo/app.so', + '--strip', + '--no-sim-use-hardfp', + '--no-use-integer-division', + '--no-causal-async-stacks', + '--lazy-async-stacks', + '--dwarf-stack-traces', + '--save-debugging-info=$debugPath', + 'main.dill', + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.android_arm, @@ -758,29 +603,26 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.android_arm); - expect(genSnapshot.snapshotType.mode, BuildMode.release); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-elf', - '--elf=build/foo/app.so', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - '--dwarf-stack-traces', - '--save-debugging-info=$debugPath', - 'main.dill', - ]); - }, overrides: contextOverrides); + expect(processManager.hasRemainingExpectations, false); + }); - testUsingContext('builds shared library for android-arm with obfuscate', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); + testWithoutContext('builds shared library for android-arm with obfuscate', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + processManager.addCommand(const FakeCommand( + command: [ + 'gen_snapshot', + '--deterministic', + '--snapshot_kind=app-aot-elf', + '--elf=build/foo/app.so', + '--strip', + '--no-sim-use-hardfp', + '--no-use-integer-division', + '--no-causal-async-stacks', + '--lazy-async-stacks', + '--obfuscate', + 'main.dill', + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.android_arm, @@ -794,28 +636,25 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.android_arm); - expect(genSnapshot.snapshotType.mode, BuildMode.release); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-elf', - '--elf=build/foo/app.so', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - '--obfuscate', - 'main.dill', - ]); - }, overrides: contextOverrides); + expect(processManager.hasRemainingExpectations, false); + }); - testUsingContext('builds shared library for android-arm without dwarf stack traces due to empty string', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); + testWithoutContext('builds shared library for android-arm without dwarf stack traces due to empty string', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + processManager.addCommand(const FakeCommand( + command: [ + 'gen_snapshot', + '--deterministic', + '--snapshot_kind=app-aot-elf', + '--elf=build/foo/app.so', + '--strip', + '--no-sim-use-hardfp', + '--no-use-integer-division', + '--no-causal-async-stacks', + '--lazy-async-stacks', + 'main.dill', + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.android_arm, @@ -829,27 +668,23 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.android_arm); - expect(genSnapshot.snapshotType.mode, BuildMode.release); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-elf', - '--elf=build/foo/app.so', - '--strip', - '--no-sim-use-hardfp', - '--no-use-integer-division', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); - }, overrides: contextOverrides); + expect(processManager.hasRemainingExpectations, false); + }); - testUsingContext('builds shared library for android-arm64', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); + testWithoutContext('builds shared library for android-arm64', () async { + final String outputPath = fileSystem.path.join('build', 'foo'); + processManager.addCommand(const FakeCommand( + command: [ + 'gen_snapshot', + '--deterministic', + '--snapshot_kind=app-aot-elf', + '--elf=build/foo/app.so', + '--strip', + '--no-causal-async-stacks', + '--lazy-async-stacks', + 'main.dill', + ] + )); final int genSnapshotExitCode = await snapshotter.build( platform: TargetPlatform.android_arm64, @@ -863,48 +698,9 @@ void main() { ); expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(genSnapshot.snapshotType.platform, TargetPlatform.android_arm64); - expect(genSnapshot.snapshotType.mode, BuildMode.release); - expect(genSnapshot.additionalArgs, [ - '--deterministic', - '--snapshot_kind=app-aot-elf', - '--elf=build/foo/app.so', - '--strip', - '--no-causal-async-stacks', - '--lazy-async-stacks', - 'main.dill', - ]); - }, overrides: contextOverrides); - - testUsingContext('reports timing', () async { - globals.fs.file('main.dill').writeAsStringSync('binary magic'); - - final String outputPath = globals.fs.path.join('build', 'foo'); - globals.fs.directory(outputPath).createSync(recursive: true); - - genSnapshot.outputs = { - globals.fs.path.join(outputPath, 'app.so'): '', - }; - - final RunResult successResult = RunResult(ProcessResult(1, 0, '', ''), ['command name', 'arguments...']); - when(mockXcode.cc(any)).thenAnswer((_) => Future.value(successResult)); - when(mockXcode.clang(any)).thenAnswer((_) => Future.value(successResult)); - - final int genSnapshotExitCode = await snapshotterWithTimings.build( - platform: TargetPlatform.android_arm, - buildMode: BuildMode.release, - mainPath: 'main.dill', - packagesPath: '.packages', - outputPath: outputPath, - bitcode: false, - splitDebugInfo: null, - dartObfuscation: false, - ); - - expect(genSnapshotExitCode, 0); - expect(genSnapshot.callCount, 1); - expect(testLogger.statusText, matches(RegExp(r'snapshot\(CompileTime\): \d+ ms.'))); - }, overrides: contextOverrides); + expect(processManager.hasRemainingExpectations, false); + }); }); } + +class MockArtifacts extends Mock implements Artifacts {} 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 0cee898d37..e0ebb090fa 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 @@ -5,7 +5,6 @@ import 'package:flutter_tools/src/base/build.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; -import 'package:flutter_tools/src/base/process.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/build_system/targets/dart.dart'; import 'package:flutter_tools/src/build_system/targets/macos.dart'; @@ -49,7 +48,6 @@ void main() { Testbed testbed; Environment environment; MockPlatform mockPlatform; - MockXcode mockXcode; setUpAll(() { Cache.disableLocking(); @@ -57,7 +55,6 @@ void main() { }); setUp(() { - mockXcode = MockXcode(); mockPlatform = MockPlatform(); when(mockPlatform.isWindows).thenReturn(false); when(mockPlatform.isMacOS).thenReturn(true); @@ -193,35 +190,6 @@ void main() { expect(outputFramework.readAsStringSync(), 'DEF'); })); - - test('release/profile macOS compilation uses correct gen_snapshot', () => testbed.run(() async { - when(genSnapshot.run( - snapshotType: anyNamed('snapshotType'), - additionalArgs: anyNamed('additionalArgs'), - darwinArch: anyNamed('darwinArch'), - )).thenAnswer((Invocation invocation) { - environment.buildDir.childFile('snapshot_assembly.o').createSync(); - environment.buildDir.childFile('snapshot_assembly.S').createSync(); - return Future.value(0); - }); - when(mockXcode.cc(any)).thenAnswer((Invocation invocation) { - return Future.value(RunResult(FakeProcessResult()..exitCode = 0, ['test'])); - }); - when(mockXcode.clang(any)).thenAnswer((Invocation invocation) { - return Future.value(RunResult(FakeProcessResult()..exitCode = 0, ['test'])); - }); - environment.buildDir.childFile('app.dill').createSync(recursive: true); - globals.fs.file('.packages') - ..createSync() - ..writeAsStringSync(''' -# Generated -sky_engine:file:///bin/cache/pkg/sky_engine/lib/ -flutter_tools:lib/'''); - await const CompileMacOSFramework().build(environment..defines[kBuildMode] = 'release'); - }, overrides: { - GenSnapshot: () => MockGenSnapshot(), - Xcode: () => mockXcode, - })); } class MockPlatform extends Mock implements Platform {}