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
......
......@@ -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