diff --git a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart index fae9b56cf59..12efadc5dbf 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/native_assets.dart @@ -3,22 +3,14 @@ // found in the LICENSE file. import 'package:meta/meta.dart'; -import 'package:native_assets_builder/native_assets_builder.dart' hide NativeAssetsBuildRunner; +import 'package:native_assets_builder/native_assets_builder.dart'; import 'package:package_config/package_config_types.dart'; -import '../../android/gradle_utils.dart'; import '../../base/common.dart'; import '../../base/file_system.dart'; -import '../../base/platform.dart'; import '../../build_info.dart'; import '../../dart/package_map.dart'; -import '../../isolated/native_assets/android/native_assets.dart'; -import '../../isolated/native_assets/ios/native_assets.dart'; -import '../../isolated/native_assets/linux/native_assets.dart'; -import '../../isolated/native_assets/macos/native_assets.dart'; import '../../isolated/native_assets/native_assets.dart'; -import '../../isolated/native_assets/windows/native_assets.dart'; -import '../../macos/xcode.dart'; import '../build_system.dart'; import '../depfile.dart'; import '../exceptions.dart'; @@ -43,20 +35,21 @@ import 'common.dart'; /// rebuild. class NativeAssets extends Target { const NativeAssets({ - @visibleForTesting NativeAssetsBuildRunner? buildRunner, + @visibleForTesting FlutterNativeAssetsBuildRunner? buildRunner, }) : _buildRunner = buildRunner; - final NativeAssetsBuildRunner? _buildRunner; + final FlutterNativeAssetsBuildRunner? _buildRunner; @override Future build(Environment environment) async { final String? nativeAssetsEnvironment = environment.defines[kNativeAssets]; - final List dependencies; final FileSystem fileSystem = environment.fileSystem; - final File nativeAssetsFile = environment.buildDir.childFile('native_assets.yaml'); + final Uri nativeAssetsFileUri = environment.buildDir.childFile('native_assets.yaml').uri; + + final DartBuildResult result; if (nativeAssetsEnvironment == 'false') { - dependencies = []; - await writeNativeAssetsYaml(KernelAssets(), environment.buildDir.uri, fileSystem); + result = const DartBuildResult.empty(); + await writeNativeAssetsYaml(KernelAssets(), nativeAssetsFileUri, fileSystem); } else { final String? targetPlatformEnvironment = environment.defines[kTargetPlatform]; if (targetPlatformEnvironment == null) { @@ -69,8 +62,8 @@ class NativeAssets extends Target { fileSystem.file(environment.packageConfigPath), logger: environment.logger, ); - final NativeAssetsBuildRunner buildRunner = _buildRunner ?? - NativeAssetsBuildRunnerImpl( + final FlutterNativeAssetsBuildRunner buildRunner = _buildRunner ?? + FlutterNativeAssetsBuildRunnerImpl( projectUri, environment.packageConfigPath, packageConfig, @@ -78,102 +71,22 @@ class NativeAssets extends Target { environment.logger, ); - switch (targetPlatform) { - case TargetPlatform.ios: - dependencies = await _buildIOS( - environment, - projectUri, - fileSystem, - buildRunner, - ); - case TargetPlatform.darwin: - dependencies = await _buildMacOS( - environment, - projectUri, - fileSystem, - buildRunner, - ); - case TargetPlatform.linux_arm64: - case TargetPlatform.linux_x64: - dependencies = await _buildLinux( - environment, - targetPlatform, - projectUri, - fileSystem, - buildRunner, - ); - case TargetPlatform.windows_arm64: - case TargetPlatform.windows_x64: - dependencies = await _buildWindows( - environment, - targetPlatform, - projectUri, - fileSystem, - buildRunner, - ); - case TargetPlatform.tester: - if (const LocalPlatform().isMacOS) { - (_, dependencies) = await buildNativeAssetsMacOS( - buildMode: BuildMode.debug, - projectUri: projectUri, - codesignIdentity: environment.defines[kCodesignIdentity], - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - flutterTester: true, - ); - } else if (const LocalPlatform().isLinux) { - (_, dependencies) = await buildNativeAssetsLinux( - buildMode: BuildMode.debug, - projectUri: projectUri, - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - flutterTester: true, - ); - } else if (const LocalPlatform().isWindows) { - (_, dependencies) = await buildNativeAssetsWindows( - buildMode: BuildMode.debug, - projectUri: projectUri, - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - flutterTester: true, - ); - } else { - // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 - // Write the file we claim to have in the [outputs]. - await writeNativeAssetsYaml(KernelAssets(), environment.buildDir.uri, fileSystem); - dependencies = []; - } - case TargetPlatform.android_arm: - case TargetPlatform.android_arm64: - case TargetPlatform.android_x64: - case TargetPlatform.android_x86: - case TargetPlatform.android: - (_, dependencies) = await _buildAndroid( - environment, - targetPlatform, - projectUri, - fileSystem, - buildRunner, - ); - case TargetPlatform.fuchsia_arm64: - case TargetPlatform.fuchsia_x64: - case TargetPlatform.web_javascript: - // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 - // Write the file we claim to have in the [outputs]. - await writeNativeAssetsYaml(KernelAssets(), environment.buildDir.uri, fileSystem); - dependencies = []; - } + (result, _) = await runFlutterSpecificDartBuild( + environmentDefines: environment.defines, + buildRunner: buildRunner, + targetPlatform: targetPlatform, + projectUri: projectUri, + nativeAssetsYamlUri : nativeAssetsFileUri, + fileSystem: fileSystem, + ); } final Depfile depfile = Depfile( [ - for (final Uri dependency in dependencies) fileSystem.file(dependency), + for (final Uri dependency in result.dependencies) fileSystem.file(dependency), ], [ - nativeAssetsFile, + fileSystem.file(nativeAssetsFileUri), ], ); final File outputDepfile = environment.buildDir.childFile('native_assets.d'); @@ -181,188 +94,14 @@ class NativeAssets extends Target { outputDepfile.parent.createSync(recursive: true); } environment.depFileService.writeToFile(depfile, outputDepfile); - if (!await nativeAssetsFile.exists()) { - throwToolExit("${nativeAssetsFile.path} doesn't exist."); + if (!await fileSystem.file(nativeAssetsFileUri).exists()) { + throwToolExit("${nativeAssetsFileUri.path} doesn't exist."); } if (!await outputDepfile.exists()) { throwToolExit("${outputDepfile.path} doesn't exist."); } } - Future> _buildWindows( - Environment environment, - TargetPlatform targetPlatform, - Uri projectUri, - FileSystem fileSystem, - NativeAssetsBuildRunner buildRunner, - ) async { - final String? environmentBuildMode = environment.defines[kBuildMode]; - if (environmentBuildMode == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); - final (_, List dependencies) = await buildNativeAssetsWindows( - targetPlatform: targetPlatform, - buildMode: buildMode, - projectUri: projectUri, - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - return dependencies; - } - - Future> _buildLinux( - Environment environment, - TargetPlatform targetPlatform, - Uri projectUri, - FileSystem fileSystem, - NativeAssetsBuildRunner buildRunner, - ) async { - final String? environmentBuildMode = environment.defines[kBuildMode]; - if (environmentBuildMode == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); - final (_, List dependencies) = await buildNativeAssetsLinux( - targetPlatform: targetPlatform, - buildMode: buildMode, - projectUri: projectUri, - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - return dependencies; - } - - Future> _buildMacOS( - Environment environment, - Uri projectUri, - FileSystem fileSystem, - NativeAssetsBuildRunner buildRunner, - ) async { - final List darwinArchs = - _emptyToNull(environment.defines[kDarwinArchs]) - ?.split(' ') - .map(getDarwinArchForName) - .toList() ?? - [DarwinArch.x86_64, DarwinArch.arm64]; - final String? environmentBuildMode = environment.defines[kBuildMode]; - if (environmentBuildMode == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); - final (_, List dependencies) = await buildNativeAssetsMacOS( - darwinArchs: darwinArchs, - buildMode: buildMode, - projectUri: projectUri, - codesignIdentity: environment.defines[kCodesignIdentity], - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - return dependencies; - } - - Future> _buildIOS( - Environment environment, - Uri projectUri, - FileSystem fileSystem, - NativeAssetsBuildRunner buildRunner, - ) { - final List iosArchs = - _emptyToNull(environment.defines[kIosArchs]) - ?.split(' ') - .map(getIOSArchForName) - .toList() ?? - [DarwinArch.arm64]; - final String? environmentBuildMode = environment.defines[kBuildMode]; - if (environmentBuildMode == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); - final String? sdkRoot = environment.defines[kSdkRoot]; - if (sdkRoot == null) { - throw MissingDefineException(kSdkRoot, name); - } - final EnvironmentType environmentType = - environmentTypeFromSdkroot(sdkRoot, environment.fileSystem)!; - return buildNativeAssetsIOS( - environmentType: environmentType, - darwinArchs: iosArchs, - buildMode: buildMode, - projectUri: projectUri, - codesignIdentity: environment.defines[kCodesignIdentity], - fileSystem: fileSystem, - buildRunner: buildRunner, - yamlParentDirectory: environment.buildDir.uri, - ); - } - - Future<(Uri? nativeAssetsYaml, List dependencies)> _buildAndroid( - Environment environment, - TargetPlatform targetPlatform, - Uri projectUri, - FileSystem fileSystem, - NativeAssetsBuildRunner buildRunner) { - final String? androidArchsEnvironment = environment.defines[kAndroidArchs]; - final List androidArchs = _androidArchs( - targetPlatform, - androidArchsEnvironment, - ); - final int targetAndroidNdkApi = - int.parse(environment.defines[kMinSdkVersion] ?? minSdkVersion); - final String? environmentBuildMode = environment.defines[kBuildMode]; - if (environmentBuildMode == null) { - throw MissingDefineException(kBuildMode, name); - } - final BuildMode buildMode = BuildMode.fromCliName(environmentBuildMode); - return buildNativeAssetsAndroid( - buildMode: buildMode, - projectUri: projectUri, - yamlParentDirectory: environment.buildDir.uri, - fileSystem: fileSystem, - buildRunner: buildRunner, - androidArchs: androidArchs, - targetAndroidNdkApi: targetAndroidNdkApi, - ); - } - - List _androidArchs( - TargetPlatform targetPlatform, - String? androidArchsEnvironment, - ) { - switch (targetPlatform) { - case TargetPlatform.android_arm: - return [AndroidArch.armeabi_v7a]; - case TargetPlatform.android_arm64: - return [AndroidArch.arm64_v8a]; - case TargetPlatform.android_x64: - return [AndroidArch.x86_64]; - case TargetPlatform.android_x86: - return [AndroidArch.x86]; - case TargetPlatform.android: - if (androidArchsEnvironment == null) { - throw MissingDefineException(kAndroidArchs, name); - } - return androidArchsEnvironment - .split(' ') - .map(getAndroidArchForName) - .toList(); - case TargetPlatform.darwin: - case TargetPlatform.fuchsia_arm64: - case TargetPlatform.fuchsia_x64: - case TargetPlatform.ios: - case TargetPlatform.linux_arm64: - case TargetPlatform.linux_x64: - case TargetPlatform.tester: - case TargetPlatform.web_javascript: - case TargetPlatform.windows_x64: - case TargetPlatform.windows_arm64: - throwToolExit('Unsupported Android target platform: $targetPlatform.'); - } - } - @override List get depfiles => [ 'native_assets.d', @@ -390,10 +129,3 @@ class NativeAssets extends Target { Source.pattern('{BUILD_DIR}/native_assets.yaml'), ]; } - -String? _emptyToNull(String? input) { - if (input == null || input.isEmpty) { - return null; - } - return input; -} diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart index 1a8b2fcf6bb..c5fde536ced 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/android/native_assets.dart @@ -2,145 +2,24 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:native_assets_builder/native_assets_builder.dart' - hide NativeAssetsBuildRunner; +import 'package:native_assets_builder/native_assets_builder.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import '../../../android/android_sdk.dart'; +import '../../../android/gradle_utils.dart'; import '../../../base/common.dart'; import '../../../base/file_system.dart'; -import '../../../build_info.dart'; +import '../../../build_info.dart' hide BuildMode; import '../../../globals.dart' as globals; -import '../native_assets.dart'; -/// Dry run the native builds. -/// -/// This does not build native assets, it only simulates what the final paths -/// of all assets will be so that this can be embedded in the kernel file. -Future dryRunNativeAssetsAndroid({ - required NativeAssetsBuildRunner buildRunner, - required Uri projectUri, - bool flutterTester = false, - required FileSystem fileSystem, -}) async { - if (!await nativeBuildRequired(buildRunner)) { - return null; - } - - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, OSImpl.android); - final Iterable nativeAssetPaths = - await dryRunNativeAssetsAndroidInternal( - fileSystem, - projectUri, - buildRunner, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - KernelAssets(nativeAssetPaths), - buildUri_, - fileSystem, - ); - return nativeAssetsUri; +int targetAndroidNdkApi(Map environmentDefines) { + return int.parse(environmentDefines[kMinSdkVersion] ?? minSdkVersion); } -Future> dryRunNativeAssetsAndroidInternal( - FileSystem fileSystem, - Uri projectUri, - NativeAssetsBuildRunner buildRunner, -) async { - const OSImpl targetOS = OSImpl.android; - - globals.logger.printTrace('Dry running native assets for $targetOS.'); - final BuildDryRunResult buildDryRunResult = await buildRunner.buildDryRun( - linkModePreference: LinkModePreferenceImpl.dynamic, - targetOS: targetOS, - workingDirectory: projectUri, - includeParentEnvironment: true, - ); - ensureNativeAssetsBuildDryRunSucceed(buildDryRunResult); - // No link hooks in JIT mode. - final List nativeAssets = buildDryRunResult.assets; - globals.logger.printTrace('Dry running native assets for $targetOS done.'); - final Map assetTargetLocations = - _assetTargetLocations(nativeAssets); - return assetTargetLocations.values; -} - -/// Builds native assets. -Future<(Uri? nativeAssetsYaml, List dependencies)> - buildNativeAssetsAndroid({ - required NativeAssetsBuildRunner buildRunner, - required Iterable androidArchs, - required Uri projectUri, - required BuildMode buildMode, - String? codesignIdentity, - Uri? yamlParentDirectory, - required FileSystem fileSystem, - required int targetAndroidNdkApi, -}) async { - const OSImpl targetOS = OSImpl.android; - final Uri buildUri_ = nativeAssetsBuildUri(projectUri, targetOS); - if (!await nativeBuildRequired(buildRunner)) { - final Uri nativeAssetsYaml = await writeNativeAssetsYaml( - KernelAssets(), - yamlParentDirectory ?? buildUri_, - fileSystem, - ); - return (nativeAssetsYaml, []); - } - - final List targets = androidArchs.map(_getNativeTarget).toList(); - final BuildModeImpl buildModeCli = - nativeAssetsBuildMode(buildMode); - final bool linkingEnabled = buildModeCli == BuildModeImpl.release; - - globals.logger - .printTrace('Building native assets for $targets $buildModeCli.'); - final List nativeAssets = []; - final Set dependencies = {}; - for (final Target target in targets) { - final BuildResult buildResult = await buildRunner.build( - linkModePreference: LinkModePreferenceImpl.dynamic, - target: target, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.ndkCCompilerConfigImpl, - targetAndroidNdkApi: targetAndroidNdkApi, - linkingEnabled: linkingEnabled, - ); - ensureNativeAssetsBuildSucceed(buildResult); - nativeAssets.addAll(buildResult.assets); - dependencies.addAll(buildResult.dependencies); - if (linkingEnabled) { - final LinkResult linkResult = await buildRunner.link( - linkModePreference: LinkModePreferenceImpl.dynamic, - target: target, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.ndkCCompilerConfigImpl, - targetAndroidNdkApi: targetAndroidNdkApi, - buildResult: buildResult, - ); - ensureNativeAssetsLinkSucceed(linkResult); - nativeAssets.addAll(linkResult.assets); - dependencies.addAll(linkResult.dependencies); - } - } - globals.logger.printTrace('Building native assets for $targets done.'); - final Map assetTargetLocations = - _assetTargetLocations(nativeAssets); - await _copyNativeAssetsAndroid(buildUri_, assetTargetLocations, fileSystem); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - KernelAssets(assetTargetLocations.values), - yamlParentDirectory ?? buildUri_, - fileSystem); - return (nativeAssetsUri, dependencies.toList()); -} - -Future _copyNativeAssetsAndroid( +Future copyNativeCodeAssetsAndroid( Uri buildUri, - Map assetTargetLocations, + Map assetTargetLocations, FileSystem fileSystem, ) async { if (assetTargetLocations.isNotEmpty) { @@ -154,7 +33,7 @@ Future _copyNativeAssetsAndroid( final Uri archUri = buildUri.resolve('jniLibs/lib/$jniArchDir/'); await fileSystem.directory(archUri).create(recursive: true); } - for (final MapEntry assetMapping + for (final MapEntry assetMapping in assetTargetLocations.entries) { final Uri source = assetMapping.key.file!; final Uri target = (assetMapping.value.path as KernelAssetAbsolutePath).uri; @@ -171,7 +50,7 @@ Future _copyNativeAssetsAndroid( } /// Get the [Target] for [androidArch]. -Target _getNativeTarget(AndroidArch androidArch) { +Target getNativeAndroidTarget(AndroidArch androidArch) { return switch (androidArch) { AndroidArch.armeabi_v7a => Target.androidArm, AndroidArch.arm64_v8a => Target.androidArm64, @@ -192,27 +71,27 @@ AndroidArch _getAndroidArch(Target target) { }; } -Map _assetTargetLocations( - List nativeAssets) { - return { - for (final AssetImpl asset in nativeAssets) +Map assetTargetLocationsAndroid( + List nativeAssets) { + return { + for (final NativeCodeAssetImpl asset in nativeAssets) asset: _targetLocationAndroid(asset), }; } /// Converts the `path` of [asset] as output from a `build.dart` invocation to /// the path used inside the Flutter app bundle. -KernelAsset _targetLocationAndroid(AssetImpl asset) { - final LinkModeImpl linkMode = (asset as NativeCodeAssetImpl).linkMode; +KernelAsset _targetLocationAndroid(NativeCodeAssetImpl asset) { + final LinkMode linkMode = asset.linkMode; final KernelAssetPath kernelAssetPath; switch (linkMode) { - case DynamicLoadingSystemImpl _: + case DynamicLoadingSystem _: kernelAssetPath = KernelAssetSystemPath(linkMode.uri); - case LookupInExecutableImpl _: + case LookupInExecutable _: kernelAssetPath = KernelAssetInExecutable(); - case LookupInProcessImpl _: + case LookupInProcess _: kernelAssetPath = KernelAssetInProcess(); - case DynamicLoadingBundledImpl _: + case DynamicLoadingBundled _: final String fileName = asset.file!.pathSegments.last; kernelAssetPath = KernelAssetAbsolutePath(Uri(path: fileName)); default: @@ -234,7 +113,6 @@ KernelAsset _targetLocationAndroid(AssetImpl asset) { /// Should only be invoked if a native assets build is performed. If the native /// assets feature is disabled, or none of the packages have native assets, a /// missing NDK is okay. -@override Future cCompilerConfigAndroid() async { final AndroidSdk? androidSdk = AndroidSdk.locateAndroidSdk(); if (androidSdk == null) { diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart index 427ccc45fd5..20b5cb7c89f 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/ios/native_assets.dart @@ -2,147 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:native_assets_builder/native_assets_builder.dart' - hide NativeAssetsBuildRunner; +import 'package:native_assets_builder/native_assets_builder.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import '../../../base/file_system.dart'; -import '../../../build_info.dart'; +import '../../../build_info.dart' hide BuildMode; +import '../../../build_info.dart' as build_info; import '../../../globals.dart' as globals; import '../macos/native_assets_host.dart'; -import '../native_assets.dart'; -/// Dry run the native builds. -/// -/// This does not build native assets, it only simulates what the final paths -/// of all assets will be so that this can be embedded in the kernel file and -/// the Xcode project. -Future dryRunNativeAssetsIOS({ - required NativeAssetsBuildRunner buildRunner, - required Uri projectUri, - required FileSystem fileSystem, -}) async { - if (!await nativeBuildRequired(buildRunner)) { - return null; - } +// TODO(dcharkes): Fetch minimum iOS version from somewhere. https://github.com/flutter/flutter/issues/145104 +const int targetIOSVersion = 12; - final Uri buildUri = nativeAssetsBuildUri(projectUri, OSImpl.iOS); - final Iterable assetTargetLocations = await dryRunNativeAssetsIOSInternal( - fileSystem, - projectUri, - buildRunner, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - KernelAssets(assetTargetLocations), - buildUri, - fileSystem, - ); - return nativeAssetsUri; -} - -Future> dryRunNativeAssetsIOSInternal( - FileSystem fileSystem, - Uri projectUri, - NativeAssetsBuildRunner buildRunner, -) async { - const OSImpl targetOS = OSImpl.iOS; - globals.logger.printTrace('Dry running native assets for $targetOS.'); - final BuildDryRunResult buildDryRunResult = await buildRunner.buildDryRun( - linkModePreference: LinkModePreferenceImpl.dynamic, - targetOS: targetOS, - workingDirectory: projectUri, - includeParentEnvironment: true, - ); - ensureNativeAssetsBuildDryRunSucceed(buildDryRunResult); - // No link hooks in JIT. - final List nativeAssets = buildDryRunResult.assets; - globals.logger.printTrace('Dry running native assets for $targetOS done.'); - return _assetTargetLocations(nativeAssets).values; -} - -/// Builds native assets. -Future> buildNativeAssetsIOS({ - required NativeAssetsBuildRunner buildRunner, - required List darwinArchs, - required EnvironmentType environmentType, - required Uri projectUri, - required BuildMode buildMode, - String? codesignIdentity, - required Uri yamlParentDirectory, - required FileSystem fileSystem, -}) async { - if (!await nativeBuildRequired(buildRunner)) { - await writeNativeAssetsYaml(KernelAssets(), yamlParentDirectory, fileSystem); - return []; - } - - final List targets = darwinArchs.map(_getNativeTarget).toList(); - final BuildModeImpl buildModeCli = nativeAssetsBuildMode(buildMode); - final bool linkingEnabled = buildModeCli == BuildModeImpl.release; - - const OSImpl targetOS = OSImpl.iOS; - final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); - final IOSSdkImpl iosSdk = _getIOSSdkImpl(environmentType); - - globals.logger.printTrace('Building native assets for $targets $buildModeCli.'); - final List nativeAssets = []; - final Set dependencies = {}; - for (final Target target in targets) { - final BuildResult buildResult = await buildRunner.build( - linkModePreference: LinkModePreferenceImpl.dynamic, - target: target, - targetIOSSdkImpl: iosSdk, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.cCompilerConfig, - // TODO(dcharkes): Fetch minimum iOS version from somewhere. https://github.com/flutter/flutter/issues/145104 - targetIOSVersion: 12, - linkingEnabled: linkingEnabled, - ); - ensureNativeAssetsBuildSucceed(buildResult); - nativeAssets.addAll(buildResult.assets); - dependencies.addAll(buildResult.dependencies); - if (linkingEnabled) { - final LinkResult linkResult = await buildRunner.link( - linkModePreference: LinkModePreferenceImpl.dynamic, - target: target, - targetIOSSdkImpl: iosSdk, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.cCompilerConfig, - buildResult: buildResult, - // TODO(dcharkes): Fetch minimum iOS version from somewhere. https://github.com/flutter/flutter/issues/145104 - targetIOSVersion: 12, - ); - ensureNativeAssetsLinkSucceed(linkResult); - nativeAssets.addAll(linkResult.assets); - dependencies.addAll(linkResult.dependencies); - } - } - globals.logger.printTrace('Building native assets for $targets done.'); - final Map> fatAssetTargetLocations = - _fatAssetTargetLocations(nativeAssets); - await _copyNativeAssetsIOS( - buildUri, - fatAssetTargetLocations, - codesignIdentity, - buildMode, - fileSystem, - ); - - final Map assetTargetLocations = - _assetTargetLocations(nativeAssets); - await writeNativeAssetsYaml( - KernelAssets(assetTargetLocations.values), - yamlParentDirectory, - fileSystem, - ); - return dependencies.toList(); -} - -IOSSdkImpl _getIOSSdkImpl(EnvironmentType environmentType) { +IOSSdkImpl getIOSSdk(EnvironmentType environmentType) { return switch (environmentType) { EnvironmentType.physical => IOSSdkImpl.iPhoneOS, EnvironmentType.simulator => IOSSdkImpl.iPhoneSimulator, @@ -150,7 +23,7 @@ IOSSdkImpl _getIOSSdkImpl(EnvironmentType environmentType) { } /// Extract the [Target] from a [DarwinArch]. -Target _getNativeTarget(DarwinArch darwinArch) { +Target getNativeIOSTarget(DarwinArch darwinArch) { return switch (darwinArch) { DarwinArch.armv7 => Target.iOSArm, DarwinArch.arm64 => Target.iOSArm64, @@ -158,13 +31,13 @@ Target _getNativeTarget(DarwinArch darwinArch) { }; } -Map> _fatAssetTargetLocations( - List nativeAssets) { +Map> fatAssetTargetLocationsIOS( + List nativeAssets) { final Set alreadyTakenNames = {}; - final Map> result = - >{}; + final Map> result = + >{}; final Map idToPath = {}; - for (final AssetImpl asset in nativeAssets) { + for (final NativeCodeAssetImpl asset in nativeAssets) { // Use same target path for all assets with the same id. final KernelAssetPath path = idToPath[asset.id] ?? _targetLocationIOS( @@ -172,23 +45,24 @@ Map> _fatAssetTargetLocations( alreadyTakenNames, ).path; idToPath[asset.id] = path; - result[path] ??= []; + result[path] ??= []; result[path]!.add(asset); } return result; } -Map _assetTargetLocations( - List nativeAssets) { +Map assetTargetLocationsIOS( + List nativeAssets) { final Set alreadyTakenNames = {}; final Map idToPath = {}; - final Map result = {}; - for (final AssetImpl asset in nativeAssets) { - final KernelAssetPath path = idToPath[asset.id] ?? - _targetLocationIOS(asset, alreadyTakenNames).path; + final Map result = + {}; + for (final NativeCodeAssetImpl asset in nativeAssets) { + final KernelAssetPath path = + idToPath[asset.id] ?? _targetLocationIOS(asset, alreadyTakenNames).path; idToPath[asset.id] = path; result[asset] = KernelAsset( - id: (asset as NativeCodeAssetImpl).id, + id: asset.id, target: Target.fromArchitectureAndOS(asset.architecture!, asset.os), path: path, ); @@ -196,17 +70,18 @@ Map _assetTargetLocations( return result; } -KernelAsset _targetLocationIOS(AssetImpl asset, Set alreadyTakenNames) { -final LinkModeImpl linkMode = (asset as NativeCodeAssetImpl).linkMode; -final KernelAssetPath kernelAssetPath; +KernelAsset _targetLocationIOS( + NativeCodeAssetImpl asset, Set alreadyTakenNames) { + final LinkMode linkMode = asset.linkMode; + final KernelAssetPath kernelAssetPath; switch (linkMode) { - case DynamicLoadingSystemImpl _: + case DynamicLoadingSystem _: kernelAssetPath = KernelAssetSystemPath(linkMode.uri); - case LookupInExecutableImpl _: + case LookupInExecutable _: kernelAssetPath = KernelAssetInExecutable(); - case LookupInProcessImpl _: + case LookupInProcess _: kernelAssetPath = KernelAssetInProcess(); - case DynamicLoadingBundledImpl _: + case DynamicLoadingBundled _: final String fileName = asset.file!.pathSegments.last; kernelAssetPath = KernelAssetAbsolutePath(frameworkUri( fileName, @@ -236,11 +111,11 @@ final KernelAssetPath kernelAssetPath; /// /// Code signing is also done here, so that it doesn't have to be done in /// in xcode_backend.dart. -Future _copyNativeAssetsIOS( +Future copyNativeCodeAssetsIOS( Uri buildUri, - Map> assetTargetLocations, + Map> assetTargetLocations, String? codesignIdentity, - BuildMode buildMode, + build_info.BuildMode buildMode, FileSystem fileSystem, ) async { if (assetTargetLocations.isNotEmpty) { @@ -250,11 +125,12 @@ Future _copyNativeAssetsIOS( final Map oldToNewInstallNames = {}; final List<(File, String, Directory)> dylibs = <(File, String, Directory)>[]; - for (final MapEntry> assetMapping + for (final MapEntry> assetMapping in assetTargetLocations.entries) { final Uri target = (assetMapping.key as KernelAssetAbsolutePath).uri; final List sources = [ - for (final AssetImpl source in assetMapping.value) fileSystem.file(source.file) + for (final NativeCodeAssetImpl source in assetMapping.value) + fileSystem.file(source.file) ]; final Uri targetUri = buildUri.resolveUri(target); final File dylibFile = fileSystem.file(targetUri); @@ -265,7 +141,8 @@ Future _copyNativeAssetsIOS( await lipoDylibs(dylibFile, sources); final String dylibFileName = dylibFile.basename; - final String newInstallName = '@rpath/$dylibFileName.framework/$dylibFileName'; + final String newInstallName = + '@rpath/$dylibFileName.framework/$dylibFileName'; final Set oldInstallNames = await getInstallNamesDylib(dylibFile); for (final String oldInstallName in oldInstallNames) { oldToNewInstallNames[oldInstallName] = newInstallName; diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart index ee4be081dc6..815146e96ff 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/linux/native_assets.dart @@ -2,70 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:native_assets_builder/native_assets_builder.dart' - hide NativeAssetsBuildRunner; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import '../../../base/common.dart'; import '../../../base/file_system.dart'; import '../../../base/io.dart'; -import '../../../build_info.dart'; import '../../../globals.dart' as globals; -import '../native_assets.dart'; - -/// Dry run the native builds. -/// -/// This does not build native assets, it only simulates what the final paths -/// of all assets will be so that this can be embedded in the kernel file. -Future dryRunNativeAssetsLinux({ - required NativeAssetsBuildRunner buildRunner, - required Uri projectUri, - bool flutterTester = false, - required FileSystem fileSystem, -}) { - return dryRunNativeAssetsSingleArchitecture( - buildRunner: buildRunner, - projectUri: projectUri, - flutterTester: flutterTester, - fileSystem: fileSystem, - os: OSImpl.linux, - ); -} - -Future> dryRunNativeAssetsLinuxInternal( - FileSystem fileSystem, - Uri projectUri, - bool flutterTester, - NativeAssetsBuildRunner buildRunner, -) { - return dryRunNativeAssetsSingleArchitectureInternal( - fileSystem, - projectUri, - flutterTester, - buildRunner, - OSImpl.linux, - ); -} - -Future<(Uri? nativeAssetsYaml, List dependencies)> buildNativeAssetsLinux({ - required NativeAssetsBuildRunner buildRunner, - TargetPlatform? targetPlatform, - required Uri projectUri, - required BuildMode buildMode, - bool flutterTester = false, - Uri? yamlParentDirectory, - required FileSystem fileSystem, -}) { - return buildNativeAssetsSingleArchitecture( - buildRunner: buildRunner, - targetPlatform: targetPlatform, - projectUri: projectUri, - buildMode: buildMode, - flutterTester: flutterTester, - yamlParentDirectory: yamlParentDirectory, - fileSystem: fileSystem, - ); -} /// Flutter expects `clang++` to be on the path on Linux hosts. /// diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart index e6d681aa451..6878797a2c3 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets.dart @@ -2,179 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:native_assets_builder/native_assets_builder.dart' - hide NativeAssetsBuildRunner; +import 'package:native_assets_builder/native_assets_builder.dart'; +import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import '../../../base/file_system.dart'; -import '../../../build_info.dart'; +import '../../../build_info.dart' hide BuildMode; +import '../../../build_info.dart' as build_info; import '../../../globals.dart' as globals; -import '../native_assets.dart'; import 'native_assets_host.dart'; -/// Dry run the native builds. -/// -/// This does not build native assets, it only simulates what the final paths -/// of all assets will be so that this can be embedded in the kernel file and -/// the Xcode project. -Future dryRunNativeAssetsMacOS({ - required NativeAssetsBuildRunner buildRunner, - required Uri projectUri, - bool flutterTester = false, - required FileSystem fileSystem, -}) async { - if (!await nativeBuildRequired(buildRunner)) { - return null; - } - - final Uri buildUri = nativeAssetsBuildUri(projectUri, OSImpl.macOS); - final Iterable nativeAssetPaths = await dryRunNativeAssetsMacOSInternal( - fileSystem, - projectUri, - flutterTester, - buildRunner, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - KernelAssets(nativeAssetPaths), - buildUri, - fileSystem, - ); - return nativeAssetsUri; -} - -Future> dryRunNativeAssetsMacOSInternal( - FileSystem fileSystem, - Uri projectUri, - bool flutterTester, - NativeAssetsBuildRunner buildRunner, -) async { - const OSImpl targetOS = OSImpl.macOS; - final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); - - globals.logger.printTrace('Dry running native assets for $targetOS.'); - final BuildDryRunResult buildDryRunResult = await buildRunner.buildDryRun( - linkModePreference: LinkModePreferenceImpl.dynamic, - targetOS: targetOS, - workingDirectory: projectUri, - includeParentEnvironment: true, - ); - ensureNativeAssetsBuildDryRunSucceed(buildDryRunResult); - // No link hooks in JIT mode. - final List nativeAssets = buildDryRunResult.assets; - globals.logger.printTrace('Dry running native assets for $targetOS done.'); - final Uri? absolutePath = flutterTester ? buildUri : null; - final Map assetTargetLocations = - _assetTargetLocations( - nativeAssets, - absolutePath, - ); - return assetTargetLocations.values; -} - -/// Builds native assets. -/// -/// If [darwinArchs] is omitted, the current target architecture is used. -/// -/// If [flutterTester] is true, absolute paths are emitted in the native -/// assets mapping. This can be used for JIT mode without sandbox on the host. -/// This is used in `flutter test` and `flutter run -d flutter-tester`. -Future<(Uri? nativeAssetsYaml, List dependencies)> buildNativeAssetsMacOS({ - required NativeAssetsBuildRunner buildRunner, - List? darwinArchs, - required Uri projectUri, - required BuildMode buildMode, - bool flutterTester = false, - String? codesignIdentity, - Uri? yamlParentDirectory, - required FileSystem fileSystem, -}) async { - const OSImpl targetOS = OSImpl.macOS; - final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); - if (!await nativeBuildRequired(buildRunner)) { - final Uri nativeAssetsYaml = await writeNativeAssetsYaml( - KernelAssets(), - yamlParentDirectory ?? buildUri, - fileSystem, - ); - return (nativeAssetsYaml, []); - } - - final List targets = darwinArchs != null - ? darwinArchs.map(_getNativeTarget).toList() - : [Target.current]; - final BuildModeImpl buildModeCli = - nativeAssetsBuildMode(buildMode); - final bool linkingEnabled = buildModeCli == BuildModeImpl.release; - - globals.logger - .printTrace('Building native assets for $targets $buildModeCli.'); - final List nativeAssets = []; - final Set dependencies = {}; - for (final Target target in targets) { - final BuildResult buildResult = await buildRunner.build( - linkModePreference: LinkModePreferenceImpl.dynamic, - target: target, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.cCompilerConfig, - // TODO(dcharkes): Fetch minimum MacOS version from somewhere. https://github.com/flutter/flutter/issues/145104 - targetMacOSVersion: 13, - linkingEnabled: linkingEnabled, - ); - ensureNativeAssetsBuildSucceed(buildResult); - nativeAssets.addAll(buildResult.assets); - dependencies.addAll(buildResult.dependencies); - if (linkingEnabled) { - final LinkResult linkResult = await buildRunner.link( - linkModePreference: LinkModePreferenceImpl.dynamic, - target: target, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.cCompilerConfig, - buildResult: buildResult, - // TODO(dcharkes): Fetch minimum MacOS version from somewhere. https://github.com/flutter/flutter/issues/145104 - targetMacOSVersion: 13, - ); - ensureNativeAssetsLinkSucceed(linkResult); - nativeAssets.addAll(linkResult.assets); - dependencies.addAll(linkResult.dependencies); - } - } - globals.logger.printTrace('Building native assets for $targets done.'); - final Uri? absolutePath = flutterTester ? buildUri : null; - final Map assetTargetLocations = - _assetTargetLocations(nativeAssets, absolutePath); - final Map> fatAssetTargetLocations = - _fatAssetTargetLocations(nativeAssets, absolutePath); - if (flutterTester) { - await _copyNativeAssetsMacOSFlutterTester( - buildUri, - fatAssetTargetLocations, - codesignIdentity, - buildMode, - fileSystem, - ); - } else { - await _copyNativeAssetsMacOS( - buildUri, - fatAssetTargetLocations, - codesignIdentity, - buildMode, - fileSystem, - ); - } - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - KernelAssets(assetTargetLocations.values), - yamlParentDirectory ?? buildUri, - fileSystem, - ); - return (nativeAssetsUri, dependencies.toList()); -} +// TODO(dcharkes): Fetch minimum MacOS version from somewhere. https://github.com/flutter/flutter/issues/145104 +const int targetMacOSVersion = 13; /// Extract the [Target] from a [DarwinArch]. -Target _getNativeTarget(DarwinArch darwinArch) { +Target getNativeMacOSTarget(DarwinArch darwinArch) { return switch (darwinArch) { DarwinArch.arm64 => Target.macOSArm64, DarwinArch.x86_64 => Target.macOSX64, @@ -182,15 +24,15 @@ Target _getNativeTarget(DarwinArch darwinArch) { }; } -Map> _fatAssetTargetLocations( - List nativeAssets, +Map> fatAssetTargetLocationsMacOS( + List nativeAssets, Uri? absolutePath, ) { final Set alreadyTakenNames = {}; - final Map> result = - >{}; + final Map> result = + >{}; final Map idToPath = {}; - for (final AssetImpl asset in nativeAssets) { + for (final NativeCodeAssetImpl asset in nativeAssets) { // Use same target path for all assets with the same id. final KernelAssetPath path = idToPath[asset.id] ?? _targetLocationMacOS( @@ -199,25 +41,25 @@ Map> _fatAssetTargetLocations( alreadyTakenNames, ).path; idToPath[asset.id] = path; - result[path] ??= []; + result[path] ??= []; result[path]!.add(asset); } return result; } -Map _assetTargetLocations( - List nativeAssets, +Map assetTargetLocationsMacOS( + List nativeAssets, Uri? absolutePath, ) { final Set alreadyTakenNames = {}; final Map idToPath = {}; - final Map result = {}; - for (final AssetImpl asset in nativeAssets) { + final Map result = {}; + for (final NativeCodeAssetImpl asset in nativeAssets) { final KernelAssetPath path = idToPath[asset.id] ?? _targetLocationMacOS(asset, absolutePath, alreadyTakenNames).path; idToPath[asset.id] = path; result[asset] = KernelAsset( - id: (asset as NativeCodeAssetImpl).id, + id: asset.id, target: Target.fromArchitectureAndOS(asset.architecture!, asset.os), path: path, ); @@ -226,20 +68,20 @@ Map _assetTargetLocations( } KernelAsset _targetLocationMacOS( - AssetImpl asset, + NativeCodeAssetImpl asset, Uri? absolutePath, Set alreadyTakenNames, ) { - final LinkModeImpl linkMode = (asset as NativeCodeAssetImpl).linkMode; + final LinkMode linkMode = asset.linkMode; final KernelAssetPath kernelAssetPath; switch (linkMode) { - case DynamicLoadingSystemImpl _: + case DynamicLoadingSystem _: kernelAssetPath = KernelAssetSystemPath(linkMode.uri); - case LookupInExecutableImpl _: + case LookupInExecutable _: kernelAssetPath = KernelAssetInExecutable(); - case LookupInProcessImpl _: + case LookupInProcess _: kernelAssetPath = KernelAssetInProcess(); - case DynamicLoadingBundledImpl _: + case DynamicLoadingBundled _: final String fileName = asset.file!.pathSegments.last; Uri uri; if (absolutePath != null) { @@ -279,11 +121,11 @@ KernelAsset _targetLocationMacOS( /// /// Code signing is also done here, so that it doesn't have to be done in /// in macos_assemble.sh. -Future _copyNativeAssetsMacOS( +Future copyNativeCodeAssetsMacOS( Uri buildUri, - Map> assetTargetLocations, + Map> assetTargetLocations, String? codesignIdentity, - BuildMode buildMode, + build_info.BuildMode buildMode, FileSystem fileSystem, ) async { if (assetTargetLocations.isNotEmpty) { @@ -294,11 +136,11 @@ Future _copyNativeAssetsMacOS( final Map oldToNewInstallNames = {}; final List<(File, String, Directory)> dylibs = <(File, String, Directory)>[]; - for (final MapEntry> assetMapping + for (final MapEntry> assetMapping in assetTargetLocations.entries) { final Uri target = (assetMapping.key as KernelAssetAbsolutePath).uri; final List sources = [ - for (final AssetImpl source in assetMapping.value) fileSystem.file(source.file), + for (final NativeCodeAssetImpl source in assetMapping.value) fileSystem.file(source.file), ]; final Uri targetUri = buildUri.resolveUri(target); final String name = targetUri.pathSegments.last; @@ -373,11 +215,11 @@ Future _copyNativeAssetsMacOS( /// so that the referenced library can be found the dynamic linker. /// /// Code signing is also done here. -Future _copyNativeAssetsMacOSFlutterTester( +Future copyNativeCodeAssetsMacOSFlutterTester( Uri buildUri, - Map> assetTargetLocations, + Map> assetTargetLocations, String? codesignIdentity, - BuildMode buildMode, + build_info.BuildMode buildMode, FileSystem fileSystem, ) async { if (assetTargetLocations.isNotEmpty) { @@ -388,11 +230,11 @@ Future _copyNativeAssetsMacOSFlutterTester( final Map oldToNewInstallNames = {}; final List<(File, String)> dylibs = <(File, String)>[]; - for (final MapEntry> assetMapping + for (final MapEntry> assetMapping in assetTargetLocations.entries) { final Uri target = (assetMapping.key as KernelAssetAbsolutePath).uri; final List sources = [ - for (final AssetImpl source in assetMapping.value) fileSystem.file(source.file), + for (final NativeCodeAssetImpl source in assetMapping.value) fileSystem.file(source.file), ]; final Uri targetUri = buildUri.resolveUri(target); final File dylibFile = fileSystem.file(targetUri); diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart index 4ce136c74d5..503f9ae2a0c 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/macos/native_assets_host.dart @@ -4,13 +4,13 @@ // Shared logic between iOS and macOS implementations of native assets. -import 'package:native_assets_cli/native_assets_cli.dart' show Architecture; +import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import '../../../base/common.dart'; import '../../../base/file_system.dart'; import '../../../base/io.dart'; -import '../../../build_info.dart'; +import '../../../build_info.dart' as build_info; import '../../../convert.dart'; import '../../../globals.dart' as globals; @@ -99,13 +99,13 @@ Future setInstallNamesDylib( String newInstallName, Map oldToNewInstallNames, ) async { - final ProcessResult setInstallNamesResult = await globals.processManager.run( + final ProcessResult setInstallNamesResult = await globals.processManager.run( [ 'install_name_tool', '-id', newInstallName, - for (final MapEntry entry in oldToNewInstallNames.entries) - ...['-change', entry.key, entry.value], + for (final MapEntry entry in oldToNewInstallNames + .entries) ...['-change', entry.key, entry.value], dylibFile.path, ], ); @@ -135,18 +135,16 @@ Future> getInstallNamesDylib(File dylibFile) async { return { for (final List architectureSection - in parseOtoolArchitectureSections(installNameResult.stdout as String).values) + in parseOtoolArchitectureSections(installNameResult.stdout as String).values) // For each architecture, a separate install name is reported, which are // not necessarily the same. architectureSection.single, }; } - - Future codesignDylib( String? codesignIdentity, - BuildMode buildMode, + build_info.BuildMode buildMode, FileSystemEntity target, ) async { if (codesignIdentity == null || codesignIdentity.isEmpty) { @@ -157,7 +155,7 @@ Future codesignDylib( '--force', '--sign', codesignIdentity, - if (buildMode != BuildMode.release) ...[ + if (buildMode != build_info.BuildMode.release) ...[ // Mimic Xcode's timestamp codesigning behavior on non-release binaries. '--timestamp=none', ], diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart index 99e1a6f5225..fd8952e7d98 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/native_assets.dart @@ -5,10 +5,7 @@ // Logic for native assets shared between all host OSes. import 'package:logging/logging.dart' as logging; -import 'package:native_assets_builder/native_assets_builder.dart' - as native_assets_builder show NativeAssetsBuildRunner; -import 'package:native_assets_builder/native_assets_builder.dart' - hide NativeAssetsBuildRunner; +import 'package:native_assets_builder/native_assets_builder.dart'; import 'package:native_assets_cli/native_assets_cli.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:package_config/package_config_types.dart'; @@ -18,9 +15,11 @@ import '../../base/file_system.dart'; import '../../base/logger.dart'; import '../../base/platform.dart'; import '../../build_info.dart' as build_info; +import '../../build_system/exceptions.dart'; import '../../cache.dart'; import '../../features.dart'; import '../../globals.dart' as globals; +import '../../macos/xcode.dart' as xcode; import '../../resident_runner.dart'; import '../../run_hot.dart'; import 'android/native_assets.dart'; @@ -30,11 +29,161 @@ import 'macos/native_assets.dart'; import 'macos/native_assets_host.dart'; import 'windows/native_assets.dart'; +/// The assets produced by a Dart build and the dependencies of those assets. +/// +/// If any of the dependencies change, then the Dart build should be performed +/// again. +final class DartBuildResult { + const DartBuildResult({required this.codeAssets, required this.dependencies}); + const DartBuildResult.empty() + : codeAssets = const [], + dependencies = const []; + + final List codeAssets; + final List dependencies; +} + +/// Invokes the build of all transitive Dart packages and prepares code assets +/// to be included in the native build. +Future<(DartBuildResult, Uri)> runFlutterSpecificDartBuild({ + required Map environmentDefines, + required FlutterNativeAssetsBuildRunner buildRunner, + required build_info.TargetPlatform targetPlatform, + required Uri projectUri, + Uri? nativeAssetsYamlUri, + required FileSystem fileSystem, +}) async { + final OS targetOS = _getNativeOSFromTargetPlatfrorm(targetPlatform); + final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); + final Directory buildDir = fileSystem.directory(buildUri); + + final bool flutterTester = targetPlatform == build_info.TargetPlatform.tester; + + if (nativeAssetsYamlUri == null) { + // Only `flutter test` uses the + // `build/native_assets//native_assets.yaml` file which uses absolute + // paths to the shared libraries. + // + // testCompilerBuildNativeAssets() passes `null` + assert(flutterTester); + nativeAssetsYamlUri ??= buildUri.resolve('native_assets.yaml'); + } + + if (!await buildDir.exists()) { + // Ensure the folder exists so the native build system can copy it even + // if there's no native assets. + await buildDir.create(recursive: true); + } + + if (!await _nativeBuildRequired(buildRunner)) { + await writeNativeAssetsYaml( + KernelAssets(), nativeAssetsYamlUri, fileSystem); + return (const DartBuildResult.empty(), nativeAssetsYamlUri); + } + + final build_info.BuildMode buildMode; + if (flutterTester) { + buildMode = build_info.BuildMode.debug; + } else { + final String? environmentBuildMode = + environmentDefines[build_info.kBuildMode]; + if (environmentBuildMode == null) { + throw MissingDefineException(build_info.kBuildMode, 'native_assets'); + } + buildMode = build_info.BuildMode.fromCliName(environmentBuildMode); + } + final List targets = flutterTester + ? [Target.current] + : _targetsForOS(targetPlatform, targetOS, environmentDefines); + final DartBuildResult result = targets.isEmpty + ? const DartBuildResult.empty() + : await _runDartBuild( + environmentDefines: environmentDefines, + buildRunner: buildRunner, + targets: targets, + projectUri: projectUri, + buildMode: _nativeAssetsBuildMode(buildMode), + fileSystem: fileSystem, + targetOS: targetOS); + + final String? codesignIdentity = + environmentDefines[build_info.kCodesignIdentity]; + + final Map assetTargetLocations = + _assetTargetLocationsForOS( + targetOS, result.codeAssets, flutterTester, buildUri); + await _copyNativeCodeAssetsForOS(targetOS, buildUri, buildMode, fileSystem, + assetTargetLocations, codesignIdentity, flutterTester); + final KernelAssets vmAssetMapping = + KernelAssets(assetTargetLocations.values.toList()); + await writeNativeAssetsYaml(vmAssetMapping, nativeAssetsYamlUri, fileSystem); + return (result, nativeAssetsYamlUri); +} + +Future runFlutterSpecificDartDryRunOnPlatforms({ + required Uri projectUri, + required FileSystem fileSystem, + required FlutterNativeAssetsBuildRunner buildRunner, + required List targetPlatforms, +}) async { + if (!await _nativeBuildRequired(buildRunner)) { + return null; + } + + final Map assetTargetLocations = + {}; + for (final build_info.TargetPlatform targetPlatform in targetPlatforms) { + // This dry-run functionality is only used in the `flutter run` + // implementation (not in `flutter build` or `flutter test`). + // + // Though we can end up with `flutterTester == true` if someone uses the + // `flutter-tester` device via `flutter run -d flutter-tester` (which mainly + // happens in tests) + final bool flutterTester = + targetPlatform == build_info.TargetPlatform.tester; + + final OSImpl targetOS = _getNativeOSFromTargetPlatfrorm(targetPlatform); + if (targetOS != OS.macOS && + targetOS != OS.windows && + targetOS != OS.linux && + targetOS != OS.android && + targetOS != OS.iOS) { + await ensureNoNativeAssetsOrOsIsSupported( + projectUri, + targetPlatform.toString(), + fileSystem, + buildRunner, + ); + } + + final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); + final DartBuildResult result = await _runDartDryRunBuild( + buildRunner: buildRunner, + projectUri: projectUri, + fileSystem: fileSystem, + targetOS: targetOS); + assetTargetLocations.addAll(_assetTargetLocationsForOS( + targetOS, result.codeAssets, flutterTester, buildUri)); + } + + final Uri buildUri = targetPlatforms.length == 1 + ? nativeAssetsBuildUri( + projectUri, _getNativeOSFromTargetPlatfrorm(targetPlatforms.single)) + : _buildUriMultiple(projectUri); + final Uri nativeAssetsYamlUri = buildUri.resolve('native_assets.yaml'); + await writeNativeAssetsYaml( + KernelAssets(assetTargetLocations.values.toList()), + nativeAssetsYamlUri, + fileSystem, + ); + return nativeAssetsYamlUri; +} + /// Programmatic API to be used by Dart launchers to invoke native builds. /// /// It enables mocking `package:native_assets_builder` package. /// It also enables mocking native toolchain discovery via [cCompilerConfig]. -abstract class NativeAssetsBuildRunner { +abstract interface class FlutterNativeAssetsBuildRunner { /// Whether the project has a `.dart_tools/package_config.json`. /// /// If there is no package config, [packagesWithNativeAssets], [build], and @@ -67,15 +216,6 @@ abstract class NativeAssetsBuildRunner { required bool linkingEnabled, }); - /// Runs all [packagesWithNativeAssets] `link.dart` in dry run. - Future linkDryRun({ - required bool includeParentEnvironment, - required LinkModePreferenceImpl linkModePreference, - required OSImpl targetOS, - required Uri workingDirectory, - required BuildDryRunResult buildDryRunResult, - }); - /// Runs all [packagesWithNativeAssets] `link.dart`. Future link({ required bool includeParentEnvironment, @@ -99,8 +239,8 @@ abstract class NativeAssetsBuildRunner { } /// Uses `package:native_assets_builder` for its implementation. -class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { - NativeAssetsBuildRunnerImpl( +class FlutterNativeAssetsBuildRunnerImpl implements FlutterNativeAssetsBuildRunner { + FlutterNativeAssetsBuildRunnerImpl( this.projectUri, this.packageConfigPath, this.packageConfig, @@ -131,7 +271,7 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { late final Uri _dartExecutable = fileSystem.directory(Cache.flutterRoot).uri.resolve('bin/dart'); - late final native_assets_builder.NativeAssetsBuildRunner _buildRunner = native_assets_builder.NativeAssetsBuildRunner( + late final NativeAssetsBuildRunner _buildRunner = NativeAssetsBuildRunner( logger: _logger, dartExecutable: _dartExecutable, ); @@ -208,29 +348,6 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { ); } - - @override - Future linkDryRun({ - required bool includeParentEnvironment, - required LinkModePreferenceImpl linkModePreference, - required OSImpl targetOS, - required Uri workingDirectory, - required BuildDryRunResult buildDryRunResult, - }) { - final PackageLayout packageLayout = PackageLayout.fromPackageConfig( - packageConfig, - Uri.file(packageConfigPath), - ); - return _buildRunner.linkDryRun( - includeParentEnvironment: includeParentEnvironment, - linkModePreference: linkModePreference, - targetOS: targetOS, - workingDirectory: workingDirectory, - packageLayout: packageLayout, - buildDryRunResult: buildDryRunResult, - ); - } - @override Future link({ required bool includeParentEnvironment, @@ -277,7 +394,7 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { return cCompilerConfigWindows(); } if (globals.platform.isAndroid) { - throwToolExit('Should use ndkCCompilerConfigImpl for Android.'); + throwToolExit('Should use ndkCCompilerConfig for Android.'); } throwToolExit('Unknown target OS.'); }(); @@ -288,26 +405,25 @@ class NativeAssetsBuildRunnerImpl implements NativeAssetsBuildRunner { }(); } -/// Write [assets] to `native_assets.yaml` in [yamlParentDirectory]. Future writeNativeAssetsYaml( KernelAssets assets, - Uri yamlParentDirectory, + Uri nativeAssetsYamlUri, FileSystem fileSystem, ) async { - globals.logger.printTrace('Writing native_assets.yaml.'); + globals.logger.printTrace('Writing native assets yaml to $nativeAssetsYamlUri.'); final String nativeAssetsDartContents = assets.toNativeAssetsFile(); - final Directory parentDirectory = fileSystem.directory(yamlParentDirectory); + final File nativeAssetsFile = fileSystem.file(nativeAssetsYamlUri); + final Directory parentDirectory = nativeAssetsFile.parent; if (!await parentDirectory.exists()) { await parentDirectory.create(recursive: true); } - final File nativeAssetsFile = parentDirectory.childFile('native_assets.yaml'); await nativeAssetsFile.writeAsString(nativeAssetsDartContents); globals.logger.printTrace('Writing ${nativeAssetsFile.path} done.'); return nativeAssetsFile.uri; } /// Select the native asset build mode for a given Flutter build mode. -BuildModeImpl nativeAssetsBuildMode(build_info.BuildMode buildMode) { +BuildModeImpl _nativeAssetsBuildMode(build_info.BuildMode buildMode) { switch (buildMode) { case build_info.BuildMode.debug: return BuildModeImpl.debug; @@ -324,7 +440,7 @@ BuildModeImpl nativeAssetsBuildMode(build_info.BuildMode buildMode) { /// /// Native asset builds cannot be run without a package config. If there is /// no package config, leave a logging trace about that. -Future _hasNoPackageConfig(NativeAssetsBuildRunner buildRunner) async { +Future _hasNoPackageConfig(FlutterNativeAssetsBuildRunner buildRunner) async { final bool packageConfigExists = await buildRunner.hasPackageConfig(); if (!packageConfigExists) { globals.logger.printTrace('No package config found. Skipping native assets compilation.'); @@ -332,7 +448,8 @@ Future _hasNoPackageConfig(NativeAssetsBuildRunner buildRunner) async { return !packageConfigExists; } -Future nativeBuildRequired(NativeAssetsBuildRunner buildRunner) async { + +Future _nativeBuildRequired(FlutterNativeAssetsBuildRunner buildRunner) async { if (await _hasNoPackageConfig(buildRunner)) { return false; } @@ -362,7 +479,7 @@ Future ensureNoNativeAssetsOrOsIsSupported( Uri workingDirectory, String os, FileSystem fileSystem, - NativeAssetsBuildRunner buildRunner, + FlutterNativeAssetsBuildRunner buildRunner, ) async { if (await _hasNoPackageConfig(buildRunner)) { return; @@ -389,6 +506,11 @@ Uri nativeAssetsBuildUri(Uri projectUri, OS os) { return projectUri.resolve('$buildDir/native_assets/$os/'); } +/// Gets the native asset id to dylib mapping to embed in the kernel file. +/// +/// Run hot compiles a kernel file that is pushed to the device after hot +/// restart. We need to embed the native assets mapping in order to access +/// native assets after hot restart. class HotRunnerNativeAssetsBuilderImpl implements HotRunnerNativeAssetsBuilder { const HotRunnerNativeAssetsBuilderImpl(); @@ -401,351 +523,44 @@ class HotRunnerNativeAssetsBuilderImpl implements HotRunnerNativeAssetsBuilder { required PackageConfig packageConfig, required Logger logger, }) async { - final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl( + final FlutterNativeAssetsBuildRunner buildRunner = + FlutterNativeAssetsBuildRunnerImpl( projectUri, packageConfigPath, packageConfig, fileSystem, globals.logger, ); - return dryRunNativeAssets( + + // If `flutter run -d all` is used then we may have multiple OSes. + final List targetPlatforms = flutterDevices + .map((FlutterDevice d) => d.targetPlatform) + .nonNulls + .toList(); + + return runFlutterSpecificDartDryRunOnPlatforms( projectUri: projectUri, fileSystem: fileSystem, buildRunner: buildRunner, - flutterDevices: flutterDevices, + targetPlatforms: targetPlatforms, ); } } -/// Gets the native asset id to dylib mapping to embed in the kernel file. -/// -/// Run hot compiles a kernel file that is pushed to the device after hot -/// restart. We need to embed the native assets mapping in order to access -/// native assets after hot restart. -Future dryRunNativeAssets({ - required Uri projectUri, - required FileSystem fileSystem, - required NativeAssetsBuildRunner buildRunner, - required List flutterDevices, -}) async { - if (flutterDevices.length != 1) { - return dryRunNativeAssetsMultipleOSes( - projectUri: projectUri, - fileSystem: fileSystem, - targetPlatforms: flutterDevices.map((FlutterDevice d) => d.targetPlatform).nonNulls, - buildRunner: buildRunner, - ); - } - final FlutterDevice flutterDevice = flutterDevices.single; - final build_info.TargetPlatform targetPlatform = flutterDevice.targetPlatform!; - - final Uri? nativeAssetsYaml; - switch (targetPlatform) { - case build_info.TargetPlatform.darwin: - nativeAssetsYaml = await dryRunNativeAssetsMacOS( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - case build_info.TargetPlatform.ios: - nativeAssetsYaml = await dryRunNativeAssetsIOS( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - case build_info.TargetPlatform.tester: - if (const LocalPlatform().isMacOS) { - nativeAssetsYaml = await dryRunNativeAssetsMacOS( - projectUri: projectUri, - flutterTester: true, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - } else if (const LocalPlatform().isLinux) { - nativeAssetsYaml = await dryRunNativeAssetsLinux( - projectUri: projectUri, - flutterTester: true, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - } else if (const LocalPlatform().isWindows) { - nativeAssetsYaml = await dryRunNativeAssetsWindows( - projectUri: projectUri, - flutterTester: true, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - } else { - await nativeBuildRequired(buildRunner); - nativeAssetsYaml = null; - } - case build_info.TargetPlatform.linux_arm64: - case build_info.TargetPlatform.linux_x64: - nativeAssetsYaml = await dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - case build_info.TargetPlatform.windows_arm64: - case build_info.TargetPlatform.windows_x64: - nativeAssetsYaml = await dryRunNativeAssetsWindows( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - case build_info.TargetPlatform.android_arm: - case build_info.TargetPlatform.android_arm64: - case build_info.TargetPlatform.android_x64: - case build_info.TargetPlatform.android_x86: - case build_info.TargetPlatform.android: - nativeAssetsYaml = await dryRunNativeAssetsAndroid( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - case build_info.TargetPlatform.fuchsia_arm64: - case build_info.TargetPlatform.fuchsia_x64: - case build_info.TargetPlatform.web_javascript: - await ensureNoNativeAssetsOrOsIsSupported( - projectUri, - targetPlatform.toString(), - fileSystem, - buildRunner, - ); - nativeAssetsYaml = null; - } - return nativeAssetsYaml; -} - -/// Dry run the native builds for multiple OSes. -/// -/// Needed for `flutter run -d all`. -Future dryRunNativeAssetsMultipleOSes({ - required NativeAssetsBuildRunner buildRunner, - required Uri projectUri, - required FileSystem fileSystem, - required Iterable targetPlatforms, -}) async { - if (await nativeBuildRequired(buildRunner)) { - return null; - } - - final Uri buildUri = buildUriMultiple(projectUri); - final Iterable nativeAssetPaths = [ - if (targetPlatforms.contains(build_info.TargetPlatform.darwin) || - (targetPlatforms.contains(build_info.TargetPlatform.tester) && - OSImpl.current == OSImpl.macOS)) - ...await dryRunNativeAssetsMacOSInternal( - fileSystem, - projectUri, - false, - buildRunner, - ), - if (targetPlatforms.contains(build_info.TargetPlatform.linux_arm64) || - targetPlatforms.contains(build_info.TargetPlatform.linux_x64) || - (targetPlatforms.contains(build_info.TargetPlatform.tester) && - OSImpl.current == OSImpl.linux)) - ...await dryRunNativeAssetsLinuxInternal( - fileSystem, - projectUri, - false, - buildRunner, - ), - if (targetPlatforms.contains(build_info.TargetPlatform.windows_arm64) || - targetPlatforms.contains(build_info.TargetPlatform.windows_x64) || - (targetPlatforms.contains(build_info.TargetPlatform.tester) && - OSImpl.current == OSImpl.windows)) - ...await dryRunNativeAssetsWindowsInternal( - fileSystem, - projectUri, - false, - buildRunner, - ), - if (targetPlatforms.contains(build_info.TargetPlatform.ios)) - ...await dryRunNativeAssetsIOSInternal( - fileSystem, - projectUri, - buildRunner, - ), - if (targetPlatforms.contains(build_info.TargetPlatform.android) || - targetPlatforms.contains(build_info.TargetPlatform.android_arm) || - targetPlatforms.contains(build_info.TargetPlatform.android_arm64) || - targetPlatforms.contains(build_info.TargetPlatform.android_x64) || - targetPlatforms.contains(build_info.TargetPlatform.android_x86)) - ...await dryRunNativeAssetsAndroidInternal( - fileSystem, - projectUri, - buildRunner, - ), - ]; - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - KernelAssets(nativeAssetPaths), - buildUri, - fileSystem, - ); - return nativeAssetsUri; -} /// With `flutter run -d all` we need a place to store the native assets /// mapping for multiple OSes combined. -Uri buildUriMultiple(Uri projectUri) { +Uri _buildUriMultiple(Uri projectUri) { final String buildDir = build_info.getBuildDirectory(); return projectUri.resolve('$buildDir/native_assets/multiple/'); } -/// Dry run the native builds. -/// -/// This does not build native assets, it only simulates what the final paths -/// of all assets will be so that this can be embedded in the kernel file. -Future dryRunNativeAssetsSingleArchitecture({ - required NativeAssetsBuildRunner buildRunner, - required Uri projectUri, - bool flutterTester = false, - required FileSystem fileSystem, - required OSImpl os, -}) async { - if (!await nativeBuildRequired(buildRunner)) { - return null; - } - - final Uri buildUri = nativeAssetsBuildUri(projectUri, os); - final Iterable nativeAssetPaths = await dryRunNativeAssetsSingleArchitectureInternal( - fileSystem, - projectUri, - flutterTester, - buildRunner, - os, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - KernelAssets(nativeAssetPaths.toList()), - buildUri, - fileSystem, - ); - return nativeAssetsUri; -} - -Future> dryRunNativeAssetsSingleArchitectureInternal( - FileSystem fileSystem, - Uri projectUri, - bool flutterTester, - NativeAssetsBuildRunner buildRunner, - OSImpl targetOS, -) async { - final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); - - globals.logger.printTrace('Dry running native assets for $targetOS.'); - - final BuildDryRunResult buildDryRunResult = await buildRunner.buildDryRun( - linkModePreference: LinkModePreferenceImpl.dynamic, - targetOS: targetOS, - workingDirectory: projectUri, - includeParentEnvironment: true, - ); - ensureNativeAssetsBuildDryRunSucceed(buildDryRunResult); - // No link hooks in JIT mode. - final List nativeAssets = buildDryRunResult.assets; - globals.logger.printTrace('Dry running native assets for $targetOS done.'); - final Uri? absolutePath = flutterTester ? buildUri : null; - final Map assetTargetLocations = - _assetTargetLocationsSingleArchitecture( - nativeAssets, - absolutePath, - ); - return assetTargetLocations.values; -} - -/// Builds native assets. -/// -/// If [targetPlatform] is omitted, the current target architecture is used. -/// -/// If [flutterTester] is true, absolute paths are emitted in the native -/// assets mapping. This can be used for JIT mode without sandbox on the host. -/// This is used in `flutter test` and `flutter run -d flutter-tester`. -Future<(Uri? nativeAssetsYaml, List dependencies)> buildNativeAssetsSingleArchitecture({ - required NativeAssetsBuildRunner buildRunner, - build_info.TargetPlatform? targetPlatform, - required Uri projectUri, - required build_info.BuildMode buildMode, - bool flutterTester = false, - Uri? yamlParentDirectory, - required FileSystem fileSystem, -}) async { - final Target target = targetPlatform != null ? _getNativeTarget(targetPlatform) : Target.current; - final OSImpl targetOS = target.os; - final Uri buildUri = nativeAssetsBuildUri(projectUri, targetOS); - final Directory buildDir = fileSystem.directory(buildUri); - if (!await buildDir.exists()) { - // CMake requires the folder to exist to do copying. - await buildDir.create(recursive: true); - } - if (!await nativeBuildRequired(buildRunner)) { - final Uri nativeAssetsYaml = await writeNativeAssetsYaml( - KernelAssets(), - yamlParentDirectory ?? buildUri, - fileSystem, - ); - return (nativeAssetsYaml, []); - } - - final BuildModeImpl buildModeCli = nativeAssetsBuildMode(buildMode); - final bool linkingEnabled = buildModeCli == BuildModeImpl.release; - - globals.logger.printTrace('Building native assets for $target $buildModeCli.'); - final BuildResult buildResult = await buildRunner.build( - linkModePreference: LinkModePreferenceImpl.dynamic, - target: target, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.cCompilerConfig, - linkingEnabled: linkingEnabled, - ); - ensureNativeAssetsBuildSucceed(buildResult); - late final LinkResult linkResult; - if (linkingEnabled) { - linkResult = await buildRunner.link( - linkModePreference: LinkModePreferenceImpl.dynamic, - target: target, - buildMode: buildModeCli, - workingDirectory: projectUri, - includeParentEnvironment: true, - cCompilerConfig: await buildRunner.cCompilerConfig, - buildResult: buildResult, - ); - ensureNativeAssetsLinkSucceed(linkResult); - } - final List nativeAssets = [ - ...buildResult.assets, - if (linkingEnabled) ...linkResult.assets, - ]; - final Set dependencies = { - ...buildResult.dependencies, - if (linkingEnabled) ...linkResult.dependencies, - }; - globals.logger.printTrace('Building native assets for $target done.'); - final Uri? absolutePath = flutterTester ? buildUri : null; - final Map assetTargetLocations = - _assetTargetLocationsSingleArchitecture(nativeAssets, absolutePath); - await _copyNativeAssetsSingleArchitecture( - buildUri, - assetTargetLocations, - buildMode, - fileSystem, - ); - final Uri nativeAssetsUri = await writeNativeAssetsYaml( - KernelAssets(assetTargetLocations.values.toList()), - yamlParentDirectory ?? buildUri, - fileSystem, - ); - return (nativeAssetsUri, dependencies.toList()); -} - -Map _assetTargetLocationsSingleArchitecture( - List nativeAssets, +Map _assetTargetLocationsWindowsLinux( + List assets, Uri? absolutePath, ) { - return { - for (final AssetImpl asset in nativeAssets) + return { + for (final NativeCodeAssetImpl asset in assets) asset: _targetLocationSingleArchitecture( asset, absolutePath, @@ -754,22 +569,17 @@ Map _assetTargetLocationsSingleArchitecture( } KernelAsset _targetLocationSingleArchitecture( - AssetImpl asset, Uri? absolutePath) { - if (asset is! NativeCodeAssetImpl) { - throw Exception( - 'Unsupported asset type ${asset.runtimeType}', - ); - } - final LinkModeImpl linkMode = asset.linkMode; + NativeCodeAssetImpl asset, Uri? absolutePath) { + final LinkMode linkMode = asset.linkMode; final KernelAssetPath kernelAssetPath; switch (linkMode) { - case DynamicLoadingSystemImpl _: + case DynamicLoadingSystem _: kernelAssetPath = KernelAssetSystemPath(linkMode.uri); - case LookupInExecutableImpl _: + case LookupInExecutable _: kernelAssetPath = KernelAssetInExecutable(); - case LookupInProcessImpl _: + case LookupInProcess _: kernelAssetPath = KernelAssetInProcess(); - case DynamicLoadingBundledImpl _: + case DynamicLoadingBundled _: final String fileName = asset.file!.pathSegments.last; Uri uri; if (absolutePath != null) { @@ -794,10 +604,240 @@ KernelAsset _targetLocationSingleArchitecture( ); } -/// Extract the [Target] from a [TargetPlatform]. +Map _assetTargetLocationsForOS(OS targetOS, + List codeAssets, bool flutterTester, Uri buildUri) { + switch (targetOS) { + case OS.windows: + case OS.linux: + final Uri? absolutePath = flutterTester ? buildUri : null; + return _assetTargetLocationsWindowsLinux(codeAssets, absolutePath); + case OS.macOS: + final Uri? absolutePath = flutterTester ? buildUri : null; + return assetTargetLocationsMacOS(codeAssets, absolutePath); + case OS.iOS: + return assetTargetLocationsIOS(codeAssets); + case OS.android: + return assetTargetLocationsAndroid(codeAssets); + default: + throw UnimplementedError('This should be unreachable.'); + } +} + +Future _copyNativeCodeAssetsForOS( + OS targetOS, + Uri buildUri, + build_info.BuildMode buildMode, + FileSystem fileSystem, + Map assetTargetLocations, + String? codesignIdentity, + bool flutterTester) async { + final List codeAssets = + assetTargetLocations.keys.toList(); + switch (targetOS) { + case OS.windows: + case OS.linux: + assert(codesignIdentity == null); + await _copyNativeCodeAssetsToBundleOnWindowsLinux( + buildUri, + assetTargetLocations, + buildMode, + fileSystem, + ); + case OS.macOS: + if (flutterTester) { + await copyNativeCodeAssetsMacOSFlutterTester( + buildUri, + fatAssetTargetLocationsMacOS(codeAssets, buildUri), + codesignIdentity, + buildMode, + fileSystem, + ); + } else { + await copyNativeCodeAssetsMacOS( + buildUri, + fatAssetTargetLocationsMacOS(codeAssets, null), + codesignIdentity, + buildMode, + fileSystem, + ); + } + case OS.iOS: + await copyNativeCodeAssetsIOS( + buildUri, + fatAssetTargetLocationsIOS(codeAssets), + codesignIdentity, + buildMode, + fileSystem, + ); + case OS.android: + assert(codesignIdentity == null); + await copyNativeCodeAssetsAndroid( + buildUri, assetTargetLocations, fileSystem); + default: + throw StateError('This should be unreachable.'); + } +} + +/// Invokes the build of all transitive Dart packages. /// -/// Does not cover MacOS, iOS, and Android as these pass the architecture -/// in other enums. +/// This will invoke `hook/build.dart` and `hook/link.dart` (if applicable) for +/// all transitive dart packages that define such hooks. +Future _runDartBuild({ + required Map environmentDefines, + required FlutterNativeAssetsBuildRunner buildRunner, + required List targets, + required Uri projectUri, + required BuildModeImpl buildMode, + required FileSystem fileSystem, + required OS targetOS, +}) async { + final bool linkingEnabled = buildMode == BuildMode.release; + final String targetString = targets.length == 1 + ? targets.single.toString() + : targets.toList().toString(); + globals.logger + .printTrace('Building native assets for $targetString $buildMode.'); + final List assets = []; + final Set dependencies = {}; + final build_info.EnvironmentType? environmentType; + if (targetOS == OS.iOS) { + final String? sdkRoot = environmentDefines[build_info.kSdkRoot]; + if (sdkRoot == null) { + throw MissingDefineException(build_info.kSdkRoot, 'native_assets'); + } + environmentType = xcode.environmentTypeFromSdkroot(sdkRoot, fileSystem); + } else { + environmentType = null; + } + + final CCompilerConfigImpl cCompilerConfig = targetOS == OS.android + ? await buildRunner.ndkCCompilerConfigImpl + : await buildRunner.cCompilerConfig; + + final String? codesignIdentity = environmentDefines[build_info.kCodesignIdentity]; + assert(codesignIdentity == null || targetOS == OS.iOS || targetOS == OS.macOS); + + final int? androidNdkApi = targetOS == OS.android ? targetAndroidNdkApi(environmentDefines) : null; + final int? iOSVersion = targetOS == OS.iOS ? targetIOSVersion : null; + final int? macOSVersion = targetOS == OS.macOS ? targetMacOSVersion : null; + final IOSSdkImpl? iOSSdkImpl = targetOS == OS.iOS ? getIOSSdk(environmentType!) : null; + + for (final Target target in targets) { + final BuildResult buildResult = await buildRunner.build( + linkModePreference: LinkModePreferenceImpl.dynamic, + target: target, + buildMode: buildMode, + workingDirectory: projectUri, + includeParentEnvironment: true, + linkingEnabled: linkingEnabled, + cCompilerConfig: cCompilerConfig, + targetAndroidNdkApi: androidNdkApi, + targetIOSVersion: iOSVersion, + targetMacOSVersion: macOSVersion, + targetIOSSdkImpl: iOSSdkImpl, + ); + if (!buildResult.success) { + _throwNativeAssetsBuildFailed(); + } + assets.addAll(buildResult.assets); + dependencies.addAll(buildResult.dependencies); + if (linkingEnabled) { + final LinkResult linkResult = await buildRunner.link( + linkModePreference: LinkModePreferenceImpl.dynamic, + target: target, + buildMode: buildMode, + workingDirectory: projectUri, + includeParentEnvironment: true, + buildResult: buildResult, + cCompilerConfig: cCompilerConfig, + targetAndroidNdkApi: androidNdkApi, + targetIOSVersion: iOSVersion, + targetMacOSVersion: macOSVersion, + targetIOSSdkImpl: iOSSdkImpl, + ); + if (!linkResult.success) { + _throwNativeAssetsLinkFailed(); + } + assets.addAll(linkResult.assets); + dependencies.addAll(linkResult.dependencies); + } + } + + final List codeAssets = + assets.whereType().toList(); + globals.logger + .printTrace('Building native assets for $targetString $buildMode done.'); + return DartBuildResult(codeAssets: codeAssets, dependencies: dependencies.toList()); +} + +Future _runDartDryRunBuild({ + required FlutterNativeAssetsBuildRunner buildRunner, + required Uri projectUri, + required FileSystem fileSystem, + required OSImpl targetOS, +}) async { + globals.logger.printTrace('Dry running native assets for $targetOS.'); + final List assets = []; + final Set dependencies = {}; + + final BuildDryRunResult buildResult = await buildRunner.buildDryRun( + linkModePreference: LinkModePreferenceImpl.dynamic, + targetOS: targetOS, + workingDirectory: projectUri, + includeParentEnvironment: true, + ); + if (!buildResult.success) { + _throwNativeAssetsBuildDryRunFailed(); + } + assets.addAll(buildResult.assets); + + final List codeAssets = + assets.whereType().toList(); + globals.logger.printTrace('Dry running native assets for $targetOS done.'); + return DartBuildResult(codeAssets: codeAssets, dependencies: dependencies.toList()); +} + +List _targetsForOS(build_info.TargetPlatform targetPlatform, + OS targetOS, Map environmentDefines) { + switch (targetOS) { + case OS.linux: + return [_getNativeTarget(targetPlatform)]; + case OS.windows: + return [_getNativeTarget(targetPlatform)]; + case OS.macOS: + final List darwinArchs = + _emptyToNull(environmentDefines[build_info.kDarwinArchs]) + ?.split(' ') + .map(build_info.getDarwinArchForName) + .toList() ?? + [ + build_info.DarwinArch.x86_64, + build_info.DarwinArch.arm64 + ]; + return darwinArchs.map(getNativeMacOSTarget).toList(); + case OS.android: + final String? androidArchsEnvironment = + environmentDefines[build_info.kAndroidArchs]; + final List androidArchs = _androidArchs( + targetPlatform, + androidArchsEnvironment, + ); + return androidArchs.map(getNativeAndroidTarget).toList(); + case OS.iOS: + final List iosArchs = + _emptyToNull(environmentDefines[build_info.kIosArchs]) + ?.split(' ') + .map(build_info.getIOSArchForName) + .toList() ?? + [build_info.DarwinArch.arm64]; + return iosArchs.map(getNativeIOSTarget).toList(); + default: + // TODO(dacoharkes): Implement other OSes. https://github.com/flutter/flutter/issues/129757 + // Write the file we claim to have in the [outputs]. + return []; + } +} + Target _getNativeTarget(build_info.TargetPlatform targetPlatform) { switch (targetPlatform) { case build_info.TargetPlatform.linux_x64: @@ -823,57 +863,124 @@ Target _getNativeTarget(build_info.TargetPlatform targetPlatform) { } } -Future _copyNativeAssetsSingleArchitecture( +Future _copyNativeCodeAssetsToBundleOnWindowsLinux( Uri buildUri, - Map assetTargetLocations, + Map assetTargetLocations, build_info.BuildMode buildMode, FileSystem fileSystem, ) async { + globals.logger.printTrace('copyNativeCodeAssetsToBundleOnWindowsLinux()'); if (assetTargetLocations.isNotEmpty) { globals.logger.printTrace('Copying native assets to ${buildUri.toFilePath()}.'); final Directory buildDir = fileSystem.directory(buildUri.toFilePath()); if (!buildDir.existsSync()) { buildDir.createSync(recursive: true); } - for (final MapEntry assetMapping in assetTargetLocations.entries) { + for (final MapEntry assetMapping in assetTargetLocations.entries) { final Uri source = assetMapping.key.file!; final Uri target = (assetMapping.value.path as KernelAssetAbsolutePath).uri; final Uri targetUri = buildUri.resolveUri(target); final String targetFullPath = targetUri.toFilePath(); await fileSystem.file(source).copy(targetFullPath); + globals.logger.printTrace('copyNativeCodeAssetsToBundleOnWindowsLinux(): copied $source to $targetFullPath'); } globals.logger.printTrace('Copying native assets done.'); } } -void ensureNativeAssetsBuildDryRunSucceed(BuildDryRunResult result) { - if (!result.success) { - throwToolExit( - 'Building (dry run) native assets failed. See the logs for more details.', - ); +Never _throwNativeAssetsBuildDryRunFailed() { + throwToolExit( + 'Building (dry run) native assets failed. See the logs for more details.', + ); +} + +Never _throwNativeAssetsBuildFailed() { + throwToolExit( + 'Building native assets failed. See the logs for more details.', + ); +} + +Never _throwNativeAssetsLinkFailed() { + throwToolExit( + 'Linking native assets failed. See the logs for more details.', + ); +} + + +OSImpl _getNativeOSFromTargetPlatfrorm(build_info.TargetPlatform platform) { + switch (platform) { + case build_info.TargetPlatform.ios: + return OSImpl.iOS; + case build_info.TargetPlatform.darwin: + return OSImpl.macOS; + case build_info.TargetPlatform.linux_x64: + case build_info.TargetPlatform.linux_arm64: + return OSImpl.linux; + case build_info.TargetPlatform.windows_x64: + case build_info.TargetPlatform.windows_arm64: + return OSImpl.windows; + case build_info.TargetPlatform.fuchsia_arm64: + case build_info.TargetPlatform.fuchsia_x64: + return OSImpl.fuchsia; + case build_info.TargetPlatform.android: + case build_info.TargetPlatform.android_arm: + case build_info.TargetPlatform.android_arm64: + case build_info.TargetPlatform.android_x64: + case build_info.TargetPlatform.android_x86: + return OSImpl.android; + case build_info.TargetPlatform.tester: + if (const LocalPlatform().isMacOS) { + return OSImpl.macOS; + } else if (const LocalPlatform().isLinux) { + return OSImpl.linux; + } else if (const LocalPlatform().isWindows) { + return OSImpl.windows; + } else { + throw StateError('Unknown operating system'); + } + case build_info.TargetPlatform.web_javascript: + throw StateError('No dart builds for web yet.'); } } -void ensureNativeAssetsBuildSucceed(BuildResult result) { - if (!result.success) { - throwToolExit( - 'Building native assets failed. See the logs for more details.', - ); +List _androidArchs( + build_info.TargetPlatform targetPlatform, + String? androidArchsEnvironment, +) { + switch (targetPlatform) { + case build_info.TargetPlatform.android_arm: + return [build_info.AndroidArch.armeabi_v7a]; + case build_info.TargetPlatform.android_arm64: + return [build_info.AndroidArch.arm64_v8a]; + case build_info.TargetPlatform.android_x64: + return [build_info.AndroidArch.x86_64]; + case build_info.TargetPlatform.android_x86: + return [build_info.AndroidArch.x86]; + case build_info.TargetPlatform.android: + if (androidArchsEnvironment == null) { + throw MissingDefineException(build_info.kAndroidArchs, 'native_assets'); + } + return androidArchsEnvironment + .split(' ') + .map(build_info.getAndroidArchForName) + .toList(); + case build_info.TargetPlatform.darwin: + case build_info.TargetPlatform.fuchsia_arm64: + case build_info.TargetPlatform.fuchsia_x64: + case build_info.TargetPlatform.ios: + case build_info.TargetPlatform.linux_arm64: + case build_info.TargetPlatform.linux_x64: + case build_info.TargetPlatform.tester: + case build_info.TargetPlatform.web_javascript: + case build_info.TargetPlatform.windows_x64: + case build_info.TargetPlatform.windows_arm64: + throwToolExit('Unsupported Android target platform: $targetPlatform.'); } } -void ensureNativeAssetsLinkDryRunSucceed(LinkDryRunResult result) { - if (!result.success) { - throwToolExit( - 'Linking (dry run) native assets failed. See the logs for more details.', - ); - } -} - -void ensureNativeAssetsLinkSucceed(LinkResult result) { - if (!result.success) { - throwToolExit( - 'Linking native assets failed. See the logs for more details.', - ); +String? _emptyToNull(String? input) { + if (input == null || input.isEmpty) { + return null; } + return input; } diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart index d62ca7c76c3..423c297670b 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/test/native_assets.dart @@ -6,16 +6,12 @@ import 'package:native_assets_cli/native_assets_cli.dart'; -import '../../../base/os.dart'; import '../../../base/platform.dart'; import '../../../build_info.dart'; import '../../../globals.dart' as globals; import '../../../native_assets.dart'; import '../../../project.dart'; -import '../linux/native_assets.dart'; -import '../macos/native_assets.dart'; import '../native_assets.dart'; -import '../windows/native_assets.dart'; class TestCompilerNativeAssetsBuilderImpl implements TestCompilerNativeAssetsBuilder { @@ -31,57 +27,36 @@ class TestCompilerNativeAssetsBuilderImpl } Future testCompilerBuildNativeAssets(BuildInfo buildInfo) async { - Uri? nativeAssetsYaml; if (!buildInfo.buildNativeAssets) { - nativeAssetsYaml = null; - } else { - final Uri projectUri = FlutterProject.current().directory.uri; - final NativeAssetsBuildRunner buildRunner = NativeAssetsBuildRunnerImpl( - projectUri, - buildInfo.packageConfigPath, - buildInfo.packageConfig, - globals.fs, - globals.logger, - ); - if (globals.platform.isMacOS) { - (nativeAssetsYaml, _) = await buildNativeAssetsMacOS( - buildMode: buildInfo.mode, - projectUri: projectUri, - flutterTester: true, - fileSystem: globals.fs, - buildRunner: buildRunner, - ); - } else if (globals.platform.isLinux) { - (nativeAssetsYaml, _) = await buildNativeAssetsLinux( - buildMode: buildInfo.mode, - projectUri: projectUri, - flutterTester: true, - fileSystem: globals.fs, - buildRunner: buildRunner, - ); - } else if (globals.platform.isWindows) { - final TargetPlatform targetPlatform; - if (globals.os.hostPlatform == HostPlatform.windows_x64) { - targetPlatform = TargetPlatform.windows_x64; - } else { - targetPlatform = TargetPlatform.windows_arm64; - } - (nativeAssetsYaml, _) = await buildNativeAssetsWindows( - buildMode: buildInfo.mode, - targetPlatform: targetPlatform, - projectUri: projectUri, - flutterTester: true, - fileSystem: globals.fs, - buildRunner: buildRunner, - ); - } else { - await ensureNoNativeAssetsOrOsIsSupported( - projectUri, - const LocalPlatform().operatingSystem, - globals.fs, - buildRunner, - ); - } + return null; } + final Uri projectUri = FlutterProject.current().directory.uri; + final FlutterNativeAssetsBuildRunner buildRunner = FlutterNativeAssetsBuildRunnerImpl( + projectUri, + buildInfo.packageConfigPath, + buildInfo.packageConfig, + globals.fs, + globals.logger, + ); + + if (!globals.platform.isMacOS && + !globals.platform.isLinux && + !globals.platform.isWindows) { + await ensureNoNativeAssetsOrOsIsSupported( + projectUri, + const LocalPlatform().operatingSystem, + globals.fs, + buildRunner, + ); + return null; + } + final (_, Uri nativeAssetsYaml) = await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: buildInfo.mode.cliName, + }, + buildRunner: buildRunner, + targetPlatform: TargetPlatform.tester, + projectUri: projectUri, + fileSystem: globals.fs); return nativeAssetsYaml; } diff --git a/packages/flutter_tools/lib/src/isolated/native_assets/windows/native_assets.dart b/packages/flutter_tools/lib/src/isolated/native_assets/windows/native_assets.dart index 11703c4f288..f61b1bc76d3 100644 --- a/packages/flutter_tools/lib/src/isolated/native_assets/windows/native_assets.dart +++ b/packages/flutter_tools/lib/src/isolated/native_assets/windows/native_assets.dart @@ -2,70 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'package:native_assets_builder/native_assets_builder.dart' - hide NativeAssetsBuildRunner; import 'package:native_assets_cli/native_assets_cli_internal.dart'; -import '../../../base/file_system.dart'; -import '../../../build_info.dart'; import '../../../globals.dart' as globals; import '../../../windows/visual_studio.dart'; -import '../native_assets.dart'; - -/// Dry run the native builds. -/// -/// This does not build native assets, it only simulates what the final paths -/// of all assets will be so that this can be embedded in the kernel file. -Future dryRunNativeAssetsWindows({ - required NativeAssetsBuildRunner buildRunner, - required Uri projectUri, - bool flutterTester = false, - required FileSystem fileSystem, -}) { - return dryRunNativeAssetsSingleArchitecture( - buildRunner: buildRunner, - projectUri: projectUri, - flutterTester: flutterTester, - fileSystem: fileSystem, - os: OSImpl.windows, - ); -} - -Future> dryRunNativeAssetsWindowsInternal( - FileSystem fileSystem, - Uri projectUri, - bool flutterTester, - NativeAssetsBuildRunner buildRunner, -) { - return dryRunNativeAssetsSingleArchitectureInternal( - fileSystem, - projectUri, - flutterTester, - buildRunner, - OSImpl.windows, - ); -} - -Future<(Uri? nativeAssetsYaml, List dependencies)> - buildNativeAssetsWindows({ - required NativeAssetsBuildRunner buildRunner, - TargetPlatform? targetPlatform, - required Uri projectUri, - required BuildMode buildMode, - bool flutterTester = false, - Uri? yamlParentDirectory, - required FileSystem fileSystem, -}) { - return buildNativeAssetsSingleArchitecture( - buildRunner: buildRunner, - targetPlatform: targetPlatform, - projectUri: projectUri, - buildMode: buildMode, - flutterTester: flutterTester, - yamlParentDirectory: yamlParentDirectory, - fileSystem: fileSystem, - ); -} Future cCompilerConfigWindows() async { final VisualStudio visualStudio = VisualStudio( diff --git a/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart index 3d0a03251d0..587a2a47a1f 100644 --- a/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/android/native_assets_test.dart @@ -5,6 +5,7 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; +import 'package:flutter_tools/src/android/gradle_utils.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -14,7 +15,7 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:flutter_tools/src/isolated/native_assets/android/native_assets.dart'; +import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart'; import 'package:package_config/package_config_types.dart'; @@ -48,173 +49,6 @@ void main() { projectUri = environment.projectDir.uri; }); - testUsingContext('dry run with no package config', overrides: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - expect( - await dryRunNativeAssetsAndroid( - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await buildNativeAssetsAndroid( - androidArchs: [AndroidArch.arm64_v8a], - targetAndroidNdkApi: 21, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => dryRunNativeAssetsAndroid( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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 FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: FakeNativeAssetsBuilderResult( - assets: [ - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.macOS, - architecture: ArchitectureImpl.arm64, - file: Uri.file('libbar.so'), - ), - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.macOS, - architecture: ArchitectureImpl.x64, - file: Uri.file('libbar.so'), - ), - ], - ), - ); - final Uri? nativeAssetsYaml = await dryRunNativeAssetsAndroid( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - expect( - (globals.logger as BufferLogger).traceText, - stringContainsInOrder([ - 'Dry running native assets for android.', - 'Dry running native assets for android done.', - ]), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/android/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - contains('package:bar/bar.dart'), - ); - expect(buildRunner.buildDryRunInvocations, 1); - expect(buildRunner.linkDryRunInvocations, 0); - }); - - testUsingContext('build with assets but not enabled', () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => buildNativeAssetsAndroid( - androidArchs: [AndroidArch.arm64_v8a], - targetAndroidNdkApi: 21, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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(); - await buildNativeAssetsAndroid( - androidArchs: [AndroidArch.arm64_v8a], - targetAndroidNdkApi: 21, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - ), - ); - expect( - environment.buildDir.childFile('native_assets.yaml'), - exists, - ); - }); - for (final BuildMode buildMode in [ BuildMode.debug, BuildMode.release, @@ -227,17 +61,17 @@ void main() { }, () async { final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; await packageConfig.parent.create(); await packageConfig.create(); final File dylibAfterCompiling = fileSystem.file('libbar.so'); // The mock doesn't create the file, so create it here. await dylibAfterCompiling.create(); - final FakeNativeAssetsBuildRunner buildRunner = - FakeNativeAssetsBuildRunner( + final FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: [ Package('bar', projectUri), ], - buildResult: FakeNativeAssetsBuilderResult( + buildResult: FakeFlutterNativeAssetsBuilderResult( assets: [ NativeCodeAssetImpl( id: 'package:bar/bar.dart', @@ -249,22 +83,25 @@ void main() { ], ), ); - await buildNativeAssetsAndroid( - androidArchs: [AndroidArch.arm64_v8a], - targetAndroidNdkApi: 21, + await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: buildMode.cliName, + kMinSdkVersion: minSdkVersion, + }, + targetPlatform: TargetPlatform.android_arm64, projectUri: projectUri, - buildMode: buildMode, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, buildRunner: buildRunner, ); expect( (globals.logger as BufferLogger).traceText, stringContainsInOrder([ - 'Building native assets for [android_arm64] $buildMode.', - 'Building native assets for [android_arm64] done.', + 'Building native assets for android_arm64 $buildMode.', + 'Building native assets for android_arm64 $buildMode done.', ]), ); + expect( environment.buildDir.childFile('native_assets.yaml'), exists, @@ -287,12 +124,16 @@ void main() { }, () async { final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; await packageConfig.create(recursive: true); - await buildNativeAssetsAndroid( - androidArchs: [AndroidArch.x86_64], - targetAndroidNdkApi: 21, + await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: BuildMode.debug.cliName, + kMinSdkVersion: minSdkVersion, + }, + targetPlatform: TargetPlatform.android_x64, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, projectUri: projectUri, - buildMode: BuildMode.debug, fileSystem: fileSystem, buildRunner: _BuildRunnerWithoutNdk(), ); @@ -308,16 +149,19 @@ void main() { }, () async { final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; await packageConfig.parent.create(); await packageConfig.create(); expect( - () => buildNativeAssetsAndroid( - androidArchs: [AndroidArch.arm64_v8a], - targetAndroidNdkApi: 21, + () => runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: BuildMode.debug.cliName, + kMinSdkVersion: minSdkVersion, + }, + targetPlatform: TargetPlatform.android_arm64, projectUri: projectUri, - buildMode: BuildMode.debug, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, buildRunner: _BuildRunnerWithoutNdk( packagesWithNativeAssetsResult: [ Package('bar', projectUri), @@ -330,73 +174,9 @@ void main() { ); }); - testUsingContext('Native assets dry run error', overrides: { - 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( - () => dryRunNativeAssetsAndroid( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: const FakeNativeAssetsBuilderResult( - success: false, - ), - ), - ), - throwsToolExit( - message: - 'Building (dry run) native assets failed. See the logs for more details.', - ), - ); - }); - - testUsingContext('Native assets build error', overrides: { - 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(); - for (final String hook in ['Building', 'Linking']) { - expect( - () => buildNativeAssetsAndroid( - androidArchs: [AndroidArch.arm64_v8a], - targetAndroidNdkApi: 21, - projectUri: projectUri, - buildMode: BuildMode.release, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildResult: FakeNativeAssetsBuilderResult( - success: hook != 'Building', - ), - linkResult: FakeNativeAssetsBuilderResult( - success: hook != 'Linking', - ), - ), - ), - throwsToolExit( - message: - '$hook native assets failed. See the logs for more details.', - ), - ); - } - }); } -class _BuildRunnerWithoutNdk extends FakeNativeAssetsBuildRunner { +class _BuildRunnerWithoutNdk extends FakeFlutterNativeAssetsBuildRunner { _BuildRunnerWithoutNdk({ super.packagesWithNativeAssetsResult = const [], }); diff --git a/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart index c8210fe7a9e..fc687348226 100644 --- a/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/build_system/targets/native_assets_test.dart @@ -76,21 +76,29 @@ void main() { iosEnvironment.defines.remove(kIosArchs); - final NativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(); + final FlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner(); await NativeAssets(buildRunner: buildRunner).build(iosEnvironment); final File nativeAssetsYaml = iosEnvironment.buildDir.childFile('native_assets.yaml'); + final File depsFile = iosEnvironment.buildDir.childFile('native_assets.d'); expect(depsFile, exists); expect(nativeAssetsYaml, exists); }); - testUsingContext('NativeAssets throws error if missing sdk root', () async { + testUsingContext('NativeAssets throws error if missing sdk root', overrides: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + }, () async { await createPackageConfig(iosEnvironment); + final FlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('foo', iosEnvironment.projectDir.uri), + ]); + iosEnvironment.defines.remove(kSdkRoot); - expect(const NativeAssets().build(iosEnvironment), throwsA(isA())); + expect(NativeAssets(buildRunner: buildRunner).build(iosEnvironment), throwsA(isA())); }); // The NativeAssets Target should _always_ be creating a yaml an d file. @@ -109,7 +117,7 @@ void main() { () async { await createPackageConfig(iosEnvironment); - final NativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(); + final FlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner(); await NativeAssets(buildRunner: buildRunner).build(iosEnvironment); expect(iosEnvironment.buildDir.childFile('native_assets.d'), exists); @@ -182,9 +190,9 @@ void main() { () async { await createPackageConfig(iosEnvironment); - final NativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + final FlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: [Package('foo', iosEnvironment.buildDir.uri)], - buildResult: FakeNativeAssetsBuilderResult( + buildResult: FakeFlutterNativeAssetsBuilderResult( assets: [ native_assets_cli.NativeCodeAssetImpl( id: 'package:foo/foo.dart', @@ -243,11 +251,11 @@ void main() { await createPackageConfig(androidEnvironment); await fileSystem.file('libfoo.so').create(); - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + final FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: [ Package('foo', androidEnvironment.buildDir.uri) ], - buildResult: FakeNativeAssetsBuilderResult( + buildResult: FakeFlutterNativeAssetsBuilderResult( assets: [ if (hasAssets) native_assets_cli.NativeCodeAssetImpl( diff --git a/packages/flutter_tools/test/general.shard/isolated/fake_native_assets_build_runner.dart b/packages/flutter_tools/test/general.shard/isolated/fake_native_assets_build_runner.dart index 20bf8d1e1ce..339f6a7faa8 100644 --- a/packages/flutter_tools/test/general.shard/isolated/fake_native_assets_build_runner.dart +++ b/packages/flutter_tools/test/general.shard/isolated/fake_native_assets_build_runner.dart @@ -4,6 +4,7 @@ import 'package:file/file.dart'; import 'package:flutter_tools/src/base/logger.dart'; +import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/run_hot.dart'; @@ -14,15 +15,15 @@ import 'package:package_config/package_config_types.dart'; /// Mocks all logic instead of using `package:native_assets_builder`, which /// relies on doing process calls to `pub` and the local file system. -class FakeNativeAssetsBuildRunner implements NativeAssetsBuildRunner { - FakeNativeAssetsBuildRunner({ +class FakeFlutterNativeAssetsBuildRunner implements FlutterNativeAssetsBuildRunner { + FakeFlutterNativeAssetsBuildRunner({ this.hasPackageConfigResult = true, this.packagesWithNativeAssetsResult = const [], this.onBuild, - this.buildDryRunResult = const FakeNativeAssetsBuilderResult(), - this.buildResult = const FakeNativeAssetsBuilderResult(), - this.linkResult = const FakeNativeAssetsBuilderResult(), - this.linkDryRunResult = const FakeNativeAssetsBuilderResult(), + this.buildDryRunResult = const FakeFlutterNativeAssetsBuilderResult(), + this.buildResult = const FakeFlutterNativeAssetsBuilderResult(), + this.linkResult = const FakeFlutterNativeAssetsBuilderResult(), + this.linkDryRunResult = const FakeFlutterNativeAssetsBuilderResult(), CCompilerConfigImpl? cCompilerConfigResult, CCompilerConfigImpl? ndkCCompilerConfigImplResult, }) : cCompilerConfigResult = cCompilerConfigResult ?? CCompilerConfigImpl(), @@ -96,18 +97,6 @@ class FakeNativeAssetsBuildRunner implements NativeAssetsBuildRunner { return buildDryRunResult; } - @override - Future linkDryRun({ - required bool includeParentEnvironment, - required LinkModePreferenceImpl linkModePreference, - required OSImpl targetOS, - required Uri workingDirectory, - required native_assets_builder.BuildDryRunResult buildDryRunResult, - }) async { - linkDryRunInvocations++; - return linkDryRunResult; - } - @override Future hasPackageConfig() async { hasPackageConfigInvocations++; @@ -129,13 +118,13 @@ class FakeNativeAssetsBuildRunner implements NativeAssetsBuildRunner { cCompilerConfigResult; } -final class FakeNativeAssetsBuilderResult +final class FakeFlutterNativeAssetsBuilderResult implements native_assets_builder.BuildResult, native_assets_builder.BuildDryRunResult, native_assets_builder.LinkResult, native_assets_builder.LinkDryRunResult { - const FakeNativeAssetsBuilderResult({ + const FakeFlutterNativeAssetsBuilderResult({ this.assets = const [], this.assetsForLinking = const >{}, this.dependencies = const [], @@ -158,7 +147,7 @@ final class FakeNativeAssetsBuilderResult class FakeHotRunnerNativeAssetsBuilder implements HotRunnerNativeAssetsBuilder { FakeHotRunnerNativeAssetsBuilder(this.buildRunner); - final NativeAssetsBuildRunner buildRunner; + final FlutterNativeAssetsBuildRunner buildRunner; @override Future dryRun({ @@ -169,11 +158,15 @@ class FakeHotRunnerNativeAssetsBuilder implements HotRunnerNativeAssetsBuilder { required PackageConfig packageConfig, required Logger logger, }) { - return dryRunNativeAssets( + final List targetPlatforms = flutterDevices + .map((FlutterDevice d) => d.targetPlatform) + .nonNulls + .toList(); + return runFlutterSpecificDartDryRunOnPlatforms( projectUri: projectUri, fileSystem: fileSystem, buildRunner: buildRunner, - flutterDevices: flutterDevices, + targetPlatforms: targetPlatforms, ); } } diff --git a/packages/flutter_tools/test/general.shard/isolated/hot_test.dart b/packages/flutter_tools/test/general.shard/isolated/hot_test.dart index ff10468eec6..64aa9fbf787 100644 --- a/packages/flutter_tools/test/general.shard/isolated/hot_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/hot_test.dart @@ -58,11 +58,11 @@ void main() { (fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + final FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: [ Package('bar', fileSystem.currentDirectory.uri), ], - buildDryRunResult: FakeNativeAssetsBuilderResult( + buildDryRunResult: FakeFlutterNativeAssetsBuilderResult( assets: [ NativeCodeAssetImpl( id: 'package:bar/bar.dart', @@ -127,11 +127,11 @@ void main() { (fakeFlutterDevice.devFS! as FakeDevFs).baseUri = Uri.parse('file:///base_uri'); - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + final FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: [ Package('bar', fileSystem.currentDirectory.uri), ], - buildDryRunResult: FakeNativeAssetsBuilderResult( + buildDryRunResult: FakeFlutterNativeAssetsBuilderResult( assets: [ NativeCodeAssetImpl( id: 'package:bar/bar.dart', diff --git a/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart index 21bd6e6944b..da875d8d917 100644 --- a/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/ios/native_assets_test.dart @@ -13,9 +13,8 @@ import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_system/build_system.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; -import 'package:flutter_tools/src/isolated/native_assets/ios/native_assets.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - hide Target; +import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; +import 'package:native_assets_cli/native_assets_cli_internal.dart' hide Target; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:package_config/package_config_types.dart'; @@ -50,174 +49,6 @@ void main() { projectUri = environment.projectDir.uri; }); - testUsingContext('dry run with no package config', overrides: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - expect( - await dryRunNativeAssetsIOS( - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await buildNativeAssetsIOS( - darwinArchs: [DarwinArch.arm64], - environmentType: EnvironmentType.simulator, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => dryRunNativeAssetsIOS( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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 FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: FakeNativeAssetsBuilderResult( - assets: [ - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.macOS, - architecture: ArchitectureImpl.arm64, - file: Uri.file('libbar.dylib'), - ), - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.macOS, - architecture: ArchitectureImpl.x64, - file: Uri.file('libbar.dylib'), - ), - ], - ), - ); - final Uri? nativeAssetsYaml = await dryRunNativeAssetsIOS( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - expect( - (globals.logger as BufferLogger).traceText, - stringContainsInOrder([ - 'Dry running native assets for ios.', - 'Dry running native assets for ios done.', - ]), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/ios/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - contains('package:bar/bar.dart'), - ); - expect(buildRunner.buildDryRunInvocations, 1); - expect(buildRunner.linkDryRunInvocations, 0); - }); - - testUsingContext('build with assets but not enabled', () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => buildNativeAssetsIOS( - darwinArchs: [DarwinArch.arm64], - environmentType: EnvironmentType.simulator, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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(); - await buildNativeAssetsIOS( - darwinArchs: [DarwinArch.arm64], - environmentType: EnvironmentType.simulator, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - ), - ); - expect( - environment.buildDir.childFile('native_assets.yaml'), - exists, - ); - }); - - for (final BuildMode buildMode in [ BuildMode.debug, BuildMode.release, @@ -330,15 +161,15 @@ void main() { } final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; await packageConfig.parent.create(); await packageConfig.create(); - final FakeNativeAssetsBuildRunner buildRunner = - FakeNativeAssetsBuildRunner( + final FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: [ Package('bar', projectUri), ], onBuild: (native_assets_cli.Target target) => - FakeNativeAssetsBuilderResult( + FakeFlutterNativeAssetsBuilderResult( assets: [ NativeCodeAssetImpl( id: 'package:bar/bar.dart', @@ -355,22 +186,25 @@ void main() { file: Uri.file('${target.architecture}/libbuz.dylib'), ), ], - ), + ), ); - await buildNativeAssetsIOS( - darwinArchs: [DarwinArch.arm64, DarwinArch.x86_64], - environmentType: EnvironmentType.simulator, + await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: buildMode.cliName, + kSdkRoot: '.../iPhone Simulator', + kIosArchs: 'arm64 x86_64', + }, + targetPlatform: TargetPlatform.ios, projectUri: projectUri, - buildMode: buildMode, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, buildRunner: buildRunner, ); expect( (globals.logger as BufferLogger).traceText, stringContainsInOrder([ 'Building native assets for [ios_arm64, ios_x64] $buildMode.', - 'Building native assets for [ios_arm64, ios_x64] done.', + 'Building native assets for [ios_arm64, ios_x64] $buildMode done.', ]), ); expect( @@ -385,69 +219,4 @@ void main() { ); }); } - - testUsingContext('Native assets dry run error', overrides: { - 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( - () => dryRunNativeAssetsIOS( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: const FakeNativeAssetsBuilderResult( - success: false, - ), - ), - ), - throwsToolExit( - message: - 'Building (dry run) native assets failed. See the logs for more details.', - ), - ); - }); - - testUsingContext('Native assets build error', overrides: { - 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(); - for (final String hook in ['Building', 'Linking']) { - expect( - () => buildNativeAssetsIOS( - darwinArchs: [DarwinArch.arm64], - environmentType: EnvironmentType.simulator, - projectUri: projectUri, - buildMode: BuildMode.release, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildResult: FakeNativeAssetsBuilderResult( - success: hook != 'Building', - ), - linkResult: FakeNativeAssetsBuilderResult( - success: hook != 'Linking', - ), - ), - ), - throwsToolExit( - message: - '$hook native assets failed. See the logs for more details.', - ), - ); - } - }); } diff --git a/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart index 793df6f7ec8..978e733c477 100644 --- a/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/linux/native_assets_test.dart @@ -4,7 +4,6 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; -import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -15,7 +14,6 @@ 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/isolated/native_assets/linux/native_assets.dart'; import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; import 'package:native_assets_cli/native_assets_cli_internal.dart' hide Target; @@ -51,51 +49,21 @@ void main() { projectUri = environment.projectDir.uri; }); - testUsingContext('dry run with no package config', overrides: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - expect( - await dryRunNativeAssetsLinux( - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await buildNativeAssetsLinux( - 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('does not throw if clang not present but no native assets present', overrides: { FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), ProcessManager: () => FakeProcessManager.empty(), }, () async { final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; await packageConfig.create(recursive: true); - await buildNativeAssetsLinux( + + await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: BuildMode.debug.cliName, + }, + targetPlatform: TargetPlatform.linux_x64, projectUri: projectUri, - buildMode: BuildMode.debug, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, fileSystem: fileSystem, buildRunner: _BuildRunnerWithoutClang(), ); @@ -105,300 +73,6 @@ void main() { ); }); - testUsingContext('dry run for multiple OSes with no package config', overrides: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await dryRunNativeAssetsMultipleOSes( - projectUri: projectUri, - fileSystem: fileSystem, - targetPlatforms: [ - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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 FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: FakeNativeAssetsBuilderResult( - assets: [ - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.linux, - architecture: ArchitectureImpl.x64, - file: Uri.file('libbar.so'), - ), - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.linux, - architecture: ArchitectureImpl.arm64, - file: Uri.file('libbar.so'), - ), - ], - ), - ); - final Uri? nativeAssetsYaml = await dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - expect( - (globals.logger as BufferLogger).traceText, - stringContainsInOrder([ - 'Dry running native assets for linux.', - 'Dry running native assets for linux done.', - ]), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/linux/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - contains('package:bar/bar.dart'), - ); - expect(buildRunner.buildDryRunInvocations, 1); - expect(buildRunner.linkDryRunInvocations, 0); - }); - - testUsingContext('build with assets but not enabled', overrides: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => buildNativeAssetsLinux( - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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 buildNativeAssetsLinux( - targetPlatform: TargetPlatform.linux_x64, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - ), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/linux/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - isNot(contains('package:bar/bar.dart')), - ); - expect( - environment.projectDir - .childDirectory('build') - .childDirectory('native_assets') - .childDirectory('linux'), - exists, - ); - }); - - for (final bool flutterTester in [false, true]) { - String testName = ''; - if (flutterTester) { - testName += ' flutter tester'; - } - for (final BuildMode buildMode in [ - BuildMode.debug, - BuildMode.release, - ]) { - testUsingContext('build with assets $buildMode$testName', - overrides: { - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir - .childDirectory('.dart_tool') - .childFile('package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - final File dylibAfterCompiling = fileSystem.file('libbar.so'); - // The mock doesn't create the file, so create it here. - await dylibAfterCompiling.create(); - final FakeNativeAssetsBuildRunner buildRunner = - FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildResult: FakeNativeAssetsBuilderResult( - assets: [ - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.linux, - architecture: ArchitectureImpl.x64, - file: dylibAfterCompiling.uri, - ), - ], - ), - ); - final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsLinux( - targetPlatform: TargetPlatform.linux_x64, - projectUri: projectUri, - buildMode: buildMode, - fileSystem: fileSystem, - flutterTester: flutterTester, - buildRunner: buildRunner, - ); - expect( - (globals.logger as BufferLogger).traceText, - stringContainsInOrder([ - 'Building native assets for linux_x64 $buildMode.', - 'Building native assets for linux_x64 done.', - ]), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/linux/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - stringContainsInOrder([ - '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/linux/libbar.so').toFilePath()}' - else - // Apps are a bundle with the dylibs on their dlopen path. - '- libbar.so', - ]), - ); - expect(buildRunner.buildInvocations, 1); - expect( - buildRunner.linkInvocations, - buildMode == BuildMode.release ? 1 : 0, - ); - }); - } - } - - testUsingContext('Native assets dry run error', overrides: { - 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( - () => dryRunNativeAssetsLinux( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: const FakeNativeAssetsBuilderResult( - success: false, - ), - ), - ), - throwsToolExit( - message: - 'Building (dry run) native assets failed. See the logs for more details.', - ), - ); - }); - - testUsingContext('Native assets build error', overrides: { - 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( - () => buildNativeAssetsLinux( - targetPlatform: TargetPlatform.linux_x64, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildResult: const FakeNativeAssetsBuilderResult( - success: false, - ), - ), - ), - throwsToolExit( - message: - 'Building native assets failed. See the logs for more details.', - ), - ); - }); - // 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. @@ -436,14 +110,14 @@ void main() { packageConfigFile, logger: environment.logger, ); - final NativeAssetsBuildRunner runner = - NativeAssetsBuildRunnerImpl(projectUri, packageConfigFile.path, packageConfig, fileSystem, logger); + final FlutterNativeAssetsBuildRunner runner = + FlutterNativeAssetsBuildRunnerImpl(projectUri, packageConfigFile.path, packageConfig, fileSystem, logger); final CCompilerConfigImpl result = await runner.cCompilerConfig; expect(result.compiler, Uri.file('/some/path/to/clang')); }); } -class _BuildRunnerWithoutClang extends FakeNativeAssetsBuildRunner { +class _BuildRunnerWithoutClang extends FakeFlutterNativeAssetsBuildRunner { @override Future get cCompilerConfig async => throwToolExit('Failed to find clang++ on the PATH.'); diff --git a/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart index 3d23fb8b66b..5a2ae7fad05 100644 --- a/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/macos/native_assets_test.dart @@ -13,10 +13,8 @@ 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/isolated/native_assets/macos/native_assets.dart'; import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - hide Target; +import 'package:native_assets_cli/native_assets_cli_internal.dart' hide Target; import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:package_config/package_config_types.dart'; @@ -51,207 +49,9 @@ void main() { projectUri = environment.projectDir.uri; }); - testUsingContext('dry run with no package config', overrides: { - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await buildNativeAssetsMacOS( - darwinArchs: [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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await dryRunNativeAssetsMultipleOSes( - projectUri: projectUri, - fileSystem: fileSystem, - targetPlatforms: [ - 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: { - 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('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: { - 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 FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: FakeNativeAssetsBuilderResult( - assets: [ - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.macOS, - architecture: ArchitectureImpl.arm64, - file: Uri.file('libbar.dylib'), - ), - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.macOS, - architecture: ArchitectureImpl.x64, - file: Uri.file('libbar.dylib'), - ), - ], - ), - ); - final Uri? nativeAssetsYaml = await dryRunNativeAssetsMacOS( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - expect( - (globals.logger as BufferLogger).traceText, - stringContainsInOrder([ - 'Dry running native assets for macos.', - 'Dry running native assets for macos done.', - ]), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/macos/native_assets.yaml'), - ); - final String nativeAssetsYamlContents = - await fileSystem.file(nativeAssetsYaml).readAsString(); - expect( - nativeAssetsYamlContents, - contains('package:bar/bar.dart'), - ); - expect(buildRunner.buildDryRunInvocations, 1); - expect(buildRunner.linkDryRunInvocations, 0); - // Check that the framework uri is identical for both archs. - final String pathSeparator = const LocalPlatform().pathSeparator; - expect( - nativeAssetsYamlContents, - stringContainsInOrder( - [ - 'bar.framework${pathSeparator}bar', - 'bar.framework${pathSeparator}bar', - ], - ), - ); - }); - - testUsingContext('build with assets but not enabled', overrides: { - 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.arm64], - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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.arm64], - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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 [false, true]) { + final bool isArm64 = native_assets_cli.ArchitectureImpl.current == ArchitectureImpl.arm64; + String testName = ''; if (flutterTester) { testName += ' flutter tester'; @@ -276,7 +76,7 @@ void main() { } for (final BuildMode buildMode in [ BuildMode.debug, - BuildMode.release, + if (!flutterTester) BuildMode.release, ]) { testUsingContext('build with assets $buildMode$testName', overrides: { FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), @@ -289,8 +89,7 @@ void main() { '-create', '-output', dylibPathBar, - 'arm64/libbar.dylib', - 'x64/libbar.dylib', + '${isArm64 ? 'arm64' : 'x64'}/libbar.dylib', ], ), FakeCommand( @@ -312,8 +111,7 @@ void main() { '-create', '-output', dylibPathBuz, - 'arm64/libbuz.dylib', - 'x64/libbuz.dylib', + '${isArm64 ? 'arm64' : 'x64'}/libbuz.dylib', ], ), FakeCommand( @@ -323,9 +121,7 @@ void main() { dylibPathBuz, ], stdout: [ - '$dylibPathBuz (architecture x86_64):', - '@rpath/libbuz.dylib', - '$dylibPathBuz (architecture arm64):', + '$dylibPathBuz (architecture ${isArm64 ? 'arm64' : 'x86_64'}):', '@rpath/libbuz.dylib', ].join('\n'), ), @@ -349,8 +145,7 @@ void main() { '--force', '--sign', '-', - if (buildMode == BuildMode.debug) - '--timestamp=none', + if (buildMode == BuildMode.debug) '--timestamp=none', signPathBar, ], ), @@ -361,7 +156,7 @@ void main() { dylibPathBuz, '-change', '@rpath/libbar.dylib', - dylibPathBar, + dylibPathBar, '-change', '@rpath/libbuz.dylib', signPathBuz, @@ -374,8 +169,7 @@ void main() { '--force', '--sign', '-', - if (buildMode == BuildMode.debug) - '--timestamp=none', + if (buildMode == BuildMode.debug) '--timestamp=none', signPathBuz, ], ), @@ -461,15 +255,27 @@ void main() { if (const LocalPlatform().isWindows) { return; // Backslashes in commands, but we will never run these commands on Windows. } + if (flutterTester && !const LocalPlatform().isMacOS) { + // The [runFlutterSpecificDartBuild] will - when given + // `TargetPlatform.tester` - enable `flutter test` mode. That means if + // this test is run on linux, it's going to do a linux build. + // Though this test is mac-specific, so we skip that. + // + // Running the test in `!flutterTester` mode still works on linux as + // we explicitly tell it to do a mac build (instead of letting it + // choose the local build). + return; + } final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; await packageConfig.parent.create(); await packageConfig.create(); - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + final FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: [ Package('bar', projectUri), ], onBuild: (native_assets_cli.Target target) => - FakeNativeAssetsBuilderResult( + FakeFlutterNativeAssetsBuilderResult( assets: [ NativeCodeAssetImpl( id: 'package:bar/bar.dart', @@ -486,26 +292,34 @@ void main() { file: Uri.file('${target.architecture}/libbuz.dylib'), ), ], - ), + ), ); - final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsMacOS( - darwinArchs: [DarwinArch.arm64, DarwinArch.x86_64], + final (_, Uri nativeAssetsYaml) = await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: buildMode.cliName, + kDarwinArchs: 'arm64 x86_64', + }, + targetPlatform: flutterTester ? TargetPlatform.tester : TargetPlatform.darwin, projectUri: projectUri, - buildMode: buildMode, + nativeAssetsYamlUri: flutterTester ? null : nonFlutterTesterAssetUri, fileSystem: fileSystem, - flutterTester: flutterTester, buildRunner: buildRunner, ); + final String expectedArchsBeingBuilt = flutterTester + ? (isArm64 ? 'macos_arm64' : 'macos_x64') + : '[macos_arm64, macos_x64]'; expect( (globals.logger as BufferLogger).traceText, stringContainsInOrder([ - 'Building native assets for [macos_arm64, macos_x64] $buildMode.', - 'Building native assets for [macos_arm64, macos_x64] done.', + 'Building native assets for $expectedArchsBeingBuilt $buildMode.', + 'Building native assets for $expectedArchsBeingBuilt $buildMode done.', ]), ); expect( nativeAssetsYaml, - projectUri.resolve('build/native_assets/macos/native_assets.yaml'), + flutterTester + ? projectUri.resolve('build/native_assets/macos/native_assets.yaml') + : nonFlutterTesterAssetUri ); expect( await fileSystem.file(nativeAssetsYaml).readAsString(), @@ -513,10 +327,10 @@ void main() { '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/libbar.dylib').toFilePath()}' + projectUri.resolve('build/native_assets/macos/libbar.dylib').toFilePath() else // Apps are a bundle with the dylibs on their dlopen path. - '- bar.framework/bar', + 'bar.framework/bar', ]), ); expect( @@ -525,14 +339,14 @@ void main() { 'package:buz/buz.dart', if (flutterTester) // Tests run on host system, so the have the full path on the system. - '- ${projectUri.resolve('build/native_assets/macos/libbuz.dylib').toFilePath()}' + projectUri.resolve('build/native_assets/macos/libbuz.dylib').toFilePath() else // Apps are a bundle with the dylibs on their dlopen path. - '- buz.framework/buz', + 'buz.framework/buz', ]), ); // Multi arch. - expect(buildRunner.buildInvocations, 2); + expect(buildRunner.buildInvocations, flutterTester ? 1 : 2); expect( buildRunner.linkInvocations, buildMode == BuildMode.release ? 2 : 0, @@ -541,82 +355,24 @@ void main() { } } - testUsingContext('Native assets dry run error', overrides: { - 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('bar', projectUri), - ], - buildDryRunResult: const FakeNativeAssetsBuilderResult( - success: false, - ), - ), - ), - throwsToolExit( - message: - 'Building (dry run) native assets failed. See the logs for more details.', - ), - ); - }); - - testUsingContext('Native assets build error', overrides: { - 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( - () => buildNativeAssetsMacOS( - darwinArchs: [DarwinArch.arm64], - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildResult: const FakeNativeAssetsBuilderResult( - success: false, - ), - ), - ), - throwsToolExit( - message: - 'Building native assets failed. See the logs for more details.', - ), - ); - }); - // 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: { - FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), - ProcessManager: () => FakeProcessManager.list( - [ - const FakeCommand( - command: ['xcrun', 'clang', '--version'], - stdout: ''' + testUsingContext('NativeAssetsBuildRunnerImpl.cCompilerConfig', + overrides: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.list( + [ + const FakeCommand( + command: ['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) { return; @@ -632,7 +388,7 @@ InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault packageConfigFile, logger: environment.logger, ); - final NativeAssetsBuildRunner runner = NativeAssetsBuildRunnerImpl( + final FlutterNativeAssetsBuildRunner runner = FlutterNativeAssetsBuildRunnerImpl( projectUri, packageConfigFile.path, packageConfig, diff --git a/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart new file mode 100644 index 00000000000..5710e1da105 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/isolated/native_assets_test.dart @@ -0,0 +1,308 @@ +// 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:file_testing/file_testing.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/build_info.dart'; +import 'package:flutter_tools/src/build_system/build_system.dart'; +import 'package:flutter_tools/src/features.dart'; +import 'package:flutter_tools/src/globals.dart' as globals; +import 'package:flutter_tools/src/isolated/native_assets/native_assets.dart'; +import 'package:native_assets_cli/native_assets_cli_internal.dart'; +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: {}, + 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: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + expect( + await runFlutterSpecificDartDryRunOnPlatforms( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: [TargetPlatform.windows_x64], + buildRunner: FakeFlutterNativeAssetsBuildRunner( + 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: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; + await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: BuildMode.debug.cliName, + }, + targetPlatform: TargetPlatform.windows_x64, + projectUri: projectUri, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, + fileSystem: fileSystem, + buildRunner: FakeFlutterNativeAssetsBuildRunner( + 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: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + await runFlutterSpecificDartDryRunOnPlatforms( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: [ + TargetPlatform.windows_x64, + TargetPlatform.darwin, + TargetPlatform.ios, + ], + buildRunner: FakeFlutterNativeAssetsBuildRunner( + 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: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => runFlutterSpecificDartDryRunOnPlatforms( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: [TargetPlatform.windows_x64], + buildRunner: FakeFlutterNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + 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: { + 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 FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + buildDryRunResult: FakeFlutterNativeAssetsBuilderResult( + assets: [ + NativeCodeAssetImpl( + id: 'package:bar/bar.dart', + linkMode: DynamicLoadingBundledImpl(), + os: OSImpl.windows, + architecture: ArchitectureImpl.x64, + file: Uri.file('bar.dll'), + ), + ], + ), + ); + final Uri? nativeAssetsYaml = await runFlutterSpecificDartDryRunOnPlatforms( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: [TargetPlatform.windows_x64], + buildRunner: buildRunner, + ); + expect( + (globals.logger as BufferLogger).traceText, + stringContainsInOrder([ + 'Dry running native assets for windows.', + 'Dry running native assets for windows done.', + ]), + ); + expect( + nativeAssetsYaml, + projectUri.resolve('build/native_assets/windows/native_assets.yaml'), + ); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + contains('package:bar/bar.dart'), + ); + expect(buildRunner.buildDryRunInvocations, 1); + }); + + testUsingContext('build with assets but not enabled', overrides: { + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: BuildMode.debug.cliName, + }, + targetPlatform: TargetPlatform.windows_x64, + projectUri: projectUri, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, + fileSystem: fileSystem, + buildRunner: FakeFlutterNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + 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: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; + await packageConfig.parent.create(); + await packageConfig.create(); + final (_, Uri nativeAssetsYaml) = await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: BuildMode.debug.cliName, + }, + targetPlatform: TargetPlatform.windows_x64, + projectUri: projectUri, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, + fileSystem: fileSystem, + buildRunner: FakeFlutterNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + ), + ); + expect(nativeAssetsYaml, nonFlutterTesterAssetUri); + expect( + await fileSystem.file(nativeAssetsYaml).readAsString(), + isNot(contains('package:bar/bar.dart')), + ); + expect( + environment.projectDir.childDirectory('build').childDirectory('native_assets').childDirectory('windows'), + exists, + ); + }); + + testUsingContext('Native assets dry run error', overrides: { + 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( + () => runFlutterSpecificDartDryRunOnPlatforms( + projectUri: projectUri, + fileSystem: fileSystem, + targetPlatforms: [TargetPlatform.windows_x64], + buildRunner: FakeFlutterNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + buildDryRunResult: const FakeFlutterNativeAssetsBuilderResult( + success: false, + ), + ), + ), + throwsToolExit( + message: + 'Building (dry run) native assets failed. See the logs for more details.', + ), + ); + }); + + testUsingContext('Native assets build error', overrides: { + FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), + ProcessManager: () => FakeProcessManager.empty(), + }, () async { + final File packageConfig = + environment.projectDir.childFile('.dart_tool/package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; + await packageConfig.parent.create(); + await packageConfig.create(); + expect( + () => runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: BuildMode.debug.cliName, + }, + targetPlatform: TargetPlatform.linux_x64, + projectUri: projectUri, + nativeAssetsYamlUri: nonFlutterTesterAssetUri, + fileSystem: fileSystem, + buildRunner: FakeFlutterNativeAssetsBuildRunner( + packagesWithNativeAssetsResult: [ + Package('bar', projectUri), + ], + buildResult: const FakeFlutterNativeAssetsBuilderResult( + success: false, + ), + ), + ), + throwsToolExit( + message: + 'Building native assets failed. See the logs for more details.', + ), + ); + }); + +} diff --git a/packages/flutter_tools/test/general.shard/isolated/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/isolated/resident_runner_test.dart index 362af175090..abf01d853ac 100644 --- a/packages/flutter_tools/test/general.shard/isolated/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/resident_runner_test.dart @@ -56,7 +56,7 @@ void main() { globals.fs .file(globals.fs.path.join('lib', 'main.dart')) .createSync(recursive: true); - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner(); + final FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner(); final HotRunner residentRunner = HotRunner( [ flutterDevice, diff --git a/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart b/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart index 45c35d8a147..2eb7bf9b76f 100644 --- a/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart +++ b/packages/flutter_tools/test/general.shard/isolated/windows/native_assets_test.dart @@ -4,7 +4,6 @@ import 'package:file/file.dart'; import 'package:file/memory.dart'; -import 'package:file_testing/file_testing.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'; @@ -15,9 +14,8 @@ 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/isolated/native_assets/native_assets.dart'; -import 'package:flutter_tools/src/isolated/native_assets/windows/native_assets.dart'; -import 'package:native_assets_cli/native_assets_cli_internal.dart' - hide Target; +import 'package:native_assets_cli/native_assets_cli_internal.dart'; +import 'package:native_assets_cli/native_assets_cli_internal.dart' as native_assets_cli; import 'package:package_config/package_config_types.dart'; import '../../../src/common.dart'; @@ -50,187 +48,6 @@ void main() { projectUri = environment.projectDir.uri; }); - testUsingContext('dry run with no package config', overrides: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - expect( - await dryRunNativeAssetsWindows( - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await buildNativeAssetsWindows( - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - await dryRunNativeAssetsMultipleOSes( - projectUri: projectUri, - fileSystem: fileSystem, - targetPlatforms: [ - TargetPlatform.windows_x64, - ], - 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: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => dryRunNativeAssetsWindows( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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 FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: FakeNativeAssetsBuilderResult( - assets: [ - NativeCodeAssetImpl( - id: 'package:bar/bar.dart', - linkMode: DynamicLoadingBundledImpl(), - os: OSImpl.windows, - architecture: ArchitectureImpl.x64, - file: Uri.file('bar.dll'), - ), - ], - ), - ); - final Uri? nativeAssetsYaml = await dryRunNativeAssetsWindows( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: buildRunner, - ); - expect( - (globals.logger as BufferLogger).traceText, - stringContainsInOrder([ - 'Dry running native assets for windows.', - 'Dry running native assets for windows done.', - ]), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/windows/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - contains('package:bar/bar.dart'), - ); - expect(buildRunner.buildDryRunInvocations, 1); - expect(buildRunner.linkDryRunInvocations, 0); - }); - - testUsingContext('build with assets but not enabled', overrides: { - ProcessManager: () => FakeProcessManager.empty(), - }, () async { - final File packageConfig = environment.projectDir.childFile('.dart_tool/package_config.json'); - await packageConfig.parent.create(); - await packageConfig.create(); - expect( - () => buildNativeAssetsWindows( - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - 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: { - 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 buildNativeAssetsWindows( - targetPlatform: TargetPlatform.windows_x64, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - ), - ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/windows/native_assets.yaml'), - ); - expect( - await fileSystem.file(nativeAssetsYaml).readAsString(), - isNot(contains('package:bar/bar.dart')), - ); - expect( - environment.projectDir.childDirectory('build').childDirectory('native_assets').childDirectory('windows'), - exists, - ); - }); - for (final bool flutterTester in [false, true]) { String testName = ''; if (flutterTester) { @@ -238,23 +55,33 @@ void main() { } for (final BuildMode buildMode in [ BuildMode.debug, - BuildMode.release, + if (!flutterTester) BuildMode.release, ]) { + if (flutterTester && !const LocalPlatform().isWindows) { + // When calling [runFlutterSpecificDartBuild] with the flutter tester + // target platform, it will perform a build for the local machine. That + // means e.g. running this test on MacOS will cause it to run a MacOS + // build - which in return requires a special [ProcessManager] that can + // simulate output of `otool` invocations. + continue; + } + testUsingContext('build with assets $buildMode$testName', overrides: { FeatureFlags: () => TestFeatureFlags(isNativeAssetsEnabled: true), ProcessManager: () => FakeProcessManager.empty(), }, () async { final File packageConfig = environment.projectDir.childDirectory('.dart_tool').childFile('package_config.json'); + final Uri nonFlutterTesterAssetUri = environment.buildDir.childFile('native_assets.yaml').uri; await packageConfig.parent.create(); await packageConfig.create(); final File dylibAfterCompiling = fileSystem.file('bar.dll'); // The mock doesn't create the file, so create it here. await dylibAfterCompiling.create(); - final FakeNativeAssetsBuildRunner buildRunner = FakeNativeAssetsBuildRunner( + final FakeFlutterNativeAssetsBuildRunner buildRunner = FakeFlutterNativeAssetsBuildRunner( packagesWithNativeAssetsResult: [ Package('bar', projectUri), ], - buildResult: FakeNativeAssetsBuilderResult( + buildResult: FakeFlutterNativeAssetsBuilderResult( assets: [ NativeCodeAssetImpl( id: 'package:bar/bar.dart', @@ -266,24 +93,35 @@ void main() { ], ), ); - final (Uri? nativeAssetsYaml, _) = await buildNativeAssetsWindows( - targetPlatform: TargetPlatform.windows_x64, + final (_, Uri nativeAssetsYaml) = await runFlutterSpecificDartBuild( + environmentDefines: { + kBuildMode: buildMode.cliName, + }, + targetPlatform: flutterTester + ? TargetPlatform.tester + : TargetPlatform.windows_x64, projectUri: projectUri, - buildMode: buildMode, + nativeAssetsYamlUri: flutterTester ? null : nonFlutterTesterAssetUri, fileSystem: fileSystem, - flutterTester: flutterTester, buildRunner: buildRunner, ); + final String expectedOS = flutterTester + ? native_assets_cli.Target.current.toString() + : 'windows_x64'; expect( (globals.logger as BufferLogger).traceText, stringContainsInOrder([ - 'Building native assets for windows_x64 $buildMode.', - 'Building native assets for windows_x64 done.', + 'Building native assets for $expectedOS $buildMode.', + 'Building native assets for $expectedOS $buildMode done.', ]), ); - expect( - nativeAssetsYaml, - projectUri.resolve('build/native_assets/windows/native_assets.yaml'), + final String expectedDirectory = flutterTester + ? native_assets_cli.OSImpl.current.toString() + : 'windows'; + expect(nativeAssetsYaml, + flutterTester + ? projectUri.resolve('build/native_assets/$expectedDirectory/native_assets.yaml') + : nonFlutterTesterAssetUri ); expect( await fileSystem.file(nativeAssetsYaml).readAsString(), @@ -291,80 +129,21 @@ void main() { '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/windows/bar.dll').toFilePath()}' + projectUri.resolve('build/native_assets/$expectedDirectory/bar.dll').toFilePath() else // Apps are a bundle with the dylibs on their dlopen path. - '- bar.dll', + 'bar.dll', ]), ); expect(buildRunner.buildInvocations, 1); expect( buildRunner.linkInvocations, - buildMode == BuildMode.release ? 1 :0, + buildMode == BuildMode.release ? 1 : 0, ); }); } } - testUsingContext('Native assets dry run error', overrides: { - 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( - () => dryRunNativeAssetsWindows( - projectUri: projectUri, - fileSystem: fileSystem, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildDryRunResult: const FakeNativeAssetsBuilderResult( - success: false, - ), - ), - ), - throwsToolExit( - message: - 'Building (dry run) native assets failed. See the logs for more details.', - ), - ); - }); - - testUsingContext('Native assets build error', overrides: { - 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( - () => buildNativeAssetsWindows( - targetPlatform: TargetPlatform.windows_x64, - projectUri: projectUri, - buildMode: BuildMode.debug, - fileSystem: fileSystem, - yamlParentDirectory: environment.buildDir.uri, - buildRunner: FakeNativeAssetsBuildRunner( - packagesWithNativeAssetsResult: [ - Package('bar', projectUri), - ], - buildResult: const FakeNativeAssetsBuilderResult( - success: false, - ), - ), - ), - throwsToolExit( - message: - 'Building native assets failed. See the logs for more details.', - ), - ); - }); - // 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. @@ -453,17 +232,14 @@ void main() { fileSystem.directory(r'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\bin\Hostx64\x64'); await msvcBinDir.create(recursive: true); - final File packageConfigFile = fileSystem - .directory(projectUri) - .childDirectory('.dart_tool') - .childFile('package_config.json'); + final File packageConfigFile = fileSystem.directory(projectUri).childDirectory('.dart_tool').childFile('package_config.json'); await packageConfigFile.parent.create(); await packageConfigFile.create(); final PackageConfig packageConfig = await loadPackageConfigWithLogging( packageConfigFile, logger: environment.logger, ); - final NativeAssetsBuildRunner runner = NativeAssetsBuildRunnerImpl( + final FlutterNativeAssetsBuildRunner runner = FlutterNativeAssetsBuildRunnerImpl( projectUri, packageConfigFile.path, packageConfig,