ios.dart 5.24 KB
Newer Older
1 2 3 4
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5 6 7 8 9 10
import '../../artifacts.dart';
import '../../base/build.dart';
import '../../base/file_system.dart';
import '../../base/io.dart';
import '../../base/process_manager.dart';
import '../../build_info.dart';
11
import '../build_system.dart';
12
import '../exceptions.dart';
13 14
import 'dart.dart';

15 16 17 18 19 20 21 22
/// Supports compiling a dart kernel file to an assembly file.
///
/// If more than one iOS arch is provided, then this rule will
/// produce a univeral binary.
abstract class AotAssemblyBase extends Target {
  const AotAssemblyBase();

  @override
23
  Future<void> build(List<File> inputFiles, Environment environment) async {
24 25 26 27 28 29 30 31 32 33 34
    final AOTSnapshotter snapshotter = AOTSnapshotter(reportTimings: false);
    final String outputPath = environment.buildDir.path;
    if (environment.defines[kBuildMode] == null) {
      throw MissingDefineException(kBuildMode, 'aot_assembly');
    }
    if (environment.defines[kTargetPlatform] == null) {
      throw MissingDefineException(kTargetPlatform, 'aot_assembly');
    }
    final bool bitcode = environment.defines[kBitcodeFlag] == 'true';
    final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
    final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
35 36
    final List<DarwinArch> iosArchs = environment.defines[kIosArchs]?.split(',')?.map(getIOSArchForName)?.toList()
        ?? <DarwinArch>[DarwinArch.arm64];
37 38 39 40 41 42 43 44 45 46 47 48
    if (targetPlatform != TargetPlatform.ios) {
      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(
        platform: targetPlatform,
        buildMode: buildMode,
        mainPath: environment.buildDir.childFile('app.dill').path,
        packagesPath: environment.projectDir.childFile('.packages').path,
        outputPath: outputPath,
49
        darwinArch: iosArchs.single,
50 51 52 53 54 55 56 57 58
        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<Future<int>> pending = <Future<int>>[];
59
      for (DarwinArch iosArch in iosArchs) {
60 61 62 63 64
        pending.add(snapshotter.build(
          platform: targetPlatform,
          buildMode: buildMode,
          mainPath: environment.buildDir.childFile('app.dill').path,
          packagesPath: environment.projectDir.childFile('.packages').path,
65 66
          outputPath: fs.path.join(outputPath, getNameForDarwinArch(iosArch)),
          darwinArch: iosArch,
67 68 69 70 71 72 73 74 75
          bitcode: bitcode,
        ));
      }
      final List<int> 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 processManager.run(<String>[
        'lipo',
76 77
        ...iosArchs.map((DarwinArch iosArch) =>
            fs.path.join(outputPath, getNameForDarwinArch(iosArch), 'App.framework', 'App')),
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
        '-create',
        '-output',
        fs.path.join(outputPath, 'App.framework', 'App'),
      ]);
      if (result.exitCode != 0) {
        throw Exception('lipo exited with code ${result.exitCode}');
      }
    }
  }
}

/// Generate an assembly target from a dart kernel file in release mode.
class AotAssemblyRelease extends AotAssemblyBase {
  const AotAssemblyRelease();

  @override
  String get name => 'aot_assembly_release';

  @override
  List<Source> get inputs => const <Source>[
    Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart'),
    Source.pattern('{BUILD_DIR}/app.dill'),
    Source.pattern('{PROJECT_DIR}/.packages'),
    Source.artifact(Artifact.engineDartBinary),
    Source.artifact(Artifact.skyEnginePath),
    Source.artifact(Artifact.genSnapshot,
      platform: TargetPlatform.ios,
      mode: BuildMode.release,
    ),
  ];

  @override
  List<Source> get outputs => const <Source>[
    Source.pattern('{BUILD_DIR}/App.framework/App'),
  ];

  @override
  List<Target> get dependencies => const <Target>[
    KernelSnapshot(),
  ];
}


/// Generate an assembly target from a dart kernel file in profile mode.
class AotAssemblyProfile extends AotAssemblyBase {
  const AotAssemblyProfile();

  @override
  String get name => 'aot_assembly_profile';

  @override
  List<Source> get inputs => const <Source>[
    Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/ios.dart'),
    Source.pattern('{BUILD_DIR}/app.dill'),
    Source.pattern('{PROJECT_DIR}/.packages'),
    Source.artifact(Artifact.engineDartBinary),
    Source.artifact(Artifact.skyEnginePath),
    Source.artifact(Artifact.genSnapshot,
      platform: TargetPlatform.ios,
      mode: BuildMode.profile,
    ),
  ];

  @override
  List<Source> get outputs => const <Source>[
    Source.pattern('{BUILD_DIR}/App.framework/App'),
  ];

  @override
  List<Target> get dependencies => const <Target>[
    KernelSnapshot(),
  ];
}