From 540559204e561b7726cda7d691402cbd9ddf6836 Mon Sep 17 00:00:00 2001 From: Pierrick Bouvier <101587250+pbo-linaro@users.noreply.github.com> Date: Thu, 18 Jan 2024 23:15:23 +0400 Subject: [PATCH] Enable native compilation for windows-arm64 (#137618) It's now possible to natively compile a flutter app for windows-arm64. Cross-compilation is not yet implemented. Uses arm64 artifacts now available for Dart/Flutter. Platform detection is based on Abi class, provided by Dart. Depending if Dart is an arm64 or x64 binary, the Abi is set accordingly. Initial bootstrap of dart artifacts (update_dart_sdk.ps1) is checking PROCESSOR_ARCHITECTURE environment variable, which is the way to detect host architecture on Windows. This is available only for master channel (on other channels, it fallbacks to windows-x64). On windows-x64, it produces an x64 app. On windows-arm64, it produces an arm64 app. --- bin/internal/update_dart_sdk.ps1 | 17 +++++- dev/devicelab/lib/tasks/perf_tests.dart | 7 ++- dev/devicelab/lib/tasks/plugin_tests.dart | 4 +- dev/devicelab/lib/tasks/run_tests.dart | 7 ++- packages/flutter_tools/bin/tool_backend.dart | 2 +- .../lib/src/android/android_device.dart | 2 + packages/flutter_tools/lib/src/artifacts.dart | 15 ++++-- .../flutter_tools/lib/src/base/build.dart | 1 + packages/flutter_tools/lib/src/base/os.dart | 22 ++++++-- .../flutter_tools/lib/src/build_info.dart | 7 +++ .../lib/src/build_system/targets/common.dart | 3 +- .../build_system/targets/native_assets.dart | 2 + .../build_system/targets/shader_compiler.dart | 1 + .../lib/src/build_system/targets/windows.dart | 38 +++++++------ .../lib/src/commands/assemble.dart | 12 +++-- .../flutter_tools/lib/src/commands/build.dart | 6 ++- .../lib/src/commands/build_bundle.dart | 2 + .../lib/src/commands/build_preview.dart | 2 + .../lib/src/commands/build_windows.dart | 13 ++++- .../flutter_tools/lib/src/context_runner.dart | 1 + .../lib/src/flutter_application_package.dart | 1 + .../flutter_tools/lib/src/flutter_cache.dart | 28 +++++----- .../flutter_tools/lib/src/mdns_discovery.dart | 1 + .../flutter_tools/lib/src/native_assets.dart | 6 ++- .../lib/src/resident_runner.dart | 1 + .../lib/src/runner/flutter_command.dart | 1 + .../flutter_tools/lib/src/sksl_writer.dart | 1 + .../lib/src/test/test_compiler.dart | 8 +++ .../lib/src/windows/application_package.dart | 8 +-- .../lib/src/windows/build_windows.dart | 33 +++++++----- .../lib/src/windows/native_assets.dart | 1 + .../lib/src/windows/visual_studio.dart | 16 ++++-- .../lib/src/windows/windows_device.dart | 15 ++++-- .../hermetic/build_windows_test.dart | 53 ++++++++++--------- .../test/general.shard/base/os_test.dart | 2 +- .../build_system/targets/windows_test.dart | 8 +-- .../test/general.shard/cache_test.dart | 2 +- .../general.shard/commands/build_test.dart | 2 +- .../windows/visual_studio_test.dart | 5 ++ .../windows/windows_device_test.dart | 2 +- .../flutter_build_windows_test.dart | 10 +++- 41 files changed, 258 insertions(+), 110 deletions(-) diff --git a/bin/internal/update_dart_sdk.ps1 b/bin/internal/update_dart_sdk.ps1 index 9dbef7cf5c9..cb95257d920 100644 --- a/bin/internal/update_dart_sdk.ps1 +++ b/bin/internal/update_dart_sdk.ps1 @@ -47,7 +47,22 @@ if (-not $dartSdkBaseUrl) { if ($engineRealm) { $dartSdkBaseUrl = "$dartSdkBaseUrl/$engineRealm" } -$dartZipName = "dart-sdk-windows-x64.zip" + +# It's important to use the native Dart SDK as the default target architecture +# for Flutter Windows builds depend on the Dart executable's architecture. +$dartZipNameX64 = "dart-sdk-windows-x64.zip" +$dartZipNameArm64 = "dart-sdk-windows-arm64.zip" +$dartZipName = $dartZipNameX64 +if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") { + $dartSdkArm64Url = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipNameArm64" + Try { + Invoke-WebRequest -Uri $dartSdkArm64Url -UseBasicParsing -Method Head | Out-Null + $dartZipName = $dartZipNameArm64 + } + Catch { + Write-Host "The current channel's Dart SDK does not support Windows Arm64, falling back to Windows x64..." + } +} $dartSdkUrl = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipName" if ((Test-Path $dartSdkPath) -or (Test-Path $dartSdkLicense)) { diff --git a/dev/devicelab/lib/tasks/perf_tests.dart b/dev/devicelab/lib/tasks/perf_tests.dart index 85078dd97e4..71462ce5e8a 100644 --- a/dev/devicelab/lib/tasks/perf_tests.dart +++ b/dev/devicelab/lib/tasks/perf_tests.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert' show LineSplitter, json, utf8; +import 'dart:ffi' show Abi; import 'dart:io'; import 'dart:math' as math; @@ -953,11 +954,12 @@ class StartupTest { '--target=$target', ]); final String basename = path.basename(testDirectory); + final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64'; applicationBinaryPath = path.join( testDirectory, 'build', 'windows', - 'x64', + arch, 'runner', 'Profile', '$basename.exe' @@ -1763,11 +1765,12 @@ class CompileTest { await flutter('build', options: options); watch.stop(); final String basename = path.basename(cwd); + final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64'; final String exePath = path.join( cwd, 'build', 'windows', - 'x64', + arch, 'runner', 'release', '$basename.exe'); diff --git a/dev/devicelab/lib/tasks/plugin_tests.dart b/dev/devicelab/lib/tasks/plugin_tests.dart index 2f9943c57e5..7179ecd8b5b 100644 --- a/dev/devicelab/lib/tasks/plugin_tests.dart +++ b/dev/devicelab/lib/tasks/plugin_tests.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ffi'; import 'dart:io'; import 'package:path/path.dart' as path; @@ -328,8 +329,9 @@ public class $pluginClass: NSObject, FlutterPlugin { throw TaskResult.failure('Platform unit tests failed'); } case 'windows': + final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64'; if (await exec( - path.join(rootPath, 'build', 'windows', 'x64', 'plugins', 'plugintest', 'Release', 'plugintest_test.exe'), + path.join(rootPath, 'build', 'windows', arch, 'plugins', 'plugintest', 'Release', 'plugintest_test.exe'), [], canFail: true, ) != 0) { diff --git a/dev/devicelab/lib/tasks/run_tests.dart b/dev/devicelab/lib/tasks/run_tests.dart index a5c6f8c7547..1b1850a9f4a 100644 --- a/dev/devicelab/lib/tasks/run_tests.dart +++ b/dev/devicelab/lib/tasks/run_tests.dart @@ -4,6 +4,7 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:ffi'; import 'dart:io'; import '../framework/devices.dart'; @@ -173,12 +174,14 @@ class WindowsRunOutputTest extends DesktopRunOutputTest { } ); + final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64'; + static final RegExp _buildOutput = RegExp( r'Building Windows application\.\.\.\s*\d+(\.\d+)?(ms|s)', multiLine: true, ); static final RegExp _builtOutput = RegExp( - r'Built build\\windows\\x64\\runner\\(Debug|Release)\\\w+\.exe( \(\d+(\.\d+)?MB\))?\.', + r'Built build\\windows\\(x64|arm64)\\runner\\(Debug|Release)\\\w+\.exe( \(\d+(\.\d+)?MB\))?\.', ); @override @@ -205,7 +208,7 @@ class WindowsRunOutputTest extends DesktopRunOutputTest { return true; }, - 'Built build\\windows\\x64\\runner\\$buildMode\\app.exe', + 'Built build\\windows\\$arch\\runner\\$buildMode\\app.exe', ); } } diff --git a/packages/flutter_tools/bin/tool_backend.dart b/packages/flutter_tools/bin/tool_backend.dart index d98c7055477..8122864dcf6 100644 --- a/packages/flutter_tools/bin/tool_backend.dart +++ b/packages/flutter_tools/bin/tool_backend.dart @@ -76,7 +76,7 @@ or else 'flutter', ]); - final String bundlePlatform = targetPlatform.startsWith('windows') ? 'windows' : targetPlatform; + final String bundlePlatform = targetPlatform; final String target = '${buildMode}_bundle_${bundlePlatform}_assets'; final Process assembleProcess = await Process.start( flutterExecutable, diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart index fe05a59cb1c..e583ce397f7 100644 --- a/packages/flutter_tools/lib/src/android/android_device.dart +++ b/packages/flutter_tools/lib/src/android/android_device.dart @@ -234,6 +234,7 @@ class AndroidDevice extends Device { case TargetPlatform.tester: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: throw UnsupportedError('Invalid target platform for Android'); } } @@ -570,6 +571,7 @@ class AndroidDevice extends Device { case TargetPlatform.linux_x64: case TargetPlatform.tester: case TargetPlatform.web_javascript: + case TargetPlatform.windows_arm64: case TargetPlatform.windows_x64: _logger.printError('Android platforms are only supported.'); return LaunchResult.failed(); diff --git a/packages/flutter_tools/lib/src/artifacts.dart b/packages/flutter_tools/lib/src/artifacts.dart index 386741a0e40..a5d0022bc91 100644 --- a/packages/flutter_tools/lib/src/artifacts.dart +++ b/packages/flutter_tools/lib/src/artifacts.dart @@ -144,6 +144,7 @@ TargetPlatform? _mapTargetPlatform(TargetPlatform? targetPlatform) { case TargetPlatform.linux_x64: case TargetPlatform.linux_arm64: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.tester: @@ -526,6 +527,7 @@ class CachedArtifacts implements Artifacts { case TargetPlatform.linux_x64: case TargetPlatform.linux_arm64: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: return _getDesktopArtifactPath(artifact, platform, mode); case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: @@ -743,8 +745,9 @@ class CachedArtifacts implements Artifacts { final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode)); case Artifact.windowsCppClientWrapper: + final String platformDirName = _enginePlatformDirectoryName(platform); final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; - return _fileSystem.path.join(engineArtifactsPath, 'windows-x64', _artifactToFileName(artifact, _platform, mode)); + return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode)); case Artifact.skyEnginePath: final Directory dartPackageDirectory = _cache.getCacheDir('pkg'); return _fileSystem.path.join(dartPackageDirectory.path, _artifactToFileName(artifact, _platform)); @@ -775,6 +778,7 @@ class CachedArtifacts implements Artifacts { case TargetPlatform.linux_arm64: case TargetPlatform.darwin: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: // TODO(zanderso): remove once debug desktop artifacts are uploaded // under a separate directory from the host artifacts. // https://github.com/flutter/flutter/issues/38935 @@ -813,10 +817,11 @@ TargetPlatform _currentHostPlatform(Platform platform, OperatingSystemUtils oper } if (platform.isLinux) { return operatingSystemUtils.hostPlatform == HostPlatform.linux_x64 ? - TargetPlatform.linux_x64 : TargetPlatform.linux_arm64; + TargetPlatform.linux_x64 : TargetPlatform.linux_arm64; } if (platform.isWindows) { - return TargetPlatform.windows_x64; + return operatingSystemUtils.hostPlatform == HostPlatform.windows_arm64 ? + TargetPlatform.windows_arm64 : TargetPlatform.windows_x64; } throw UnimplementedError('Host OS not supported.'); } @@ -1089,6 +1094,8 @@ class CachedLocalEngineArtifacts implements Artifacts { return 'linux-x64'; case TargetPlatform.windows_x64: return 'windows-x64'; + case TargetPlatform.windows_arm64: + return 'windows-arm64'; case TargetPlatform.ios: case TargetPlatform.android: case TargetPlatform.android_arm: @@ -1290,6 +1297,8 @@ class CachedLocalWebSdkArtifacts implements Artifacts { return 'linux-x64'; case TargetPlatform.windows_x64: return 'windows-x64'; + case TargetPlatform.windows_arm64: + return 'windows-arm64'; case TargetPlatform.ios: case TargetPlatform.android: case TargetPlatform.android_arm: diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart index a5fa9b6cbe3..60be3c0e1d7 100644 --- a/packages/flutter_tools/lib/src/base/build.dart +++ b/packages/flutter_tools/lib/src/base/build.dart @@ -347,6 +347,7 @@ class AOTSnapshotter { TargetPlatform.linux_x64, TargetPlatform.linux_arm64, TargetPlatform.windows_x64, + TargetPlatform.windows_arm64, ].contains(platform); } } diff --git a/packages/flutter_tools/lib/src/base/os.dart b/packages/flutter_tools/lib/src/base/os.dart index 1ce1951cefd..eb9847cf139 100644 --- a/packages/flutter_tools/lib/src/base/os.dart +++ b/packages/flutter_tools/lib/src/base/os.dart @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ffi' show Abi; + import 'package:archive/archive.dart'; import 'package:file/file.dart'; import 'package:meta/meta.dart'; @@ -472,8 +474,17 @@ class _WindowsUtils extends OperatingSystemUtils { required super.processManager, }) : super._private(); + HostPlatform? _hostPlatform; + @override - HostPlatform hostPlatform = HostPlatform.windows_x64; + HostPlatform get hostPlatform { + if (_hostPlatform == null) { + final Abi abi = Abi.current(); + _hostPlatform = (abi == Abi.windowsArm64) ? HostPlatform.windows_arm64 : + HostPlatform.windows_x64; + } + return _hostPlatform!; + } @override void makeExecutable(File file) {} @@ -607,7 +618,8 @@ enum HostPlatform { darwin_arm64, linux_x64, linux_arm64, - windows_x64; + windows_x64, + windows_arm64; String get platformName { return switch (this) { @@ -615,7 +627,8 @@ enum HostPlatform { HostPlatform.darwin_arm64 => 'arm64', HostPlatform.linux_x64 => 'x64', HostPlatform.linux_arm64 => 'arm64', - HostPlatform.windows_x64 => 'x64' + HostPlatform.windows_x64 => 'x64', + HostPlatform.windows_arm64 => 'arm64', }; } } @@ -626,6 +639,7 @@ String getNameForHostPlatform(HostPlatform platform) { HostPlatform.darwin_arm64 => 'darwin-arm64', HostPlatform.linux_x64 => 'linux-x64', HostPlatform.linux_arm64 => 'linux-arm64', - HostPlatform.windows_x64 => 'windows-x64' + HostPlatform.windows_x64 => 'windows-x64', + HostPlatform.windows_arm64 => 'windows-arm64', }; } diff --git a/packages/flutter_tools/lib/src/build_info.dart b/packages/flutter_tools/lib/src/build_info.dart index 07a60475691..f50019b9a93 100644 --- a/packages/flutter_tools/lib/src/build_info.dart +++ b/packages/flutter_tools/lib/src/build_info.dart @@ -513,6 +513,7 @@ enum TargetPlatform { linux_x64, linux_arm64, windows_x64, + windows_arm64, fuchsia_arm64, fuchsia_x64, tester, @@ -544,6 +545,7 @@ enum TargetPlatform { case TargetPlatform.tester: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: throw UnsupportedError('Unexpected Fuchsia platform $this'); } } @@ -555,6 +557,7 @@ enum TargetPlatform { case TargetPlatform.windows_x64: return 'x64'; case TargetPlatform.linux_arm64: + case TargetPlatform.windows_arm64: return 'arm64'; case TargetPlatform.android: case TargetPlatform.android_arm: @@ -713,6 +716,8 @@ String getNameForTargetPlatform(TargetPlatform platform, {DarwinArch? darwinArch return 'linux-arm64'; case TargetPlatform.windows_x64: return 'windows-x64'; + case TargetPlatform.windows_arm64: + return 'windows-arm64'; case TargetPlatform.fuchsia_arm64: return 'fuchsia-arm64'; case TargetPlatform.fuchsia_x64: @@ -756,6 +761,8 @@ TargetPlatform getTargetPlatformForName(String platform) { return TargetPlatform.linux_arm64; case 'windows-x64': return TargetPlatform.windows_x64; + case 'windows-arm64': + return TargetPlatform.windows_arm64; case 'web-javascript': return TargetPlatform.web_javascript; case 'flutter-tester': diff --git a/packages/flutter_tools/lib/src/build_system/targets/common.dart b/packages/flutter_tools/lib/src/build_system/targets/common.dart index 461638298ba..fda26a47587 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/common.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/common.dart @@ -206,6 +206,7 @@ class KernelSnapshot extends Target { switch (targetPlatform) { case TargetPlatform.darwin: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: case TargetPlatform.linux_x64: forceLinkPlatform = true; case TargetPlatform.android: @@ -233,7 +234,7 @@ class KernelSnapshot extends Target { TargetPlatform.darwin => 'macos', TargetPlatform.ios => 'ios', TargetPlatform.linux_arm64 || TargetPlatform.linux_x64 => 'linux', - TargetPlatform.windows_x64 => 'windows', + TargetPlatform.windows_arm64 || TargetPlatform.windows_x64 => 'windows', TargetPlatform.tester || TargetPlatform.web_javascript => null, }; 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 8757e72123a..b6f5f12cbd2 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 @@ -104,6 +104,7 @@ class NativeAssets extends Target { fileSystem, buildRunner, ); + case TargetPlatform.windows_arm64: case TargetPlatform.windows_x64: dependencies = await _buildWindows( environment, @@ -354,6 +355,7 @@ class NativeAssets extends Target { case TargetPlatform.tester: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: throwToolExit('Unsupported Android target platform: $targetPlatform.'); } } diff --git a/packages/flutter_tools/lib/src/build_system/targets/shader_compiler.dart b/packages/flutter_tools/lib/src/build_system/targets/shader_compiler.dart index 07e4a85f378..c03ef892e73 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/shader_compiler.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/shader_compiler.dart @@ -69,6 +69,7 @@ class DevelopmentShaderCompiler { case TargetPlatform.linux_x64: case TargetPlatform.linux_arm64: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_x64: case TargetPlatform.tester: diff --git a/packages/flutter_tools/lib/src/build_system/targets/windows.dart b/packages/flutter_tools/lib/src/build_system/targets/windows.dart index de2591198fa..983eb5cee84 100644 --- a/packages/flutter_tools/lib/src/build_system/targets/windows.dart +++ b/packages/flutter_tools/lib/src/build_system/targets/windows.dart @@ -31,7 +31,9 @@ const String _kWindowsDepfile = 'windows_engine_sources.d'; /// Copies the Windows desktop embedding files to the copy directory. class UnpackWindows extends Target { - const UnpackWindows(); + const UnpackWindows(this.targetPlatform); + + final TargetPlatform targetPlatform; @override String get name => 'unpack_windows'; @@ -60,13 +62,13 @@ class UnpackWindows extends Target { final String engineSourcePath = environment.artifacts .getArtifactPath( Artifact.windowsDesktopPath, - platform: TargetPlatform.windows_x64, + platform: targetPlatform, mode: buildMode, ); final String clientSourcePath = environment.artifacts .getArtifactPath( Artifact.windowsCppClientWrapper, - platform: TargetPlatform.windows_x64, + platform: targetPlatform, mode: buildMode, ); final Directory outputDirectory = environment.fileSystem.directory( @@ -85,7 +87,7 @@ class UnpackWindows extends Target { clientSourcePaths: [clientSourcePath], icuDataPath: environment.artifacts.getArtifactPath( Artifact.icuData, - platform: TargetPlatform.windows_x64 + platform: targetPlatform, ) ); environment.depFileService.writeToFile( @@ -97,12 +99,14 @@ class UnpackWindows extends Target { /// Creates a bundle for the Windows desktop target. abstract class BundleWindowsAssets extends Target { - const BundleWindowsAssets(); + const BundleWindowsAssets(this.targetPlatform); + + final TargetPlatform targetPlatform; @override - List get dependencies => const [ - KernelSnapshot(), - UnpackWindows(), + List get dependencies => [ + const KernelSnapshot(), + UnpackWindows(targetPlatform), ]; @override @@ -138,7 +142,7 @@ abstract class BundleWindowsAssets extends Target { final Depfile depfile = await copyAssets( environment, outputDirectory, - targetPlatform: TargetPlatform.windows_x64, + targetPlatform: targetPlatform, shaderTarget: ShaderTarget.sksl, ); environment.depFileService.writeToFile( @@ -187,10 +191,10 @@ class WindowsAotBundle extends Target { } class ReleaseBundleWindowsAssets extends BundleWindowsAssets { - const ReleaseBundleWindowsAssets(); + const ReleaseBundleWindowsAssets(super.targetPlatform); @override - String get name => 'release_bundle_windows_assets'; + String get name => 'release_bundle_${getNameForTargetPlatform(targetPlatform)}_assets'; @override List get outputs => const []; @@ -198,15 +202,15 @@ class ReleaseBundleWindowsAssets extends BundleWindowsAssets { @override List get dependencies => [ ...super.dependencies, - const WindowsAotBundle(AotElfRelease(TargetPlatform.windows_x64)), + WindowsAotBundle(AotElfRelease(targetPlatform)), ]; } class ProfileBundleWindowsAssets extends BundleWindowsAssets { - const ProfileBundleWindowsAssets(); + const ProfileBundleWindowsAssets(super.targetPlatform); @override - String get name => 'profile_bundle_windows_assets'; + String get name => 'profile_bundle_${getNameForTargetPlatform(targetPlatform)}_assets'; @override List get outputs => const []; @@ -214,15 +218,15 @@ class ProfileBundleWindowsAssets extends BundleWindowsAssets { @override List get dependencies => [ ...super.dependencies, - const WindowsAotBundle(AotElfProfile(TargetPlatform.windows_x64)), + WindowsAotBundle(AotElfProfile(targetPlatform)), ]; } class DebugBundleWindowsAssets extends BundleWindowsAssets { - const DebugBundleWindowsAssets(); + const DebugBundleWindowsAssets(super.targetPlatform); @override - String get name => 'debug_bundle_windows_assets'; + String get name => 'debug_bundle_${getNameForTargetPlatform(targetPlatform)}_assets'; @override List get inputs => [ diff --git a/packages/flutter_tools/lib/src/commands/assemble.dart b/packages/flutter_tools/lib/src/commands/assemble.dart index 974a768cb43..5ac969e9d86 100644 --- a/packages/flutter_tools/lib/src/commands/assemble.dart +++ b/packages/flutter_tools/lib/src/commands/assemble.dart @@ -73,10 +73,14 @@ List _kDefaultTargets = [ const ProfileIosApplicationBundle(), const ReleaseIosApplicationBundle(), // Windows targets - const UnpackWindows(), - const DebugBundleWindowsAssets(), - const ProfileBundleWindowsAssets(), - const ReleaseBundleWindowsAssets(), + const UnpackWindows(TargetPlatform.windows_x64), + const UnpackWindows(TargetPlatform.windows_arm64), + const DebugBundleWindowsAssets(TargetPlatform.windows_x64), + const DebugBundleWindowsAssets(TargetPlatform.windows_arm64), + const ProfileBundleWindowsAssets(TargetPlatform.windows_x64), + const ProfileBundleWindowsAssets(TargetPlatform.windows_arm64), + const ReleaseBundleWindowsAssets(TargetPlatform.windows_x64), + const ReleaseBundleWindowsAssets(TargetPlatform.windows_arm64), ]; /// Assemble provides a low level API to interact with the flutter tool build diff --git a/packages/flutter_tools/lib/src/commands/build.dart b/packages/flutter_tools/lib/src/commands/build.dart index 5bca720f717..8ae6ec3baf9 100644 --- a/packages/flutter_tools/lib/src/commands/build.dart +++ b/packages/flutter_tools/lib/src/commands/build.dart @@ -72,7 +72,11 @@ class BuildCommand extends FlutterCommand { operatingSystemUtils: osUtils, verboseHelp: verboseHelp )); - _addSubcommand(BuildWindowsCommand(logger: logger, verboseHelp: verboseHelp)); + _addSubcommand(BuildWindowsCommand( + logger: logger, + operatingSystemUtils: osUtils, + verboseHelp: verboseHelp, + )); _addSubcommand(BuildPreviewCommand( artifacts: artifacts, flutterRoot: Cache.flutterRoot!, diff --git a/packages/flutter_tools/lib/src/commands/build_bundle.dart b/packages/flutter_tools/lib/src/commands/build_bundle.dart index 21291093d69..82470cf6071 100644 --- a/packages/flutter_tools/lib/src/commands/build_bundle.dart +++ b/packages/flutter_tools/lib/src/commands/build_bundle.dart @@ -45,6 +45,7 @@ class BuildBundleCommand extends BuildSubCommand { 'linux-x64', 'linux-arm64', 'windows-x64', + 'windows-arm64', ], help: 'The architecture for which to build the application.', ) @@ -116,6 +117,7 @@ class BuildBundleCommand extends BuildSubCommand { throwToolExit('macOS is not a supported target platform.'); } case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: if (!featureFlags.isWindowsEnabled) { throwToolExit('Windows is not a supported target platform.'); } diff --git a/packages/flutter_tools/lib/src/commands/build_preview.dart b/packages/flutter_tools/lib/src/commands/build_preview.dart index cd3a7eef9ec..ec20f0cc23f 100644 --- a/packages/flutter_tools/lib/src/commands/build_preview.dart +++ b/packages/flutter_tools/lib/src/commands/build_preview.dart @@ -65,9 +65,11 @@ class BuildPreviewCommand extends BuildSubCommand { final Directory targetDir = fs.systemTempDirectory.createTempSync('flutter-build-preview'); try { final FlutterProject flutterProject = await _createProject(targetDir); + // TODO(loic-sharma): Support windows-arm64 preview device, https://github.com/flutter/flutter/issues/139949. await buildWindows( flutterProject.windows, buildInfo, + TargetPlatform.windows_x64, ); final File previewDevice = targetDir diff --git a/packages/flutter_tools/lib/src/commands/build_windows.dart b/packages/flutter_tools/lib/src/commands/build_windows.dart index 830d6044800..3267782fd66 100644 --- a/packages/flutter_tools/lib/src/commands/build_windows.dart +++ b/packages/flutter_tools/lib/src/commands/build_windows.dart @@ -6,6 +6,7 @@ import 'package:meta/meta.dart'; import '../base/analyze_size.dart'; import '../base/common.dart'; +import '../base/os.dart'; import '../build_info.dart'; import '../cache.dart'; import '../features.dart'; @@ -20,11 +21,15 @@ import 'build.dart'; class BuildWindowsCommand extends BuildSubCommand { BuildWindowsCommand({ required super.logger, + required OperatingSystemUtils operatingSystemUtils, bool verboseHelp = false, - }) : super(verboseHelp: verboseHelp) { + }) : _operatingSystemUtils = operatingSystemUtils, + super(verboseHelp: verboseHelp) { addCommonDesktopBuildOptions(verboseHelp: verboseHelp); } + final OperatingSystemUtils _operatingSystemUtils; + @override final String name = 'windows'; @@ -52,10 +57,16 @@ class BuildWindowsCommand extends BuildSubCommand { if (!globals.platform.isWindows) { throwToolExit('"build windows" only supported on Windows hosts.'); } + + final String defaultTargetPlatform = (_operatingSystemUtils.hostPlatform == HostPlatform.windows_arm64) ? + 'windows-arm64' : 'windows-x64'; + final TargetPlatform targetPlatform = getTargetPlatformForName(defaultTargetPlatform); + displayNullSafetyMode(buildInfo); await buildWindows( flutterProject.windows, buildInfo, + targetPlatform, target: targetFile, visualStudioOverride: visualStudioOverride, sizeAnalyzer: SizeAnalyzer( diff --git a/packages/flutter_tools/lib/src/context_runner.dart b/packages/flutter_tools/lib/src/context_runner.dart index 35ec9627410..c4cebb385a8 100644 --- a/packages/flutter_tools/lib/src/context_runner.dart +++ b/packages/flutter_tools/lib/src/context_runner.dart @@ -351,6 +351,7 @@ Future runInContext( platform: globals.platform, logger: globals.logger, processManager: globals.processManager, + osUtils: globals.os, ) ), WebWorkflow: () => WebWorkflow( diff --git a/packages/flutter_tools/lib/src/flutter_application_package.dart b/packages/flutter_tools/lib/src/flutter_application_package.dart index 103f21c0439..f605c19575d 100644 --- a/packages/flutter_tools/lib/src/flutter_application_package.dart +++ b/packages/flutter_tools/lib/src/flutter_application_package.dart @@ -98,6 +98,7 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory { ? LinuxApp.fromLinuxProject(FlutterProject.current().linux) : LinuxApp.fromPrebuiltApp(applicationBinary); case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: return applicationBinary == null ? WindowsApp.fromWindowsProject(FlutterProject.current().windows) : WindowsApp.fromPrebuiltApp(applicationBinary); diff --git a/packages/flutter_tools/lib/src/flutter_cache.dart b/packages/flutter_tools/lib/src/flutter_cache.dart index dcba2c6da54..d19e7f98418 100644 --- a/packages/flutter_tools/lib/src/flutter_cache.dart +++ b/packages/flutter_tools/lib/src/flutter_cache.dart @@ -235,18 +235,18 @@ class FlutterSdk extends EngineCachedArtifact { @override List> getBinaryDirs() { - // Currently only Linux supports both arm64 and x64. + // Linux and Windows both support arm64 and x64. final String arch = cache.getHostPlatformArchName(); return >[ ['common', 'flutter_patched_sdk.zip'], ['common', 'flutter_patched_sdk_product.zip'], if (cache.includeAllPlatforms) ...>[ - ['windows-x64', 'windows-x64/artifacts.zip'], + ['windows-$arch', 'windows-$arch/artifacts.zip'], ['linux-$arch', 'linux-$arch/artifacts.zip'], ['darwin-x64', 'darwin-$arch/artifacts.zip'], ] else if (_platform.isWindows) - ['windows-x64', 'windows-x64/artifacts.zip'] + ['windows-$arch', 'windows-$arch/artifacts.zip'] else if (_platform.isMacOS) ['darwin-x64', 'darwin-$arch/artifacts.zip'] else if (_platform.isLinux) @@ -304,7 +304,8 @@ class WindowsEngineArtifacts extends EngineCachedArtifact { @override List> getBinaryDirs() { if (_platform.isWindows || ignorePlatformFiltering) { - return _windowsDesktopBinaryDirs; + final String arch = cache.getHostPlatformArchName(); + return _getWindowsDesktopBinaryDirs(arch); } return const >[]; } @@ -739,12 +740,12 @@ class FontSubsetArtifacts extends EngineCachedArtifact { @override List> getBinaryDirs() { - // Currently only Linux supports both arm64 and x64. + // Linux and Windows both support arm64 and x64. final String arch = cache.getHostPlatformArchName(); final Map> artifacts = > { 'macos': ['darwin-x64', 'darwin-$arch/$artifactName.zip'], 'linux': ['linux-$arch', 'linux-$arch/$artifactName.zip'], - 'windows': ['windows-x64', 'windows-x64/$artifactName.zip'], + 'windows': ['windows-$arch', 'windows-$arch/$artifactName.zip'], }; if (cache.includeAllPlatforms) { return artifacts.values.toList(); @@ -846,12 +847,15 @@ class IosUsbArtifacts extends CachedArtifact { // TODO(zanderso): upload debug desktop artifacts to host-debug and // remove from existing host folder. // https://github.com/flutter/flutter/issues/38935 -const List> _windowsDesktopBinaryDirs = >[ - ['windows-x64', 'windows-x64-debug/windows-x64-flutter.zip'], - ['windows-x64', 'windows-x64/flutter-cpp-client-wrapper.zip'], - ['windows-x64-profile', 'windows-x64-profile/windows-x64-flutter.zip'], - ['windows-x64-release', 'windows-x64-release/windows-x64-flutter.zip'], -]; + +List> _getWindowsDesktopBinaryDirs(String arch) { + return >[ + ['windows-$arch', 'windows-$arch-debug/windows-$arch-flutter.zip'], + ['windows-$arch', 'windows-$arch/flutter-cpp-client-wrapper.zip'], + ['windows-$arch-profile', 'windows-$arch-profile/windows-$arch-flutter.zip'], + ['windows-$arch-release', 'windows-$arch-release/windows-$arch-flutter.zip'], + ]; +} const List> _macOSDesktopBinaryDirs = >[ ['darwin-x64', 'darwin-x64/FlutterMacOS.framework.zip'], diff --git a/packages/flutter_tools/lib/src/mdns_discovery.dart b/packages/flutter_tools/lib/src/mdns_discovery.dart index 7034b46e510..a2f0decf7fb 100644 --- a/packages/flutter_tools/lib/src/mdns_discovery.dart +++ b/packages/flutter_tools/lib/src/mdns_discovery.dart @@ -529,6 +529,7 @@ class MDnsVmServiceDiscovery { case TargetPlatform.tester: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: _logger.printTrace('No interface with an ipv4 link local address was found.'); } } diff --git a/packages/flutter_tools/lib/src/native_assets.dart b/packages/flutter_tools/lib/src/native_assets.dart index 97ad5415b17..a92ffcc167c 100644 --- a/packages/flutter_tools/lib/src/native_assets.dart +++ b/packages/flutter_tools/lib/src/native_assets.dart @@ -379,6 +379,7 @@ Future dryRunNativeAssets({ fileSystem: fileSystem, buildRunner: buildRunner, ); + case build_info.TargetPlatform.windows_arm64: case build_info.TargetPlatform.windows_x64: nativeAssetsYaml = await dryRunNativeAssetsWindows( projectUri: projectUri, @@ -441,7 +442,8 @@ Future dryRunNativeAssetsMultipleOSes({ false, buildRunner, ), - if (targetPlatforms.contains(build_info.TargetPlatform.windows_x64) || + if (targetPlatforms.contains(build_info.TargetPlatform.windows_arm64) || + targetPlatforms.contains(build_info.TargetPlatform.windows_x64) || (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.windows)) ...await dryRunNativeAssetsWindowsInternal( fileSystem, @@ -652,6 +654,8 @@ Target _getNativeTarget(build_info.TargetPlatform targetPlatform) { return Target.linuxArm64; case build_info.TargetPlatform.windows_x64: return Target.windowsX64; + case build_info.TargetPlatform.windows_arm64: + return Target.windowsArm64; case build_info.TargetPlatform.android: case build_info.TargetPlatform.ios: case build_info.TargetPlatform.darwin: diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index e22d2ed2315..87ce7b72229 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -1630,6 +1630,7 @@ Future getMissingPackageHintForPlatform(TargetPlatform platform) async case TargetPlatform.tester: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: return null; } } diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 906c9aba7f2..1a2156b4405 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -1953,6 +1953,7 @@ DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) { } return null; case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: if (featureFlags.isWindowsEnabled) { return DevelopmentArtifact.windows; } diff --git a/packages/flutter_tools/lib/src/sksl_writer.dart b/packages/flutter_tools/lib/src/sksl_writer.dart index a0b2f863a80..706cfe19763 100644 --- a/packages/flutter_tools/lib/src/sksl_writer.dart +++ b/packages/flutter_tools/lib/src/sksl_writer.dart @@ -54,6 +54,7 @@ Future sharedSkSlWriter(Device device, Map? data, { case TargetPlatform.tester: case TargetPlatform.web_javascript: case TargetPlatform.windows_x64: + case TargetPlatform.windows_arm64: break; } final Map manifest = { diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart index 1433a7150c2..5d1cd9732a9 100644 --- a/packages/flutter_tools/lib/src/test/test_compiler.dart +++ b/packages/flutter_tools/lib/src/test/test_compiler.dart @@ -10,6 +10,7 @@ import 'package:meta/meta.dart'; import '../artifacts.dart'; import '../base/file_system.dart'; +import '../base/os.dart' show HostPlatform; import '../base/platform.dart'; import '../build_info.dart'; import '../bundle.dart'; @@ -197,8 +198,15 @@ class TestCompiler { 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, diff --git a/packages/flutter_tools/lib/src/windows/application_package.dart b/packages/flutter_tools/lib/src/windows/application_package.dart index a5b3cb6c80a..3fd8be87aa9 100644 --- a/packages/flutter_tools/lib/src/windows/application_package.dart +++ b/packages/flutter_tools/lib/src/windows/application_package.dart @@ -78,7 +78,7 @@ abstract class WindowsApp extends ApplicationPackage { @override String get displayName => id; - String executable(BuildMode buildMode); + String executable(BuildMode buildMode, TargetPlatform targetPlatform); } class PrebuiltWindowsApp extends WindowsApp implements PrebuiltApplicationPackage { @@ -91,7 +91,7 @@ class PrebuiltWindowsApp extends WindowsApp implements PrebuiltApplicationPackag final String _executable; @override - String executable(BuildMode buildMode) => _executable; + String executable(BuildMode buildMode, TargetPlatform targetPlatform) => _executable; @override String get name => _executable; @@ -108,10 +108,10 @@ class BuildableWindowsApp extends WindowsApp { final WindowsProject project; @override - String executable(BuildMode buildMode) { + String executable(BuildMode buildMode, TargetPlatform targetPlatform) { final String? binaryName = getCmakeExecutableName(project); return globals.fs.path.join( - getWindowsBuildDirectory(TargetPlatform.windows_x64), + getWindowsBuildDirectory(targetPlatform), 'runner', sentenceCase(buildMode.cliName), '$binaryName.exe', diff --git a/packages/flutter_tools/lib/src/windows/build_windows.dart b/packages/flutter_tools/lib/src/windows/build_windows.dart index eed8ef17d45..813100dd57d 100644 --- a/packages/flutter_tools/lib/src/windows/build_windows.dart +++ b/packages/flutter_tools/lib/src/windows/build_windows.dart @@ -30,7 +30,10 @@ import 'visual_studio.dart'; const String _kBadCharacters = r"'#!$^&*=|,;<>?"; /// Builds the Windows project using msbuild. -Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { +Future buildWindows( + WindowsProject windowsProject, + BuildInfo buildInfo, + TargetPlatform targetPlatform, { String? target, VisualStudio? visualStudioOverride, SizeAnalyzer? sizeAnalyzer, @@ -56,8 +59,6 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { 'to learn about adding Windows support to a project.'); } - // TODO(pbo-linaro): Add support for windows-arm64 platform, https://github.com/flutter/flutter/issues/129807 - const TargetPlatform targetPlatform = TargetPlatform.windows_x64; final Directory buildDirectory = globals.fs.directory(globals.fs.path.join( projectPath, getWindowsBuildDirectory(targetPlatform), @@ -83,6 +84,7 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { platform: globals.platform, logger: globals.logger, processManager: globals.processManager, + osUtils: globals.os, ); final String? cmakePath = visualStudio.cmakePath; final String? cmakeGenerator = visualStudio.cmakeGenerator; @@ -99,9 +101,9 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { await _runCmakeGeneration( cmakePath: cmakePath, generator: cmakeGenerator, + targetPlatform: targetPlatform, buildDir: buildDirectory, sourceDir: windowsProject.cmakeFile.parent, - targetPlatform: targetPlatform, ); if (visualStudio.displayVersion == '17.1.0') { _fixBrokenCmakeGeneration(buildDirectory); @@ -128,7 +130,7 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { } if (buildInfo.codeSizeDirectory != null && sizeAnalyzer != null) { - final String arch = getNameForTargetPlatform(TargetPlatform.windows_x64); + final String arch = getNameForTargetPlatform(targetPlatform); final File codeSizeFile = globals.fs.directory(buildInfo.codeSizeDirectory) .childFile('snapshot.$arch.json'); final File precompilerTrace = globals.fs.directory(buildInfo.codeSizeDirectory) @@ -165,23 +167,26 @@ Future buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { } } +String getCmakeWindowsArch(TargetPlatform targetPlatform) { + return switch (targetPlatform) { + TargetPlatform.windows_x64 => 'x64', + TargetPlatform.windows_arm64 => 'ARM64', + _ => throw Exception('Unsupported target platform "$targetPlatform".'), + }; +} + Future _runCmakeGeneration({ required String cmakePath, required String generator, + required TargetPlatform targetPlatform, required Directory buildDir, required Directory sourceDir, - required TargetPlatform targetPlatform, }) async { - if (targetPlatform != TargetPlatform.windows_x64) { - throwToolExit('Windows build supports only x64 target architecture'); - } - final Stopwatch sw = Stopwatch()..start(); await buildDir.create(recursive: true); int result; - const String arch = 'x64'; - const String flutterTargetPlatform = 'windows-x64'; + try { result = await globals.processUtils.stream( [ @@ -193,8 +198,8 @@ Future _runCmakeGeneration({ '-G', generator, '-A', - arch, - '-DFLUTTER_TARGET_PLATFORM=$flutterTargetPlatform', + getCmakeWindowsArch(targetPlatform), + '-DFLUTTER_TARGET_PLATFORM=${getNameForTargetPlatform(targetPlatform)}', ], trace: true, ); diff --git a/packages/flutter_tools/lib/src/windows/native_assets.dart b/packages/flutter_tools/lib/src/windows/native_assets.dart index c5f5835d008..fed23bbcac7 100644 --- a/packages/flutter_tools/lib/src/windows/native_assets.dart +++ b/packages/flutter_tools/lib/src/windows/native_assets.dart @@ -72,6 +72,7 @@ Future cCompilerConfigWindows() async { platform: globals.platform, logger: globals.logger, processManager: globals.processManager, + osUtils: globals.os, ); return CCompilerConfig( diff --git a/packages/flutter_tools/lib/src/windows/visual_studio.dart b/packages/flutter_tools/lib/src/windows/visual_studio.dart index 5251450a81b..93d6506f4eb 100644 --- a/packages/flutter_tools/lib/src/windows/visual_studio.dart +++ b/packages/flutter_tools/lib/src/windows/visual_studio.dart @@ -9,6 +9,7 @@ import '../base/common.dart'; import '../base/file_system.dart'; import '../base/io.dart'; import '../base/logger.dart'; +import '../base/os.dart' show HostPlatform, OperatingSystemUtils; import '../base/platform.dart'; import '../base/process.dart'; import '../base/version.dart'; @@ -21,15 +22,18 @@ class VisualStudio { required ProcessManager processManager, required Platform platform, required Logger logger, + required OperatingSystemUtils osUtils, }) : _platform = platform, _fileSystem = fileSystem, _processUtils = ProcessUtils(processManager: processManager, logger: logger), - _logger = logger; + _logger = logger, + _osUtils = osUtils; final FileSystem _fileSystem; final Platform _platform; final ProcessUtils _processUtils; final Logger _logger; + final OperatingSystemUtils _osUtils; /// Matches the description property from the vswhere.exe JSON output. final RegExp _vswhereDescriptionProperty = RegExp(r'\s*"description"\s*:\s*".*"\s*,?'); @@ -208,6 +212,8 @@ class VisualStudio { return null; } + final String arch = _osUtils.hostPlatform == HostPlatform.windows_arm64 ? 'arm64': 'x64'; + return _fileSystem.path.joinAll([ details.installationPath!, 'VC', @@ -215,8 +221,8 @@ class VisualStudio { 'MSVC', details.msvcVersion!, 'bin', - 'Hostx64', - 'x64', + 'Host$arch', + arch, executable, ]); } @@ -229,12 +235,14 @@ class VisualStudio { return null; } + final String arch = _osUtils.hostPlatform == HostPlatform.windows_arm64 ? 'arm64': '64'; + return _fileSystem.path.joinAll([ details.installationPath!, 'VC', 'Auxiliary', 'Build', - 'vcvars64.bat', + 'vcvars$arch.bat', ]); } diff --git a/packages/flutter_tools/lib/src/windows/windows_device.dart b/packages/flutter_tools/lib/src/windows/windows_device.dart index d94b8bbaef0..b7be891e097 100644 --- a/packages/flutter_tools/lib/src/windows/windows_device.dart +++ b/packages/flutter_tools/lib/src/windows/windows_device.dart @@ -24,7 +24,8 @@ class WindowsDevice extends DesktopDevice { required Logger logger, required FileSystem fileSystem, required OperatingSystemUtils operatingSystemUtils, - }) : super( + }) : _operatingSystemUtils = operatingSystemUtils, + super( 'windows', platformType: PlatformType.windows, ephemeral: false, @@ -34,6 +35,8 @@ class WindowsDevice extends DesktopDevice { operatingSystemUtils: operatingSystemUtils, ); + final OperatingSystemUtils _operatingSystemUtils; + @override bool isSupported() => true; @@ -41,7 +44,12 @@ class WindowsDevice extends DesktopDevice { String get name => 'Windows'; @override - Future get targetPlatform async => TargetPlatform.windows_x64; + Future get targetPlatform async => _targetPlatform; + + TargetPlatform get _targetPlatform => switch (_operatingSystemUtils.hostPlatform) { + HostPlatform.windows_arm64 => TargetPlatform.windows_arm64, + _ => TargetPlatform.windows_x64, + }; @override bool isSupportedForProject(FlutterProject flutterProject) { @@ -56,13 +64,14 @@ class WindowsDevice extends DesktopDevice { await buildWindows( FlutterProject.current().windows, buildInfo, + _targetPlatform, target: mainPath, ); } @override String executablePathForDevice(covariant WindowsApp package, BuildInfo buildInfo) { - return package.executable(buildInfo.mode); + return package.executable(buildInfo.mode, _targetPlatform); } } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart index 79fb6dee1f3..2579d919b90 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart @@ -7,10 +7,12 @@ import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; +import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/build_windows.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; +import 'package:flutter_tools/src/windows/build_windows.dart'; import 'package:flutter_tools/src/windows/visual_studio.dart'; import 'package:test/fake.dart'; import 'package:unified_analytics/unified_analytics.dart'; @@ -81,6 +83,7 @@ void main() { FakeCommand cmakeGenerationCommand({ void Function()? onRun, String generator = _defaultGenerator, + TargetPlatform targetPlatform = TargetPlatform.windows_x64, }) { return FakeCommand( command: [ @@ -92,7 +95,7 @@ void main() { '-G', generator, '-A', - 'x64', + getCmakeWindowsArch(targetPlatform), '-DFLUTTER_TARGET_PLATFORM=windows-x64', ], onRun: onRun, @@ -126,7 +129,7 @@ void main() { } testUsingContext('Windows build fails when there is no cmake path', () async { - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = FakeVisualStudio(cmakePath: null); setUpMockProjectFilesForBuild(); @@ -142,7 +145,7 @@ void main() { testUsingContext('Windows build fails when there is no windows project', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockCoreProjectFiles(); @@ -160,7 +163,7 @@ void main() { testUsingContext('Windows build fails on non windows platform', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -176,7 +179,7 @@ void main() { testUsingContext('Windows build fails when feature is disabled', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -192,7 +195,7 @@ void main() { testUsingContext('Windows build does not spew stdout to status logger', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -217,7 +220,7 @@ void main() { testUsingContext('Windows build sends timing events', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -257,7 +260,7 @@ void main() { testUsingContext('Windows build extracts errors from stdout', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -315,7 +318,7 @@ C:\foo\windows\x64\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identif testUsingContext('Windows verbose build sets VERBOSE_SCRIPT_LOGGING', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -341,7 +344,7 @@ C:\foo\windows\x64\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identif testUsingContext('Windows build works around CMake generation bug', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(displayVersion: '17.1.0'); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -478,7 +481,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Windows build invokes build and writes generated files', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -548,7 +551,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Windows profile build passes Profile configuration', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -571,7 +574,7 @@ if %errorlevel% neq 0 goto :VCEnd const String generator = 'A different generator'; final FakeVisualStudio fakeVisualStudio = FakeVisualStudio( cmakeGenerator: generator); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -592,7 +595,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext("Windows build uses pubspec's version", () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -638,7 +641,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Windows build uses build-name and build-number', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -682,7 +685,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Windows build build-name overrides pubspec', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -729,7 +732,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Windows build build-number overrides pubspec', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -776,7 +779,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Windows build build-name and build-number override pubspec', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -824,7 +827,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Windows build warns on non-numeric build-number', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -874,7 +877,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Windows build warns on complex build-number', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -923,14 +926,14 @@ if %errorlevel% neq 0 goto :VCEnd }); testUsingContext('hidden when not enabled on Windows host', () { - expect(BuildWindowsCommand(logger: BufferLogger.test()).hidden, true); + expect(BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()).hidden, true); }, overrides: { FeatureFlags: () => TestFeatureFlags(), Platform: () => windowsPlatform, }); testUsingContext('Not hidden when enabled and on Windows host', () { - expect(BuildWindowsCommand(logger: BufferLogger.test()).hidden, false); + expect(BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()).hidden, false); }, overrides: { FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), Platform: () => windowsPlatform, @@ -938,7 +941,7 @@ if %errorlevel% neq 0 goto :VCEnd testUsingContext('Performs code size analysis and sends analytics', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); @@ -994,7 +997,7 @@ if %errorlevel% neq 0 goto :VCEnd // is resolved on the VS side, we can allow these paths again testUsingContext('Test bad path characters', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; fileSystem.currentDirectory = fileSystem.directory("test_'path") ..createSync(); @@ -1021,7 +1024,7 @@ if %errorlevel% neq 0 goto :VCEnd // And tests the case where stdout contains the error about missing assets testUsingContext('Windows build extracts errors related to pubspec.yaml from stdout', () async { final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); - final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) + final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()) ..visualStudioOverride = fakeVisualStudio; setUpMockProjectFilesForBuild(); diff --git a/packages/flutter_tools/test/general.shard/base/os_test.dart b/packages/flutter_tools/test/general.shard/base/os_test.dart index 5d6765cc8c7..ad5b23c498a 100644 --- a/packages/flutter_tools/test/general.shard/base/os_test.dart +++ b/packages/flutter_tools/test/general.shard/base/os_test.dart @@ -160,7 +160,7 @@ void main() { expect(utils.hostPlatform, HostPlatform.linux_x64); }); - testWithoutContext('Windows', () async { + testWithoutContext('Windows default', () async { final OperatingSystemUtils utils = createOSUtils(FakePlatform(operatingSystem: 'windows')); expect(utils.hostPlatform, HostPlatform.windows_x64); diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/windows_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/windows_test.dart index cebfff087af..11b85dd995e 100644 --- a/packages/flutter_tools/test/general.shard/build_system/targets/windows_test.dart +++ b/packages/flutter_tools/test/general.shard/build_system/targets/windows_test.dart @@ -55,7 +55,7 @@ void main() { } fileSystem.directory('windows').createSync(); - await const UnpackWindows().build(environment); + await const UnpackWindows(TargetPlatform.windows_x64).build(environment); // Output files are copied correctly. expect(fileSystem.file(r'C:\windows\flutter\ephemeral\flutter_export.h'), exists); @@ -147,7 +147,7 @@ void main() { }, )); - await const DebugBundleWindowsAssets().build(environment); + await const DebugBundleWindowsAssets(TargetPlatform.windows_x64).build(environment); // Depfile is created and dill is copied. expect(environment.buildDir.childFile('flutter_assets.d'), exists); @@ -175,7 +175,7 @@ void main() { environment.buildDir.childFile('app.so').createSync(recursive: true); await const WindowsAotBundle(AotElfProfile(TargetPlatform.windows_x64)).build(environment); - await const ProfileBundleWindowsAssets().build(environment); + await const ProfileBundleWindowsAssets(TargetPlatform.windows_x64).build(environment); // Depfile is created and so is copied. expect(environment.buildDir.childFile('flutter_assets.d'), exists); @@ -202,7 +202,7 @@ void main() { environment.buildDir.childFile('app.so').createSync(recursive: true); await const WindowsAotBundle(AotElfRelease(TargetPlatform.windows_x64)).build(environment); - await const ReleaseBundleWindowsAssets().build(environment); + await const ReleaseBundleWindowsAssets(TargetPlatform.windows_x64).build(environment); // Depfile is created and so is copied. expect(environment.buildDir.childFile('flutter_assets.d'), exists); diff --git a/packages/flutter_tools/test/general.shard/cache_test.dart b/packages/flutter_tools/test/general.shard/cache_test.dart index f7665219455..0ec69bca6a3 100644 --- a/packages/flutter_tools/test/general.shard/cache_test.dart +++ b/packages/flutter_tools/test/general.shard/cache_test.dart @@ -615,7 +615,7 @@ void main() { expect(artifacts.getBinaryDirs(), >[ ['darwin-x64', 'darwin-arm64/font-subset.zip'], ['linux-arm64', 'linux-arm64/font-subset.zip'], - ['windows-x64', 'windows-x64/font-subset.zip'], // arm64 windows hosts are not supported now + ['windows-arm64', 'windows-arm64/font-subset.zip'], ]); }); diff --git a/packages/flutter_tools/test/general.shard/commands/build_test.dart b/packages/flutter_tools/test/general.shard/commands/build_test.dart index 090924bed93..10e7a95f60d 100644 --- a/packages/flutter_tools/test/general.shard/commands/build_test.dart +++ b/packages/flutter_tools/test/general.shard/commands/build_test.dart @@ -52,7 +52,7 @@ void main() { final Platform platform = FakePlatform(); final BufferLogger logger = BufferLogger.test(); final List commands = [ - BuildWindowsCommand(logger: BufferLogger.test()), + BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()), BuildLinuxCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()), BuildMacosCommand(logger: BufferLogger.test(), verboseHelp: false), BuildWebCommand(fileSystem: fileSystem, logger: BufferLogger.test(), verboseHelp: false), diff --git a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart index 57b07e929e2..ba82c8fb483 100644 --- a/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart +++ b/packages/flutter_tools/test/general.shard/windows/visual_studio_test.dart @@ -12,6 +12,7 @@ import 'package:flutter_tools/src/windows/visual_studio.dart'; import '../../src/common.dart'; import '../../src/context.dart'; +import '../../src/fakes.dart'; const String programFilesPath = r'C:\Program Files (x86)'; const String visualStudioPath = programFilesPath + r'\Microsoft Visual Studio\2017\Community'; @@ -344,6 +345,7 @@ VisualStudioFixture setUpVisualStudio() { platform: windowsPlatform, logger: logger, processManager: processManager, + osUtils: FakeOperatingSystemUtils(), ); return VisualStudioFixture(visualStudio, fileSystem, processManager, logger); } @@ -382,6 +384,7 @@ void main() { fileSystem: MemoryFileSystem.test(style: FileSystemStyle.windows), platform: FakePlatform(operatingSystem: 'windows'), processManager: FakeProcessManager.any(), + osUtils: FakeOperatingSystemUtils(), ); expect(() => visualStudio.isInstalled, @@ -404,6 +407,7 @@ void main() { fileSystem: fileSystem, platform: windowsPlatform, processManager: fakeProcessManager, + osUtils: FakeOperatingSystemUtils(), ); expect(visualStudio.isInstalled, false); @@ -426,6 +430,7 @@ void main() { fileSystem: fileSystem, platform: windowsPlatform, processManager: fakeProcessManager, + osUtils: FakeOperatingSystemUtils(), ); expect(visualStudio.isInstalled, false); diff --git a/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart b/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart index 6128ec607c2..7adb48f97d3 100644 --- a/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart +++ b/packages/flutter_tools/test/general.shard/windows/windows_device_test.dart @@ -130,5 +130,5 @@ WindowsDevice setUpWindowsDevice({ class FakeWindowsApp extends Fake implements WindowsApp { @override - String executable(BuildMode buildMode) => '${buildMode.cliName}/executable'; + String executable(BuildMode buildMode, TargetPlatform targetPlatform) => '${buildMode.cliName}/executable'; } diff --git a/packages/flutter_tools/test/integration.shard/flutter_build_windows_test.dart b/packages/flutter_tools/test/integration.shard/flutter_build_windows_test.dart index d238bb226a7..a7bd8ff82f8 100644 --- a/packages/flutter_tools/test/integration.shard/flutter_build_windows_test.dart +++ b/packages/flutter_tools/test/integration.shard/flutter_build_windows_test.dart @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:ffi' show Abi; import 'dart:io' as io; import 'package:file/file.dart'; @@ -41,11 +42,18 @@ void main() { projectRoot = tempDir.childDirectory('hello'); + final String arch; + if (Abi.current() == Abi.windowsArm64) { + arch = 'arm64'; + } else { + arch = 'x64'; + } + releaseDir = fileSystem.directory(fileSystem.path.join( projectRoot.path, 'build', 'windows', - 'x64', + arch, 'runner', 'Release', ));