Unverified Commit b2d19d2a authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Add support for macOS release/profile mode (3 of 3) (#38909)

parent 055c5489
......@@ -37,6 +37,9 @@ if [[ -n "$FLUTTER_ENGINE" ]]; then
flutter_engine_flag="--local-engine-src-path=${FLUTTER_ENGINE}"
fi
# Set the build mode
build_mode="$(echo "${FLUTTER_BUILD_MODE:-${CONFIGURATION}}" | tr "[:upper:]" "[:lower:]")"
if [[ -n "$LOCAL_ENGINE" ]]; then
if [[ $(echo "$LOCAL_ENGINE" | tr "[:upper:]" "[:lower:]") != *"$build_mode"* ]]; then
EchoError "========================================================================"
......@@ -53,19 +56,12 @@ if [[ -n "$LOCAL_ENGINE" ]]; then
local_engine_flag="--local-engine=${LOCAL_ENGINE}"
fi
# Set the build mode
build_mode="$(echo "${FLUTTER_BUILD_MODE:-${CONFIGURATION}}" | tr "[:upper:]" "[:lower:]")"
# The path where the input/output xcfilelists are stored. These are used by xcode
# to conditionally skip this script phase if neither have changed.
ephemeral_dir="${SOURCE_ROOT}/Flutter/ephemeral"
build_inputs_path="${ephemeral_dir}/FlutterInputs.xcfilelist"
build_outputs_path="${ephemeral_dir}/FlutterOutputs.xcfilelist"
# TODO(jonahwilliams): connect AOT rules once engine artifacts are published.
# The build mode is currently hard-coded to debug only. Since this does not yet
# support AOT, we need to ensure that we compile the kernel file in debug so that
# the VM can load it.
RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \
${verbose_flag} \
${flutter_engine_flag} \
......@@ -73,7 +69,7 @@ RunCommand "${FLUTTER_ROOT}/bin/flutter" --suppress-analytics \
assemble \
-dTargetPlatform=darwin-x64 \
-dTargetFile="${target_path}" \
-dBuildMode=debug \
-dBuildMode="${build_mode}" \
--build-inputs="${build_inputs_path}" \
--build-outputs="${build_outputs_path}" \
debug_bundle_flutter_assets
"${build_mode}_macos_bundle_flutter_assets"
......@@ -160,7 +160,6 @@ class CachedArtifacts extends Artifacts {
@override
String getArtifactPath(Artifact artifact, { TargetPlatform platform, BuildMode mode }) {
platform ??= _currentHostPlatform;
switch (platform) {
case TargetPlatform.android_arm:
case TargetPlatform.android_arm64:
......@@ -170,15 +169,15 @@ class CachedArtifacts extends Artifacts {
case TargetPlatform.ios:
return _getIosArtifactPath(artifact, platform, mode);
case TargetPlatform.darwin_x64:
return _getDarwinArtifactPath(artifact, platform, mode);
case TargetPlatform.linux_x64:
case TargetPlatform.windows_x64:
case TargetPlatform.fuchsia:
case TargetPlatform.windows_x64:
case TargetPlatform.tester:
case TargetPlatform.web_javascript:
return _getHostArtifactPath(artifact, platform, mode);
default: // could be null, but that can't be specified as a case.
return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform, mode);
}
assert(false, 'Invalid platform $platform.');
return null;
}
@override
......@@ -186,6 +185,16 @@ class CachedArtifacts extends Artifacts {
return fs.path.basename(_getEngineArtifactsPath(platform, mode));
}
String _getDarwinArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
// When platform is null, a generic host platform artifact is being requested
// and not the gen_snapshot for darwin as a target platform.
if (platform != null && artifact == Artifact.genSnapshot) {
final String engineDir = _getEngineArtifactsPath(platform, mode);
return fs.path.join(engineDir, _artifactToFileName(artifact));
}
return _getHostArtifactPath(artifact, platform ?? _currentHostPlatform, mode);
}
String _getAndroidArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
final String engineDir = _getEngineArtifactsPath(platform, mode);
switch (artifact) {
......@@ -240,6 +249,7 @@ class CachedArtifacts extends Artifacts {
}
String _getHostArtifactPath(Artifact artifact, TargetPlatform platform, BuildMode mode) {
assert(platform != null);
switch (artifact) {
case Artifact.genSnapshot:
// For script snapshots any gen_snapshot binary will do. Returning gen_snapshot for
......@@ -274,8 +284,14 @@ class CachedArtifacts extends Artifacts {
case Artifact.linuxDesktopPath:
case Artifact.windowsDesktopPath:
case Artifact.flutterMacOSPodspec:
// TODO(jonahwilliams): remove once debug desktop artifacts are uploaded
// under a separate directory from the host artifacts.
// https://github.com/flutter/flutter/issues/38935
String platformDirName = getNameForTargetPlatform(platform);
if (mode == BuildMode.profile || mode == BuildMode.release) {
platformDirName = '$platformDirName-${getNameForBuildMode(mode)}';
}
final String engineArtifactsPath = cache.getArtifactDirectory('engine').path;
final String platformDirName = getNameForTargetPlatform(platform);
return fs.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, platform, mode));
case Artifact.skyEnginePath:
final Directory dartPackageDirectory = cache.getCacheDir('pkg');
......@@ -293,6 +309,14 @@ class CachedArtifacts extends Artifacts {
case TargetPlatform.linux_x64:
case TargetPlatform.darwin_x64:
case TargetPlatform.windows_x64:
// TODO(jonahwilliams): remove once debug desktop artifacts are uploaded
// under a separate directory from the host artifacts.
// https://github.com/flutter/flutter/issues/38935
if (mode == BuildMode.debug || mode == null) {
return fs.path.join(engineDir, platformName);
}
final String suffix = mode != BuildMode.debug ? '-${snakeCase(getModeName(mode), '-')}' : '';
return fs.path.join(engineDir, platformName + suffix);
case TargetPlatform.fuchsia:
case TargetPlatform.tester:
case TargetPlatform.web_javascript:
......
......@@ -194,7 +194,7 @@ class AOTSnapshotter {
final String genSnapshotPath = GenSnapshot.getSnapshotterPath(snapshotType);
outputDir.childFile('gen_snapshot.d').writeAsStringSync('gen_snapshot.d: $genSnapshotPath\n');
// On iOS, we use Xcode to compile the snapshot into a dynamic library that the
// On iOS and macOS, we use Xcode to compile the snapshot into a dynamic library that the
// end-developer can link into their app.
if (platform == TargetPlatform.ios || platform == TargetPlatform.darwin_x64) {
final RunResult result = await _buildFramework(
......
......@@ -103,6 +103,7 @@ class KernelSnapshot extends Target {
outputFilePath: environment.buildDir.childFile('app.dill').path,
depFilePath: null,
packagesPath: packagesPath,
linkPlatformKernelIn: buildMode == BuildMode.release,
mainPath: packageUriMapper.map(targetFile)?.toString() ?? targetFile,
);
if (output.errorCount != 0) {
......
......@@ -4,6 +4,7 @@
import '../../artifacts.dart';
import '../../base/file_system.dart';
import '../../build_info.dart';
import '../../globals.dart';
import '../build_system.dart';
......@@ -17,7 +18,7 @@ class UnpackLinux extends Target {
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/linux.dart'),
Source.artifact(Artifact.linuxDesktopPath),
Source.artifact(Artifact.linuxDesktopPath, mode: BuildMode.debug),
];
@override
......
......@@ -6,6 +6,7 @@ import 'package:pool/pool.dart';
import '../../artifacts.dart';
import '../../asset.dart';
import '../../base/build.dart';
import '../../base/file_system.dart';
import '../../base/io.dart';
import '../../base/process.dart';
......@@ -16,6 +17,7 @@ import '../../globals.dart';
import '../../macos/xcode.dart';
import '../../project.dart';
import '../build_system.dart';
import '../exceptions.dart';
import 'dart.dart';
const String _kOutputPrefix = '{PROJECT_DIR}/macos/Flutter/ephemeral/FlutterMacOS.framework';
......@@ -51,7 +53,7 @@ class MacOSAssetBehavior extends SourceBehavior {
);
final FlutterProject flutterProject = FlutterProject.fromDirectory(environment.projectDir);
final String prefix = fs.path.join(flutterProject.macos.ephemeralDirectory.path,
'App.framework', 'Resources', 'flutter_assets');
'App.framework', 'Versions', 'A', 'Resources', 'flutter_assets');
final List<File> results = <File>[];
for (String key in assetBundle.entries.keys) {
final File file = fs.file(fs.path.join(prefix, key));
......@@ -63,22 +65,28 @@ class MacOSAssetBehavior extends SourceBehavior {
/// Copy the macOS framework to the correct copy dir by invoking 'cp -R'.
///
/// The shelling out is done to avoid complications with preserving special
/// files (e.g., symbolic links) in the framework structure.
/// This class is abstract to share logic between the three conrete
/// implementations. The shelling out is done to avoid complications with
/// preserving special files (e.g., symbolic links) in the framework structure.
///
/// Removes any previous version of the framework that already exists in the
/// target directory.
///
/// The real implementations are:
/// * [DebugUnpackMacOS]
/// * [ProfileUnpackMacOS]
/// * [ReleaseUnpackMacOS]
///
// TODO(jonahwilliams): remove shell out.
class UnpackMacOS extends Target {
// TODO(jonahwilliams): the subtypes are required to specify the different
// input dependencies as a current limitation of the build system planning.
// This should be resolved after https://github.com/flutter/flutter/issues/38937.
abstract class UnpackMacOS extends Target {
const UnpackMacOS();
@override
String get name => 'unpack_macos';
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/macos.dart'),
Source.artifact(Artifact.flutterMacOSFramework),
];
@override
......@@ -108,7 +116,11 @@ class UnpackMacOS extends Target {
@override
Future<void> build(List<File> inputFiles, Environment environment) async {
final String basePath = artifacts.getArtifactPath(Artifact.flutterMacOSFramework);
if (environment.defines[kBuildMode] == null) {
throw MissingDefineException(kBuildMode, 'unpack_macos');
}
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final String basePath = artifacts.getArtifactPath(Artifact.flutterMacOSFramework, mode: buildMode);
final FlutterProject flutterProject = FlutterProject.fromDirectory(environment.projectDir);
final Directory targetDirectory = flutterProject.macos
.ephemeralDirectory
......@@ -128,6 +140,48 @@ class UnpackMacOS extends Target {
}
}
/// Unpack the release prebuilt engine framework.
class ReleaseUnpackMacOS extends UnpackMacOS {
const ReleaseUnpackMacOS();
@override
String get name => 'release_unpack_macos';
@override
List<Source> get inputs => <Source>[
...super.inputs,
const Source.artifact(Artifact.flutterMacOSFramework, mode: BuildMode.release),
];
}
/// Unpack the profile prebuilt engine framework.
class ProfileUnpackMacOS extends UnpackMacOS {
const ProfileUnpackMacOS();
@override
String get name => 'profile_unpack_macos';
@override
List<Source> get inputs => <Source>[
...super.inputs,
const Source.artifact(Artifact.flutterMacOSFramework, mode: BuildMode.profile),
];
}
/// Unpack the debug prebuilt engine framework.
class DebugUnpackMacOS extends UnpackMacOS {
const DebugUnpackMacOS();
@override
String get name => 'debug_unpack_macos';
@override
List<Source> get inputs => <Source>[
...super.inputs,
const Source.artifact(Artifact.flutterMacOSFramework, mode: BuildMode.debug),
];
}
/// Create an App.framework for debug macOS targets.
///
/// This framework needs to exist for the Xcode project to link/bundle,
......@@ -178,18 +232,85 @@ static const int Moo = 88;
];
}
/// Bundle the flutter assets, app.dill, and precompiled runtimes into the App.framework.
class CompileMacOSFramework extends Target {
const CompileMacOSFramework();
@override
String get name => 'compile_macos_framework';
@override
Future<void> build(List<File> inputFiles, Environment environment) async {
if (environment.defines[kBuildMode] == null) {
throw MissingDefineException(kBuildMode, 'compile_macos_framework');
}
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
if (buildMode == BuildMode.debug) {
throw Exception('precompiled macOS framework only supported in release/profile builds.');
}
final FlutterProject flutterProject = FlutterProject.fromDirectory(environment.projectDir);
final int result = await AOTSnapshotter(reportTimings: false).build(
bitcode: false,
buildMode: buildMode,
mainPath: environment.buildDir.childFile('app.dill').path,
outputPath: environment.buildDir.path,
platform: TargetPlatform.darwin_x64,
darwinArch: DarwinArch.x86_64,
packagesPath: flutterProject.packagesFile.path
);
if (result != 0) {
throw Exception('gen shapshot failed.');
}
}
@override
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
];
@override
List<Source> get inputs => const <Source>[
Source.pattern('{BUILD_DIR}/app.dill'),
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/macos.dart'),
Source.artifact(Artifact.genSnapshot, mode: BuildMode.release, platform: TargetPlatform.darwin_x64),
];
@override
List<Source> get outputs => const <Source>[
Source.pattern('{BUILD_DIR}/App.framework/App'),
];
}
/// Bundle the flutter assets into the App.framework.
///
/// In debug mode, also include the app.dill and precompiled runtimes.
///
/// See https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html
/// for more information on Framework structure.
class DebugBundleFlutterAssets extends Target {
const DebugBundleFlutterAssets();
abstract class MacOSBundleFlutterAssets extends Target {
const MacOSBundleFlutterAssets();
@override
String get name => 'debug_bundle_flutter_assets';
List<Source> get inputs => const <Source>[
Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
Source.behavior(MacOSAssetBehavior())
];
@override
List<Source> get outputs => const <Source>[
Source.behavior(MacOSAssetBehavior()),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/App'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/Info.plist'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.json'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/FontManifest.json'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/LICENSE'),
];
@override
Future<void> build(List<File> inputFiles, Environment environment) async {
if (environment.defines[kBuildMode] == null) {
throw MissingDefineException(kBuildMode, 'compile_macos_framework');
}
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final FlutterProject flutterProject = FlutterProject.fromDirectory(environment.projectDir);
final Directory frameworkRootDirectory = flutterProject.macos
.ephemeralDirectory
......@@ -268,78 +389,121 @@ class DebugBundleFlutterAssets extends Target {
</plist>
''');
// Copy dill file.
try {
final File sourceFile = environment.buildDir.childFile('app.dill');
sourceFile.copySync(assetDirectory.childFile('kernel_blob.bin').path);
} catch (err) {
throw Exception('Failed to copy app.dill: $err');
}
// Copy precompiled runtimes.
try {
final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData,
platform: TargetPlatform.darwin_x64, mode: BuildMode.debug);
final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData,
platform: TargetPlatform.darwin_x64, mode: BuildMode.debug);
fs.file(vmSnapshotData).copySync(
assetDirectory.childFile('vm_snapshot_data').path);
fs.file(isolateSnapshotData).copySync(
assetDirectory.childFile('isolate_snapshot_data').path);
} catch (err) {
throw Exception('Failed to copy precompiled runtimes: $err');
if (buildMode == BuildMode.debug) {
// Copy dill file.
try {
final File sourceFile = environment.buildDir.childFile('app.dill');
sourceFile.copySync(assetDirectory.childFile('kernel_blob.bin').path);
} catch (err) {
throw Exception('Failed to copy app.dill: $err');
}
// Copy precompiled runtimes.
try {
final String vmSnapshotData = artifacts.getArtifactPath(Artifact.vmSnapshotData,
platform: TargetPlatform.darwin_x64, mode: BuildMode.debug);
final String isolateSnapshotData = artifacts.getArtifactPath(Artifact.isolateSnapshotData,
platform: TargetPlatform.darwin_x64, mode: BuildMode.debug);
fs.file(vmSnapshotData).copySync(
assetDirectory.childFile('vm_snapshot_data').path);
fs.file(isolateSnapshotData).copySync(
assetDirectory.childFile('isolate_snapshot_data').path);
} catch (err) {
throw Exception('Failed to copy precompiled runtimes: $err');
}
}
// Create symlink to current version.
// Create symlink to current version. These must be relative, from the
// framework root for Resources/App and from the versions root for
// Current.
try {
final Link currentVersion = outputDirectory.parent
.childLink('Current');
if (!currentVersion.existsSync()) {
currentVersion.createSync(outputDirectory.path);
final String linkPath = fs.path.relative(outputDirectory.path,
from: outputDirectory.parent.path);
print(linkPath);
currentVersion.createSync('$linkPath${fs.path.separator}');
}
// Create symlink to current resources.
final Link currentResources = frameworkRootDirectory
.childLink('Resources');
if (!currentResources.existsSync()) {
currentResources.createSync(fs.path.join(currentVersion.path, 'Resources'));
final String linkPath = fs.path.relative(fs.path.join(currentVersion.path, 'Resources'),
from: frameworkRootDirectory.path);
print(linkPath);
currentResources.createSync(linkPath);
}
// Create symlink to current binary.
final Link currentFramework = frameworkRootDirectory
.childLink('App');
if (!currentFramework.existsSync()) {
currentFramework.createSync(fs.path.join(currentVersion.path, 'App'));
final String linkPath = fs.path.relative(fs.path.join(currentVersion.path, 'App'),
from: frameworkRootDirectory.path);
print(linkPath);
currentFramework.createSync(linkPath);
}
} on FileSystemException {
throw Exception('Failed to create symlinks for framework. try removing '
'the "${flutterProject.macos.ephemeralDirectory.path}" directory and rerunning');
}
}
}
/// Bundle the debug flutter assets into the App.framework.
class DebugMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets {
const DebugMacOSBundleFlutterAssets();
@override
String get name => 'debug_macos_bundle_flutter_assets';
@override
List<Target> get dependencies => const <Target>[
KernelSnapshot(),
DebugMacOSFramework(),
UnpackMacOS(),
DebugUnpackMacOS(),
];
@override
List<Source> get inputs => const <Source>[
Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
Source.behavior(MacOSAssetBehavior()),
Source.pattern('{BUILD_DIR}/app.dill'),
Source.artifact(Artifact.isolateSnapshotData, platform: TargetPlatform.darwin_x64, mode: BuildMode.debug),
Source.artifact(Artifact.vmSnapshotData, platform: TargetPlatform.darwin_x64, mode: BuildMode.debug),
List<Source> get inputs => <Source>[
...super.inputs,
const Source.pattern('{BUILD_DIR}/app.dill'),
const Source.artifact(Artifact.isolateSnapshotData, platform: TargetPlatform.darwin_x64, mode: BuildMode.debug),
const Source.artifact(Artifact.vmSnapshotData, platform: TargetPlatform.darwin_x64, mode: BuildMode.debug),
];
@override
List<Source> get outputs => const <Source>[
Source.behavior(MacOSAssetBehavior()),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/App'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/Info.plist'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/AssetManifest.json'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/FontManifest.json'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/LICENSE'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data'),
Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data'),
List<Source> get outputs => <Source>[
...super.outputs,
const Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/kernel_blob.bin'),
const Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/vm_snapshot_data'),
const Source.pattern('{PROJECT_DIR}/macos/Flutter/ephemeral/App.framework/Versions/A/Resources/flutter_assets/isolate_snapshot_data'),
];
}
/// Bundle the profile flutter assets into the App.framework.
class ProfileMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets {
const ProfileMacOSBundleFlutterAssets();
@override
String get name => 'profile_macos_bundle_flutter_assets';
@override
List<Target> get dependencies => const <Target>[
CompileMacOSFramework(),
ProfileUnpackMacOS(),
];
}
/// Bundle the release flutter assets into the App.framework.
class ReleaseMacOSBundleFlutterAssets extends MacOSBundleFlutterAssets {
const ReleaseMacOSBundleFlutterAssets();
@override
String get name => 'release_macos_bundle_flutter_assets';
@override
List<Target> get dependencies => const <Target>[
CompileMacOSFramework(),
ReleaseUnpackMacOS(),
];
}
......@@ -4,6 +4,7 @@
import '../../artifacts.dart';
import '../../base/file_system.dart';
import '../../build_info.dart';
import '../../globals.dart';
import '../build_system.dart';
......@@ -17,7 +18,7 @@ class UnpackWindows extends Target {
@override
List<Source> get inputs => const <Source>[
Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/windows.dart'),
Source.artifact(Artifact.windowsDesktopPath),
Source.artifact(Artifact.windowsDesktopPath, mode: BuildMode.debug),
];
@override
......
......@@ -1061,8 +1061,15 @@ const List<List<String>> _linuxDesktopBinaryDirs = <List<String>>[
<String>['linux-x64', 'linux-x64/flutter-cpp-client-wrapper-glfw.zip'],
];
// TODO(jonahwilliams): upload debug desktop artifacts to host-debug and
// remove from existing host folder.
// https://github.com/flutter/flutter/issues/38935
const List<List<String>> _macOSDesktopBinaryDirs = <List<String>>[
<String>['darwin-x64', 'darwin-x64/FlutterMacOS.framework.zip'],
<String>['darwin-x64-profile', 'darwin-x64-profile/FlutterMacOS.framework.zip'],
<String>['darwin-x64-profile', 'darwin-x64-profile/artifacts.zip'],
<String>['darwin-x64-release', 'darwin-x64-release/FlutterMacOS.framework.zip'],
<String>['darwin-x64-release', 'darwin-x64-release/artifacts.zip'],
];
const List<List<String>> _osxBinaryDirs = <List<String>>[
......
......@@ -23,7 +23,6 @@ BuildSystem get buildSystem => context.get<BuildSystem>();
/// All currently implemented targets.
const List<Target> _kDefaultTargets = <Target>[
UnpackMacOS(),
UnpackLinux(),
UnpackWindows(),
CopyAssets(),
......@@ -33,7 +32,9 @@ const List<Target> _kDefaultTargets = <Target>[
AotAssemblyProfile(),
AotAssemblyRelease(),
DebugMacOSFramework(),
DebugBundleFlutterAssets(),
DebugMacOSBundleFlutterAssets(),
ProfileMacOSBundleFlutterAssets(),
ReleaseMacOSBundleFlutterAssets(),
];
/// Assemble provides a low level API to interact with the flutter tool build
......
......@@ -6,6 +6,7 @@ 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/platform.dart';
import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/process_manager.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/targets/dart.dart';
......@@ -61,6 +62,11 @@ void main() {
when(mockPlatform.isLinux).thenReturn(false);
when(mockPlatform.environment).thenReturn(const <String, String>{});
testbed = Testbed(setup: () {
fs.file(fs.path.join('bin', 'cache', 'pkg', 'sky_engine', 'lib', 'ui',
'ui.dart')).createSync(recursive: true);
fs.file(fs.path.join('bin', 'cache', 'pkg', 'sky_engine', 'sdk_ext',
'vmservice_io.dart')).createSync(recursive: true);
environment = Environment(
projectDir: fs.currentDirectory,
defines: <String, String>{
......@@ -95,7 +101,7 @@ void main() {
}
return FakeProcessResult()..exitCode = 0;
});
await const UnpackMacOS().build(<File>[], environment);
await const DebugUnpackMacOS().build(<File>[], environment);
expect(fs.directory('$_kOutputPrefix').existsSync(), true);
for (File file in inputs) {
......@@ -109,11 +115,11 @@ void main() {
..createSync(recursive: true)
..writeAsStringSync('testing');
expect(() async => await const DebugBundleFlutterAssets().build(<File>[], environment),
expect(() async => await const DebugMacOSBundleFlutterAssets().build(<File>[], environment),
throwsA(isInstanceOf<Exception>()));
}));
test('debug macOS application copies kernel blob', () => testbed.run(() async {
test('debug macOS application creates correctly structured framework', () => testbed.run(() async {
fs.file(fs.path.join('bin', 'cache', 'artifacts', 'engine', 'darwin-x64',
'vm_isolate_snapshot.bin')).createSync(recursive: true);
fs.file(fs.path.join('bin', 'cache', 'artifacts', 'engine', 'darwin-x64',
......@@ -124,18 +130,74 @@ void main() {
'macos', 'Flutter', 'ephemeral', 'App.framework');
final String inputKernel = fs.path.join(environment.buildDir.path, 'app.dill');
fs.directory(frameworkPath).createSync(recursive: true);
final String outputKernel = fs.path.join(frameworkPath, 'Resources',
final String outputKernel = fs.path.join(frameworkPath, 'Versions', 'A', 'Resources',
'flutter_assets', 'kernel_blob.bin');
final String outputPlist = fs.path.join(frameworkPath, 'Resources', 'Info.plist');
final String outputPlist = fs.path.join(frameworkPath, 'Versions', 'A', 'Resources',
'Info.plist');
fs.file(inputKernel)
..createSync(recursive: true)
..writeAsStringSync('testing');
await const DebugBundleFlutterAssets().build(<File>[], environment);
await const DebugMacOSBundleFlutterAssets().build(<File>[], environment);
expect(fs.file(outputKernel).readAsStringSync(), 'testing');
expect(fs.file(outputPlist).readAsStringSync(), contains('io.flutter.flutter.app'));
}));
test('release/profile macOS application has no blob or precompiled runtime', () => testbed.run(() async {
fs.file(fs.path.join('bin', 'cache', 'artifacts', 'engine', 'darwin-x64',
'vm_isolate_snapshot.bin')).createSync(recursive: true);
fs.file(fs.path.join('bin', 'cache', 'artifacts', 'engine', 'darwin-x64',
'isolate_snapshot.bin')).createSync(recursive: true);
fs.file(fs.path.join(environment.buildDir.path, 'App.framework', 'App'))
..createSync(recursive: true);
final String frameworkPath = fs.path.join(environment.projectDir.path,
'macos', 'Flutter', 'ephemeral', 'App.framework');
fs.directory(frameworkPath).createSync(recursive: true);
final String outputKernel = fs.path.join(frameworkPath, 'Resources',
'flutter_assets', 'kernel_blob.bin');
final String precompiledVm = fs.path.join(frameworkPath, 'Resources',
'flutter_assets', 'vm_snapshot_data');
final String precompiledIsolate = fs.path.join(frameworkPath, 'Resources',
'flutter_assets', 'isolate_snapshot_data');
await const ProfileMacOSBundleFlutterAssets().build(<File>[], environment..defines[kBuildMode] = 'profile');
expect(fs.file(outputKernel).existsSync(), false);
expect(fs.file(precompiledVm).existsSync(), false);
expect(fs.file(precompiledIsolate).existsSync(), false);
}));
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<int>.value(0);
});
when(xcode.cc(any)).thenAnswer((Invocation invocation) {
return Future<RunResult>.value(RunResult(FakeProcessResult()..exitCode = 0, <String>['test']));
});
when(xcode.clang(any)).thenAnswer((Invocation invocation) {
return Future<RunResult>.value(RunResult(FakeProcessResult()..exitCode = 0, <String>['test']));
});
when(xcode.dsymutil(any)).thenAnswer((Invocation invocation) {
return Future<RunResult>.value(RunResult(FakeProcessResult()..exitCode = 0, <String>['test']));
});
environment.buildDir.childFile('app.dill').createSync(recursive: true);
fs.file('.packages')
..createSync()
..writeAsStringSync('''
# Generated
sky_engine:file:///bin/cache/pkg/sky_engine/lib/
flutter_tools:lib/''');
await const CompileMacOSFramework().build(<File>[], environment..defines[kBuildMode] = 'release');
}, overrides: <Type, Generator>{
GenSnapshot: () => MockGenSnapshot(),
Xcode: () => MockXCode(),
}));
}
class MockPlatform extends Mock implements Platform {}
......
......@@ -36,7 +36,7 @@ void main() {
return BuildResult(success: true);
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
await commandRunner.run(<String>['assemble', 'unpack_macos']);
await commandRunner.run(<String>['assemble', 'debug_macos_bundle_flutter_assets']);
final BufferLogger bufferLogger = logger;
expect(bufferLogger.statusText.trim(), 'build succeeded.');
......@@ -62,7 +62,7 @@ void main() {
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
await commandRunner.run(<String>['assemble', '--build-outputs=outputs', '--build-inputs=inputs', 'unpack_macos']);
await commandRunner.run(<String>['assemble', '--build-outputs=outputs', '--build-inputs=inputs', 'debug_macos_bundle_flutter_assets']);
final File inputs = fs.file('inputs');
final File outputs = fs.file('outputs');
......@@ -72,7 +72,7 @@ void main() {
final DateTime theDistantPast = DateTime(1991, 8, 23);
inputs.setLastModifiedSync(theDistantPast);
outputs.setLastModifiedSync(theDistantPast);
await commandRunner.run(<String>['assemble', '--build-outputs=outputs', '--build-inputs=inputs', 'unpack_macos']);
await commandRunner.run(<String>['assemble', '--build-outputs=outputs', '--build-inputs=inputs', 'debug_macos_bundle_flutter_assets']);
expect(inputs.lastModifiedSync(), theDistantPast);
expect(outputs.lastModifiedSync(), theDistantPast);
......@@ -85,7 +85,7 @@ void main() {
inputFiles: <File>[fs.file('foo'), fs.file('fizz')..createSync()],
outputFiles: <File>[fs.file('bar'), fs.file(fs.path.join('.dart_tool', 'fizz2'))..createSync(recursive: true)]);
});
await commandRunner.run(<String>['assemble', '--build-outputs=outputs', '--build-inputs=inputs', 'unpack_macos']);
await commandRunner.run(<String>['assemble', '--build-outputs=outputs', '--build-inputs=inputs', 'debug_macos_bundle_flutter_assets']);
expect(inputs.readAsStringSync(), contains('foo'));
expect(inputs.readAsStringSync(), contains('fizz'));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment