mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

Speeds up the native assets target in the backend by 1. changing other targets `gen_dart_plugin_registrant` and `release_unpack_ios` to do async I/O, 2. not reparsing the package config, and 3. not calling `dart pub deps --json` for 0 or 1 packages (fixed package:native_assets_builder). * https://github.com/flutter/flutter/issues/134427 ``` [ +2 ms] native_assets: Starting due to {} [ +2 ms] Skipping target: gen_localizations [ +1 ms] gen_dart_plugin_registrant: Starting due to {InvalidatedReasonKind.inputChanged: The following inputs have updated contents: /Users/dacoharkes/flt/engine/flutter/examples/hello_world/.dart_tool/package_config_subset} [ +33 ms] gen_dart_plugin_registrant: Complete [ +107 ms] release_unpack_ios: Complete [ +60 ms] Writing native_assets.yaml. [ +7 ms] Writing /Users/dacoharkes/flt/engine/flutter/examples/hello_world/.dart_tool/flutter_build/be2692bbfbc0b9a27fcd2422d52354c6/native_assets.yaml done. [ ] native_assets: Complete ``` -> ``` [ +4 ms] native_assets: Starting due to {} [ ] Skipping target: gen_localizations [ +1 ms] gen_dart_plugin_registrant: Starting due to {InvalidatedReasonKind.inputChanged: The following inputs have updated contents: /Users/dacoharkes/flt/engine/flutter/examples/hello_world/.dart_tool/package_config_subset} [ +31 ms] Writing native_assets.yaml. [ +8 ms] Writing /Users/dacoharkes/flt/engine/flutter/examples/hello_world/.dart_tool/flutter_build/f9451a65a465bfab70d004e21d6cc1d6/native_assets.yaml done. [ +1 ms] native_assets: Complete ``` ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
402 lines
14 KiB
Dart
402 lines
14 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'package:file/file.dart';
|
|
import 'package:file/memory.dart';
|
|
import 'package:flutter_tools/src/artifacts.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/logger.dart';
|
|
import 'package:flutter_tools/src/base/platform.dart';
|
|
import 'package:flutter_tools/src/build_info.dart';
|
|
import 'package:flutter_tools/src/build_system/build_system.dart';
|
|
import 'package:flutter_tools/src/dart/package_map.dart';
|
|
import 'package:flutter_tools/src/features.dart';
|
|
import 'package:flutter_tools/src/globals.dart' as globals;
|
|
import 'package:flutter_tools/src/macos/native_assets.dart';
|
|
import 'package:flutter_tools/src/native_assets.dart';
|
|
import 'package:native_assets_cli/native_assets_cli.dart' hide BuildMode, Target;
|
|
import 'package:native_assets_cli/native_assets_cli.dart' as native_assets_cli;
|
|
import 'package:package_config/package_config_types.dart';
|
|
|
|
import '../../src/common.dart';
|
|
import '../../src/context.dart';
|
|
import '../../src/fakes.dart';
|
|
import '../fake_native_assets_build_runner.dart';
|
|
|
|
void main() {
|
|
late FakeProcessManager processManager;
|
|
late Environment environment;
|
|
late Artifacts artifacts;
|
|
late FileSystem fileSystem;
|
|
late BufferLogger logger;
|
|
late Uri projectUri;
|
|
|
|
setUp(() {
|
|
processManager = FakeProcessManager.empty();
|
|
logger = BufferLogger.test();
|
|
artifacts = Artifacts.test();
|
|
fileSystem = MemoryFileSystem.test();
|
|
environment = Environment.test(
|
|
fileSystem.currentDirectory,
|
|
inputs: <String, String>{},
|
|
artifacts: artifacts,
|
|
processManager: processManager,
|
|
fileSystem: fileSystem,
|
|
logger: logger,
|
|
);
|
|
environment.buildDir.createSync(recursive: true);
|
|
projectUri = environment.projectDir.uri;
|
|
});
|
|
|
|
testUsingContext('dry run with no package config', overrides: <Type, Generator>{
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
}, () async {
|
|
expect(
|
|
await dryRunNativeAssetsMacOS(
|
|
projectUri: projectUri,
|
|
fileSystem: fileSystem,
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
hasPackageConfigResult: false,
|
|
),
|
|
),
|
|
null,
|
|
);
|
|
expect(
|
|
(globals.logger as BufferLogger).traceText,
|
|
contains('No package config found. Skipping native assets compilation.'),
|
|
);
|
|
});
|
|
|
|
testUsingContext('build with no package config', overrides: <Type, Generator>{
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
}, () async {
|
|
await buildNativeAssetsMacOS(
|
|
darwinArchs: <DarwinArch>[DarwinArch.arm64],
|
|
projectUri: projectUri,
|
|
buildMode: BuildMode.debug,
|
|
fileSystem: fileSystem,
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
hasPackageConfigResult: false,
|
|
),
|
|
);
|
|
expect(
|
|
(globals.logger as BufferLogger).traceText,
|
|
contains('No package config found. Skipping native assets compilation.'),
|
|
);
|
|
});
|
|
|
|
testUsingContext('dry run for multiple OSes with no package config', overrides: <Type, Generator>{
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
}, () async {
|
|
await dryRunNativeAssetsMultipeOSes(
|
|
projectUri: projectUri,
|
|
fileSystem: fileSystem,
|
|
targetPlatforms: <TargetPlatform>[
|
|
TargetPlatform.darwin,
|
|
TargetPlatform.ios,
|
|
],
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
hasPackageConfigResult: false,
|
|
),
|
|
);
|
|
expect(
|
|
(globals.logger as BufferLogger).traceText,
|
|
contains('No package config found. Skipping native assets compilation.'),
|
|
);
|
|
});
|
|
|
|
testUsingContext('dry run with assets but not enabled', overrides: <Type, Generator>{
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
}, () async {
|
|
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
|
|
await packageConfig.parent.create();
|
|
await packageConfig.create();
|
|
expect(
|
|
() => dryRunNativeAssetsMacOS(
|
|
projectUri: projectUri,
|
|
fileSystem: fileSystem,
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
packagesWithNativeAssetsResult: <Package>[
|
|
Package('bar', projectUri),
|
|
],
|
|
),
|
|
),
|
|
throwsToolExit(
|
|
message: 'Package(s) bar require the native assets feature to be enabled. '
|
|
'Enable using `flutter config --enable-native-assets`.',
|
|
),
|
|
);
|
|
});
|
|
|
|
testUsingContext('dry run with assets', overrides: <Type, Generator>{
|
|
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
}, () async {
|
|
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
|
|
await packageConfig.parent.create();
|
|
await packageConfig.create();
|
|
final Uri? nativeAssetsYaml = await dryRunNativeAssetsMacOS(
|
|
projectUri: projectUri,
|
|
fileSystem: fileSystem,
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
packagesWithNativeAssetsResult: <Package>[
|
|
Package('bar', projectUri),
|
|
],
|
|
dryRunResult: FakeNativeAssetsBuilderResult(
|
|
assets: <Asset>[
|
|
Asset(
|
|
id: 'package:bar/bar.dart',
|
|
linkMode: LinkMode.dynamic,
|
|
target: native_assets_cli.Target.macOSArm64,
|
|
path: AssetAbsolutePath(Uri.file('bar.dylib')),
|
|
),
|
|
Asset(
|
|
id: 'package:bar/bar.dart',
|
|
linkMode: LinkMode.dynamic,
|
|
target: native_assets_cli.Target.macOSX64,
|
|
path: AssetAbsolutePath(Uri.file('bar.dylib')),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
expect(
|
|
nativeAssetsYaml,
|
|
projectUri.resolve('build/native_assets/macos/native_assets.yaml'),
|
|
);
|
|
expect(
|
|
await fileSystem.file(nativeAssetsYaml).readAsString(),
|
|
contains('package:bar/bar.dart'),
|
|
);
|
|
});
|
|
|
|
testUsingContext('build with assets but not enabled', overrides: <Type, Generator>{
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
}, () async {
|
|
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
|
|
await packageConfig.parent.create();
|
|
await packageConfig.create();
|
|
expect(
|
|
() => buildNativeAssetsMacOS(
|
|
darwinArchs: <DarwinArch>[DarwinArch.arm64],
|
|
projectUri: projectUri,
|
|
buildMode: BuildMode.debug,
|
|
fileSystem: fileSystem,
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
packagesWithNativeAssetsResult: <Package>[
|
|
Package('bar', projectUri),
|
|
],
|
|
),
|
|
),
|
|
throwsToolExit(
|
|
message: 'Package(s) bar require the native assets feature to be enabled. '
|
|
'Enable using `flutter config --enable-native-assets`.',
|
|
),
|
|
);
|
|
});
|
|
|
|
testUsingContext('build no assets', overrides: <Type, Generator>{
|
|
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
}, () async {
|
|
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
|
|
await packageConfig.parent.create();
|
|
await packageConfig.create();
|
|
final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsMacOS(
|
|
darwinArchs: <DarwinArch>[DarwinArch.arm64],
|
|
projectUri: projectUri,
|
|
buildMode: BuildMode.debug,
|
|
fileSystem: fileSystem,
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
packagesWithNativeAssetsResult: <Package>[
|
|
Package('bar', projectUri),
|
|
],
|
|
),
|
|
);
|
|
expect(
|
|
nativeAssetsYaml,
|
|
projectUri.resolve('build/native_assets/macos/native_assets.yaml'),
|
|
);
|
|
expect(
|
|
await fileSystem.file(nativeAssetsYaml).readAsString(),
|
|
isNot(contains('package:bar/bar.dart')),
|
|
);
|
|
});
|
|
|
|
for (final bool flutterTester in <bool>[false, true]) {
|
|
String testName = '';
|
|
if (flutterTester) {
|
|
testName += ' flutter tester';
|
|
}
|
|
testUsingContext('build with assets$testName', overrides: <Type, Generator>{
|
|
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
|
|
ProcessManager: () => FakeProcessManager.list(
|
|
<FakeCommand>[
|
|
const FakeCommand(
|
|
command: <Pattern>[
|
|
'lipo',
|
|
'-create',
|
|
'-output',
|
|
'/build/native_assets/macos/bar.dylib',
|
|
'bar.dylib',
|
|
],
|
|
),
|
|
const FakeCommand(
|
|
command: <Pattern>[
|
|
'install_name_tool',
|
|
'-id',
|
|
'@executable_path/Frameworks/bar.dylib',
|
|
'/build/native_assets/macos/bar.dylib',
|
|
],
|
|
),
|
|
const FakeCommand(
|
|
command: <Pattern>[
|
|
'codesign',
|
|
'--force',
|
|
'--sign',
|
|
'-',
|
|
'--timestamp=none',
|
|
'/build/native_assets/macos/bar.dylib',
|
|
],
|
|
),
|
|
],
|
|
),
|
|
}, () async {
|
|
if (const LocalPlatform().isWindows) {
|
|
return; // Backslashes in commands, but we will never run these commands on Windows.
|
|
}
|
|
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
|
|
await packageConfig.parent.create();
|
|
await packageConfig.create();
|
|
final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsMacOS(
|
|
darwinArchs: <DarwinArch>[DarwinArch.arm64],
|
|
projectUri: projectUri,
|
|
buildMode: BuildMode.debug,
|
|
fileSystem: fileSystem,
|
|
flutterTester: flutterTester,
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
packagesWithNativeAssetsResult: <Package>[
|
|
Package('bar', projectUri),
|
|
],
|
|
buildResult: FakeNativeAssetsBuilderResult(
|
|
assets: <Asset>[
|
|
Asset(
|
|
id: 'package:bar/bar.dart',
|
|
linkMode: LinkMode.dynamic,
|
|
target: native_assets_cli.Target.macOSArm64,
|
|
path: AssetAbsolutePath(Uri.file('bar.dylib')),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
expect(
|
|
nativeAssetsYaml,
|
|
projectUri.resolve('build/native_assets/macos/native_assets.yaml'),
|
|
);
|
|
expect(
|
|
await fileSystem.file(nativeAssetsYaml).readAsString(),
|
|
stringContainsInOrder(<String>[
|
|
'package:bar/bar.dart',
|
|
if (flutterTester)
|
|
// Tests run on host system, so the have the full path on the system.
|
|
'- ${projectUri.resolve('/build/native_assets/macos/bar.dylib').toFilePath()}'
|
|
else
|
|
// Apps are a bundle with the dylibs on their dlopen path.
|
|
'- bar.dylib',
|
|
]),
|
|
);
|
|
});
|
|
}
|
|
|
|
testUsingContext('static libs not supported', overrides: <Type, Generator>{
|
|
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
|
|
ProcessManager: () => FakeProcessManager.empty(),
|
|
}, () async {
|
|
final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json');
|
|
await packageConfig.parent.create();
|
|
await packageConfig.create();
|
|
expect(
|
|
() => dryRunNativeAssetsMacOS(
|
|
projectUri: projectUri,
|
|
fileSystem: fileSystem,
|
|
buildRunner: FakeNativeAssetsBuildRunner(
|
|
packagesWithNativeAssetsResult: <Package>[
|
|
Package('bar', projectUri),
|
|
],
|
|
dryRunResult: FakeNativeAssetsBuilderResult(
|
|
assets: <Asset>[
|
|
Asset(
|
|
id: 'package:bar/bar.dart',
|
|
linkMode: LinkMode.static,
|
|
target: native_assets_cli.Target.macOSArm64,
|
|
path: AssetAbsolutePath(Uri.file('bar.a')),
|
|
),
|
|
Asset(
|
|
id: 'package:bar/bar.dart',
|
|
linkMode: LinkMode.static,
|
|
target: native_assets_cli.Target.macOSX64,
|
|
path: AssetAbsolutePath(Uri.file('bar.a')),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
throwsToolExit(
|
|
message: 'Native asset(s) package:bar/bar.dart have their link mode set to '
|
|
'static, but this is not yet supported. '
|
|
'For more info see https://github.com/dart-lang/sdk/issues/49418.',
|
|
),
|
|
);
|
|
});
|
|
|
|
// This logic is mocked in the other tests to avoid having test order
|
|
// randomization causing issues with what processes are invoked.
|
|
// Exercise the parsing of the process output in this separate test.
|
|
testUsingContext('NativeAssetsBuildRunnerImpl.cCompilerConfig', overrides: <Type, Generator>{
|
|
FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true),
|
|
ProcessManager: () => FakeProcessManager.list(
|
|
<FakeCommand>[
|
|
const FakeCommand(
|
|
command: <Pattern>['xcrun', 'clang', '--version'],
|
|
stdout: '''
|
|
Apple clang version 14.0.0 (clang-1400.0.29.202)
|
|
Target: arm64-apple-darwin22.6.0
|
|
Thread model: posix
|
|
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin''',
|
|
)
|
|
],
|
|
),
|
|
}, () async {
|
|
if (!const LocalPlatform().isMacOS) {
|
|
// TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757
|
|
return;
|
|
}
|
|
|
|
final File packagesFile = fileSystem
|
|
.directory(projectUri)
|
|
.childDirectory('.dart_tool')
|
|
.childFile('package_config.json');
|
|
await packagesFile.parent.create();
|
|
await packagesFile.create();
|
|
final PackageConfig packageConfig = await loadPackageConfigWithLogging(
|
|
packagesFile,
|
|
logger: environment.logger,
|
|
);
|
|
final NativeAssetsBuildRunner runner = NativeAssetsBuildRunnerImpl(
|
|
projectUri,
|
|
packageConfig,
|
|
fileSystem,
|
|
logger,
|
|
);
|
|
final CCompilerConfig result = await runner.cCompilerConfig;
|
|
expect(
|
|
result.cc,
|
|
Uri.file(
|
|
'/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang',
|
|
),
|
|
);
|
|
});
|
|
}
|