Unverified Commit 37c3978b authored by Pierrick Bouvier's avatar Pierrick Bouvier Committed by GitHub

Enable native compilation for windows-arm64 (#141930)

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.
parent d5bd2fe5
...@@ -47,7 +47,22 @@ if (-not $dartSdkBaseUrl) { ...@@ -47,7 +47,22 @@ if (-not $dartSdkBaseUrl) {
if ($engineRealm) { if ($engineRealm) {
$dartSdkBaseUrl = "$dartSdkBaseUrl/$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" $dartSdkUrl = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipName"
if ((Test-Path $dartSdkPath) -or (Test-Path $dartSdkLicense)) { if ((Test-Path $dartSdkPath) -or (Test-Path $dartSdkLicense)) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert' show LineSplitter, json, utf8; import 'dart:convert' show LineSplitter, json, utf8;
import 'dart:ffi' show Abi;
import 'dart:io'; import 'dart:io';
import 'dart:math' as math; import 'dart:math' as math;
...@@ -953,11 +954,12 @@ class StartupTest { ...@@ -953,11 +954,12 @@ class StartupTest {
'--target=$target', '--target=$target',
]); ]);
final String basename = path.basename(testDirectory); final String basename = path.basename(testDirectory);
final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64';
applicationBinaryPath = path.join( applicationBinaryPath = path.join(
testDirectory, testDirectory,
'build', 'build',
'windows', 'windows',
'x64', arch,
'runner', 'runner',
'Profile', 'Profile',
'$basename.exe' '$basename.exe'
...@@ -1763,11 +1765,12 @@ class CompileTest { ...@@ -1763,11 +1765,12 @@ class CompileTest {
await flutter('build', options: options); await flutter('build', options: options);
watch.stop(); watch.stop();
final String basename = path.basename(cwd); final String basename = path.basename(cwd);
final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64';
final String exePath = path.join( final String exePath = path.join(
cwd, cwd,
'build', 'build',
'windows', 'windows',
'x64', arch,
'runner', 'runner',
'release', 'release',
'$basename.exe'); '$basename.exe');
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
...@@ -328,8 +329,9 @@ public class $pluginClass: NSObject, FlutterPlugin { ...@@ -328,8 +329,9 @@ public class $pluginClass: NSObject, FlutterPlugin {
throw TaskResult.failure('Platform unit tests failed'); throw TaskResult.failure('Platform unit tests failed');
} }
case 'windows': case 'windows':
final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64';
if (await exec( 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'),
<String>[], <String>[],
canFail: true, canFail: true,
) != 0) { ) != 0) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import '../framework/devices.dart'; import '../framework/devices.dart';
...@@ -173,12 +174,14 @@ class WindowsRunOutputTest extends DesktopRunOutputTest { ...@@ -173,12 +174,14 @@ class WindowsRunOutputTest extends DesktopRunOutputTest {
} }
); );
final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64';
static final RegExp _buildOutput = RegExp( static final RegExp _buildOutput = RegExp(
r'Building Windows application\.\.\.\s*\d+(\.\d+)?(ms|s)', r'Building Windows application\.\.\.\s*\d+(\.\d+)?(ms|s)',
multiLine: true, multiLine: true,
); );
static final RegExp _builtOutput = RegExp( 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 @override
...@@ -205,7 +208,7 @@ class WindowsRunOutputTest extends DesktopRunOutputTest { ...@@ -205,7 +208,7 @@ class WindowsRunOutputTest extends DesktopRunOutputTest {
return true; return true;
}, },
'Built build\\windows\\x64\\runner\\$buildMode\\app.exe', 'Built build\\windows\\$arch\\runner\\$buildMode\\app.exe',
); );
} }
} }
......
...@@ -76,7 +76,7 @@ or ...@@ -76,7 +76,7 @@ or
else else
'flutter', 'flutter',
]); ]);
final String bundlePlatform = targetPlatform.startsWith('windows') ? 'windows' : targetPlatform; final String bundlePlatform = targetPlatform;
final String target = '${buildMode}_bundle_${bundlePlatform}_assets'; final String target = '${buildMode}_bundle_${bundlePlatform}_assets';
final Process assembleProcess = await Process.start( final Process assembleProcess = await Process.start(
flutterExecutable, flutterExecutable,
......
...@@ -234,6 +234,7 @@ class AndroidDevice extends Device { ...@@ -234,6 +234,7 @@ class AndroidDevice extends Device {
case TargetPlatform.tester: case TargetPlatform.tester:
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
throw UnsupportedError('Invalid target platform for Android'); throw UnsupportedError('Invalid target platform for Android');
} }
} }
...@@ -570,6 +571,7 @@ class AndroidDevice extends Device { ...@@ -570,6 +571,7 @@ class AndroidDevice extends Device {
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
case TargetPlatform.tester: case TargetPlatform.tester:
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
case TargetPlatform.windows_arm64:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
_logger.printError('Android platforms are only supported.'); _logger.printError('Android platforms are only supported.');
return LaunchResult.failed(); return LaunchResult.failed();
......
...@@ -144,6 +144,7 @@ TargetPlatform? _mapTargetPlatform(TargetPlatform? targetPlatform) { ...@@ -144,6 +144,7 @@ TargetPlatform? _mapTargetPlatform(TargetPlatform? targetPlatform) {
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
case TargetPlatform.linux_arm64: case TargetPlatform.linux_arm64:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_arm64:
case TargetPlatform.fuchsia_x64: case TargetPlatform.fuchsia_x64:
case TargetPlatform.tester: case TargetPlatform.tester:
...@@ -526,6 +527,7 @@ class CachedArtifacts implements Artifacts { ...@@ -526,6 +527,7 @@ class CachedArtifacts implements Artifacts {
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
case TargetPlatform.linux_arm64: case TargetPlatform.linux_arm64:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
return _getDesktopArtifactPath(artifact, platform, mode); return _getDesktopArtifactPath(artifact, platform, mode);
case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_arm64:
case TargetPlatform.fuchsia_x64: case TargetPlatform.fuchsia_x64:
...@@ -743,8 +745,9 @@ class CachedArtifacts implements Artifacts { ...@@ -743,8 +745,9 @@ class CachedArtifacts implements Artifacts {
final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode)); return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode));
case Artifact.windowsCppClientWrapper: case Artifact.windowsCppClientWrapper:
final String platformDirName = _enginePlatformDirectoryName(platform);
final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path; 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: case Artifact.skyEnginePath:
final Directory dartPackageDirectory = _cache.getCacheDir('pkg'); final Directory dartPackageDirectory = _cache.getCacheDir('pkg');
return _fileSystem.path.join(dartPackageDirectory.path, _artifactToFileName(artifact, _platform)); return _fileSystem.path.join(dartPackageDirectory.path, _artifactToFileName(artifact, _platform));
...@@ -775,6 +778,7 @@ class CachedArtifacts implements Artifacts { ...@@ -775,6 +778,7 @@ class CachedArtifacts implements Artifacts {
case TargetPlatform.linux_arm64: case TargetPlatform.linux_arm64:
case TargetPlatform.darwin: case TargetPlatform.darwin:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
// TODO(zanderso): remove once debug desktop artifacts are uploaded // TODO(zanderso): remove once debug desktop artifacts are uploaded
// under a separate directory from the host artifacts. // under a separate directory from the host artifacts.
// https://github.com/flutter/flutter/issues/38935 // https://github.com/flutter/flutter/issues/38935
...@@ -816,7 +820,8 @@ TargetPlatform _currentHostPlatform(Platform platform, OperatingSystemUtils oper ...@@ -816,7 +820,8 @@ TargetPlatform _currentHostPlatform(Platform platform, OperatingSystemUtils oper
TargetPlatform.linux_x64 : TargetPlatform.linux_arm64; TargetPlatform.linux_x64 : TargetPlatform.linux_arm64;
} }
if (platform.isWindows) { 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.'); throw UnimplementedError('Host OS not supported.');
} }
...@@ -1089,6 +1094,8 @@ class CachedLocalEngineArtifacts implements Artifacts { ...@@ -1089,6 +1094,8 @@ class CachedLocalEngineArtifacts implements Artifacts {
return 'linux-x64'; return 'linux-x64';
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
return 'windows-x64'; return 'windows-x64';
case TargetPlatform.windows_arm64:
return 'windows-arm64';
case TargetPlatform.ios: case TargetPlatform.ios:
case TargetPlatform.android: case TargetPlatform.android:
case TargetPlatform.android_arm: case TargetPlatform.android_arm:
...@@ -1290,6 +1297,8 @@ class CachedLocalWebSdkArtifacts implements Artifacts { ...@@ -1290,6 +1297,8 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
return 'linux-x64'; return 'linux-x64';
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
return 'windows-x64'; return 'windows-x64';
case TargetPlatform.windows_arm64:
return 'windows-arm64';
case TargetPlatform.ios: case TargetPlatform.ios:
case TargetPlatform.android: case TargetPlatform.android:
case TargetPlatform.android_arm: case TargetPlatform.android_arm:
......
...@@ -347,6 +347,7 @@ class AOTSnapshotter { ...@@ -347,6 +347,7 @@ class AOTSnapshotter {
TargetPlatform.linux_x64, TargetPlatform.linux_x64,
TargetPlatform.linux_arm64, TargetPlatform.linux_arm64,
TargetPlatform.windows_x64, TargetPlatform.windows_x64,
TargetPlatform.windows_arm64,
].contains(platform); ].contains(platform);
} }
} }
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ffi' show Abi;
import 'package:archive/archive.dart'; import 'package:archive/archive.dart';
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
...@@ -472,8 +474,17 @@ class _WindowsUtils extends OperatingSystemUtils { ...@@ -472,8 +474,17 @@ class _WindowsUtils extends OperatingSystemUtils {
required super.processManager, required super.processManager,
}) : super._private(); }) : super._private();
HostPlatform? _hostPlatform;
@override @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 @override
void makeExecutable(File file) {} void makeExecutable(File file) {}
...@@ -607,7 +618,8 @@ enum HostPlatform { ...@@ -607,7 +618,8 @@ enum HostPlatform {
darwin_arm64, darwin_arm64,
linux_x64, linux_x64,
linux_arm64, linux_arm64,
windows_x64; windows_x64,
windows_arm64;
String get platformName { String get platformName {
return switch (this) { return switch (this) {
...@@ -615,7 +627,8 @@ enum HostPlatform { ...@@ -615,7 +627,8 @@ enum HostPlatform {
HostPlatform.darwin_arm64 => 'arm64', HostPlatform.darwin_arm64 => 'arm64',
HostPlatform.linux_x64 => 'x64', HostPlatform.linux_x64 => 'x64',
HostPlatform.linux_arm64 => 'arm64', HostPlatform.linux_arm64 => 'arm64',
HostPlatform.windows_x64 => 'x64' HostPlatform.windows_x64 => 'x64',
HostPlatform.windows_arm64 => 'arm64',
}; };
} }
} }
...@@ -626,6 +639,7 @@ String getNameForHostPlatform(HostPlatform platform) { ...@@ -626,6 +639,7 @@ String getNameForHostPlatform(HostPlatform platform) {
HostPlatform.darwin_arm64 => 'darwin-arm64', HostPlatform.darwin_arm64 => 'darwin-arm64',
HostPlatform.linux_x64 => 'linux-x64', HostPlatform.linux_x64 => 'linux-x64',
HostPlatform.linux_arm64 => 'linux-arm64', HostPlatform.linux_arm64 => 'linux-arm64',
HostPlatform.windows_x64 => 'windows-x64' HostPlatform.windows_x64 => 'windows-x64',
HostPlatform.windows_arm64 => 'windows-arm64',
}; };
} }
...@@ -513,6 +513,7 @@ enum TargetPlatform { ...@@ -513,6 +513,7 @@ enum TargetPlatform {
linux_x64, linux_x64,
linux_arm64, linux_arm64,
windows_x64, windows_x64,
windows_arm64,
fuchsia_arm64, fuchsia_arm64,
fuchsia_x64, fuchsia_x64,
tester, tester,
...@@ -544,6 +545,7 @@ enum TargetPlatform { ...@@ -544,6 +545,7 @@ enum TargetPlatform {
case TargetPlatform.tester: case TargetPlatform.tester:
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
throw UnsupportedError('Unexpected Fuchsia platform $this'); throw UnsupportedError('Unexpected Fuchsia platform $this');
} }
} }
...@@ -555,6 +557,7 @@ enum TargetPlatform { ...@@ -555,6 +557,7 @@ enum TargetPlatform {
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
return 'x64'; return 'x64';
case TargetPlatform.linux_arm64: case TargetPlatform.linux_arm64:
case TargetPlatform.windows_arm64:
return 'arm64'; return 'arm64';
case TargetPlatform.android: case TargetPlatform.android:
case TargetPlatform.android_arm: case TargetPlatform.android_arm:
...@@ -713,6 +716,8 @@ String getNameForTargetPlatform(TargetPlatform platform, {DarwinArch? darwinArch ...@@ -713,6 +716,8 @@ String getNameForTargetPlatform(TargetPlatform platform, {DarwinArch? darwinArch
return 'linux-arm64'; return 'linux-arm64';
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
return 'windows-x64'; return 'windows-x64';
case TargetPlatform.windows_arm64:
return 'windows-arm64';
case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_arm64:
return 'fuchsia-arm64'; return 'fuchsia-arm64';
case TargetPlatform.fuchsia_x64: case TargetPlatform.fuchsia_x64:
...@@ -756,6 +761,8 @@ TargetPlatform getTargetPlatformForName(String platform) { ...@@ -756,6 +761,8 @@ TargetPlatform getTargetPlatformForName(String platform) {
return TargetPlatform.linux_arm64; return TargetPlatform.linux_arm64;
case 'windows-x64': case 'windows-x64':
return TargetPlatform.windows_x64; return TargetPlatform.windows_x64;
case 'windows-arm64':
return TargetPlatform.windows_arm64;
case 'web-javascript': case 'web-javascript':
return TargetPlatform.web_javascript; return TargetPlatform.web_javascript;
case 'flutter-tester': case 'flutter-tester':
......
...@@ -206,6 +206,7 @@ class KernelSnapshot extends Target { ...@@ -206,6 +206,7 @@ class KernelSnapshot extends Target {
switch (targetPlatform) { switch (targetPlatform) {
case TargetPlatform.darwin: case TargetPlatform.darwin:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
forceLinkPlatform = true; forceLinkPlatform = true;
case TargetPlatform.android: case TargetPlatform.android:
...@@ -233,7 +234,7 @@ class KernelSnapshot extends Target { ...@@ -233,7 +234,7 @@ class KernelSnapshot extends Target {
TargetPlatform.darwin => 'macos', TargetPlatform.darwin => 'macos',
TargetPlatform.ios => 'ios', TargetPlatform.ios => 'ios',
TargetPlatform.linux_arm64 || TargetPlatform.linux_x64 => 'linux', TargetPlatform.linux_arm64 || TargetPlatform.linux_x64 => 'linux',
TargetPlatform.windows_x64 => 'windows', TargetPlatform.windows_arm64 || TargetPlatform.windows_x64 => 'windows',
TargetPlatform.tester || TargetPlatform.web_javascript => null, TargetPlatform.tester || TargetPlatform.web_javascript => null,
}; };
......
...@@ -104,6 +104,7 @@ class NativeAssets extends Target { ...@@ -104,6 +104,7 @@ class NativeAssets extends Target {
fileSystem, fileSystem,
buildRunner, buildRunner,
); );
case TargetPlatform.windows_arm64:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
dependencies = await _buildWindows( dependencies = await _buildWindows(
environment, environment,
...@@ -354,6 +355,7 @@ class NativeAssets extends Target { ...@@ -354,6 +355,7 @@ class NativeAssets extends Target {
case TargetPlatform.tester: case TargetPlatform.tester:
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
throwToolExit('Unsupported Android target platform: $targetPlatform.'); throwToolExit('Unsupported Android target platform: $targetPlatform.');
} }
} }
......
...@@ -69,6 +69,7 @@ class DevelopmentShaderCompiler { ...@@ -69,6 +69,7 @@ class DevelopmentShaderCompiler {
case TargetPlatform.linux_x64: case TargetPlatform.linux_x64:
case TargetPlatform.linux_arm64: case TargetPlatform.linux_arm64:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
case TargetPlatform.fuchsia_arm64: case TargetPlatform.fuchsia_arm64:
case TargetPlatform.fuchsia_x64: case TargetPlatform.fuchsia_x64:
case TargetPlatform.tester: case TargetPlatform.tester:
......
...@@ -31,7 +31,9 @@ const String _kWindowsDepfile = 'windows_engine_sources.d'; ...@@ -31,7 +31,9 @@ const String _kWindowsDepfile = 'windows_engine_sources.d';
/// Copies the Windows desktop embedding files to the copy directory. /// Copies the Windows desktop embedding files to the copy directory.
class UnpackWindows extends Target { class UnpackWindows extends Target {
const UnpackWindows(); const UnpackWindows(this.targetPlatform);
final TargetPlatform targetPlatform;
@override @override
String get name => 'unpack_windows'; String get name => 'unpack_windows';
...@@ -60,13 +62,13 @@ class UnpackWindows extends Target { ...@@ -60,13 +62,13 @@ class UnpackWindows extends Target {
final String engineSourcePath = environment.artifacts final String engineSourcePath = environment.artifacts
.getArtifactPath( .getArtifactPath(
Artifact.windowsDesktopPath, Artifact.windowsDesktopPath,
platform: TargetPlatform.windows_x64, platform: targetPlatform,
mode: buildMode, mode: buildMode,
); );
final String clientSourcePath = environment.artifacts final String clientSourcePath = environment.artifacts
.getArtifactPath( .getArtifactPath(
Artifact.windowsCppClientWrapper, Artifact.windowsCppClientWrapper,
platform: TargetPlatform.windows_x64, platform: targetPlatform,
mode: buildMode, mode: buildMode,
); );
final Directory outputDirectory = environment.fileSystem.directory( final Directory outputDirectory = environment.fileSystem.directory(
...@@ -85,7 +87,7 @@ class UnpackWindows extends Target { ...@@ -85,7 +87,7 @@ class UnpackWindows extends Target {
clientSourcePaths: <String>[clientSourcePath], clientSourcePaths: <String>[clientSourcePath],
icuDataPath: environment.artifacts.getArtifactPath( icuDataPath: environment.artifacts.getArtifactPath(
Artifact.icuData, Artifact.icuData,
platform: TargetPlatform.windows_x64 platform: targetPlatform,
) )
); );
environment.depFileService.writeToFile( environment.depFileService.writeToFile(
...@@ -97,12 +99,14 @@ class UnpackWindows extends Target { ...@@ -97,12 +99,14 @@ class UnpackWindows extends Target {
/// Creates a bundle for the Windows desktop target. /// Creates a bundle for the Windows desktop target.
abstract class BundleWindowsAssets extends Target { abstract class BundleWindowsAssets extends Target {
const BundleWindowsAssets(); const BundleWindowsAssets(this.targetPlatform);
final TargetPlatform targetPlatform;
@override @override
List<Target> get dependencies => const <Target>[ List<Target> get dependencies => <Target>[
KernelSnapshot(), const KernelSnapshot(),
UnpackWindows(), UnpackWindows(targetPlatform),
]; ];
@override @override
...@@ -138,7 +142,7 @@ abstract class BundleWindowsAssets extends Target { ...@@ -138,7 +142,7 @@ abstract class BundleWindowsAssets extends Target {
final Depfile depfile = await copyAssets( final Depfile depfile = await copyAssets(
environment, environment,
outputDirectory, outputDirectory,
targetPlatform: TargetPlatform.windows_x64, targetPlatform: targetPlatform,
shaderTarget: ShaderTarget.sksl, shaderTarget: ShaderTarget.sksl,
); );
environment.depFileService.writeToFile( environment.depFileService.writeToFile(
...@@ -187,10 +191,10 @@ class WindowsAotBundle extends Target { ...@@ -187,10 +191,10 @@ class WindowsAotBundle extends Target {
} }
class ReleaseBundleWindowsAssets extends BundleWindowsAssets { class ReleaseBundleWindowsAssets extends BundleWindowsAssets {
const ReleaseBundleWindowsAssets(); const ReleaseBundleWindowsAssets(super.targetPlatform);
@override @override
String get name => 'release_bundle_windows_assets'; String get name => 'release_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
@override @override
List<Source> get outputs => const <Source>[]; List<Source> get outputs => const <Source>[];
...@@ -198,15 +202,15 @@ class ReleaseBundleWindowsAssets extends BundleWindowsAssets { ...@@ -198,15 +202,15 @@ class ReleaseBundleWindowsAssets extends BundleWindowsAssets {
@override @override
List<Target> get dependencies => <Target>[ List<Target> get dependencies => <Target>[
...super.dependencies, ...super.dependencies,
const WindowsAotBundle(AotElfRelease(TargetPlatform.windows_x64)), WindowsAotBundle(AotElfRelease(targetPlatform)),
]; ];
} }
class ProfileBundleWindowsAssets extends BundleWindowsAssets { class ProfileBundleWindowsAssets extends BundleWindowsAssets {
const ProfileBundleWindowsAssets(); const ProfileBundleWindowsAssets(super.targetPlatform);
@override @override
String get name => 'profile_bundle_windows_assets'; String get name => 'profile_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
@override @override
List<Source> get outputs => const <Source>[]; List<Source> get outputs => const <Source>[];
...@@ -214,15 +218,15 @@ class ProfileBundleWindowsAssets extends BundleWindowsAssets { ...@@ -214,15 +218,15 @@ class ProfileBundleWindowsAssets extends BundleWindowsAssets {
@override @override
List<Target> get dependencies => <Target>[ List<Target> get dependencies => <Target>[
...super.dependencies, ...super.dependencies,
const WindowsAotBundle(AotElfProfile(TargetPlatform.windows_x64)), WindowsAotBundle(AotElfProfile(targetPlatform)),
]; ];
} }
class DebugBundleWindowsAssets extends BundleWindowsAssets { class DebugBundleWindowsAssets extends BundleWindowsAssets {
const DebugBundleWindowsAssets(); const DebugBundleWindowsAssets(super.targetPlatform);
@override @override
String get name => 'debug_bundle_windows_assets'; String get name => 'debug_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
@override @override
List<Source> get inputs => <Source>[ List<Source> get inputs => <Source>[
......
...@@ -73,10 +73,14 @@ List<Target> _kDefaultTargets = <Target>[ ...@@ -73,10 +73,14 @@ List<Target> _kDefaultTargets = <Target>[
const ProfileIosApplicationBundle(), const ProfileIosApplicationBundle(),
const ReleaseIosApplicationBundle(), const ReleaseIosApplicationBundle(),
// Windows targets // Windows targets
const UnpackWindows(), const UnpackWindows(TargetPlatform.windows_x64),
const DebugBundleWindowsAssets(), const UnpackWindows(TargetPlatform.windows_arm64),
const ProfileBundleWindowsAssets(), const DebugBundleWindowsAssets(TargetPlatform.windows_x64),
const ReleaseBundleWindowsAssets(), 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 /// Assemble provides a low level API to interact with the flutter tool build
......
...@@ -72,7 +72,11 @@ class BuildCommand extends FlutterCommand { ...@@ -72,7 +72,11 @@ class BuildCommand extends FlutterCommand {
operatingSystemUtils: osUtils, operatingSystemUtils: osUtils,
verboseHelp: verboseHelp verboseHelp: verboseHelp
)); ));
_addSubcommand(BuildWindowsCommand(logger: logger, verboseHelp: verboseHelp)); _addSubcommand(BuildWindowsCommand(
logger: logger,
operatingSystemUtils: osUtils,
verboseHelp: verboseHelp,
));
_addSubcommand(BuildPreviewCommand( _addSubcommand(BuildPreviewCommand(
artifacts: artifacts, artifacts: artifacts,
flutterRoot: Cache.flutterRoot!, flutterRoot: Cache.flutterRoot!,
......
...@@ -45,6 +45,7 @@ class BuildBundleCommand extends BuildSubCommand { ...@@ -45,6 +45,7 @@ class BuildBundleCommand extends BuildSubCommand {
'linux-x64', 'linux-x64',
'linux-arm64', 'linux-arm64',
'windows-x64', 'windows-x64',
'windows-arm64',
], ],
help: 'The architecture for which to build the application.', help: 'The architecture for which to build the application.',
) )
...@@ -116,6 +117,7 @@ class BuildBundleCommand extends BuildSubCommand { ...@@ -116,6 +117,7 @@ class BuildBundleCommand extends BuildSubCommand {
throwToolExit('macOS is not a supported target platform.'); throwToolExit('macOS is not a supported target platform.');
} }
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
if (!featureFlags.isWindowsEnabled) { if (!featureFlags.isWindowsEnabled) {
throwToolExit('Windows is not a supported target platform.'); throwToolExit('Windows is not a supported target platform.');
} }
......
...@@ -65,9 +65,11 @@ class BuildPreviewCommand extends BuildSubCommand { ...@@ -65,9 +65,11 @@ class BuildPreviewCommand extends BuildSubCommand {
final Directory targetDir = fs.systemTempDirectory.createTempSync('flutter-build-preview'); final Directory targetDir = fs.systemTempDirectory.createTempSync('flutter-build-preview');
try { try {
final FlutterProject flutterProject = await _createProject(targetDir); final FlutterProject flutterProject = await _createProject(targetDir);
// TODO(loic-sharma): Support windows-arm64 preview device, https://github.com/flutter/flutter/issues/139949.
await buildWindows( await buildWindows(
flutterProject.windows, flutterProject.windows,
buildInfo, buildInfo,
TargetPlatform.windows_x64,
); );
final File previewDevice = targetDir final File previewDevice = targetDir
......
...@@ -6,6 +6,7 @@ import 'package:meta/meta.dart'; ...@@ -6,6 +6,7 @@ import 'package:meta/meta.dart';
import '../base/analyze_size.dart'; import '../base/analyze_size.dart';
import '../base/common.dart'; import '../base/common.dart';
import '../base/os.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart'; import '../cache.dart';
import '../features.dart'; import '../features.dart';
...@@ -20,11 +21,15 @@ import 'build.dart'; ...@@ -20,11 +21,15 @@ import 'build.dart';
class BuildWindowsCommand extends BuildSubCommand { class BuildWindowsCommand extends BuildSubCommand {
BuildWindowsCommand({ BuildWindowsCommand({
required super.logger, required super.logger,
required OperatingSystemUtils operatingSystemUtils,
bool verboseHelp = false, bool verboseHelp = false,
}) : super(verboseHelp: verboseHelp) { }) : _operatingSystemUtils = operatingSystemUtils,
super(verboseHelp: verboseHelp) {
addCommonDesktopBuildOptions(verboseHelp: verboseHelp); addCommonDesktopBuildOptions(verboseHelp: verboseHelp);
} }
final OperatingSystemUtils _operatingSystemUtils;
@override @override
final String name = 'windows'; final String name = 'windows';
...@@ -52,10 +57,16 @@ class BuildWindowsCommand extends BuildSubCommand { ...@@ -52,10 +57,16 @@ class BuildWindowsCommand extends BuildSubCommand {
if (!globals.platform.isWindows) { if (!globals.platform.isWindows) {
throwToolExit('"build windows" only supported on Windows hosts.'); 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); displayNullSafetyMode(buildInfo);
await buildWindows( await buildWindows(
flutterProject.windows, flutterProject.windows,
buildInfo, buildInfo,
targetPlatform,
target: targetFile, target: targetFile,
visualStudioOverride: visualStudioOverride, visualStudioOverride: visualStudioOverride,
sizeAnalyzer: SizeAnalyzer( sizeAnalyzer: SizeAnalyzer(
......
...@@ -351,6 +351,7 @@ Future<T> runInContext<T>( ...@@ -351,6 +351,7 @@ Future<T> runInContext<T>(
platform: globals.platform, platform: globals.platform,
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
osUtils: globals.os,
) )
), ),
WebWorkflow: () => WebWorkflow( WebWorkflow: () => WebWorkflow(
......
...@@ -98,6 +98,7 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory { ...@@ -98,6 +98,7 @@ class FlutterApplicationPackageFactory extends ApplicationPackageFactory {
? LinuxApp.fromLinuxProject(FlutterProject.current().linux) ? LinuxApp.fromLinuxProject(FlutterProject.current().linux)
: LinuxApp.fromPrebuiltApp(applicationBinary); : LinuxApp.fromPrebuiltApp(applicationBinary);
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
return applicationBinary == null return applicationBinary == null
? WindowsApp.fromWindowsProject(FlutterProject.current().windows) ? WindowsApp.fromWindowsProject(FlutterProject.current().windows)
: WindowsApp.fromPrebuiltApp(applicationBinary); : WindowsApp.fromPrebuiltApp(applicationBinary);
......
...@@ -235,18 +235,18 @@ class FlutterSdk extends EngineCachedArtifact { ...@@ -235,18 +235,18 @@ class FlutterSdk extends EngineCachedArtifact {
@override @override
List<List<String>> getBinaryDirs() { List<List<String>> getBinaryDirs() {
// Currently only Linux supports both arm64 and x64. // Linux and Windows both support arm64 and x64.
final String arch = cache.getHostPlatformArchName(); final String arch = cache.getHostPlatformArchName();
return <List<String>>[ return <List<String>>[
<String>['common', 'flutter_patched_sdk.zip'], <String>['common', 'flutter_patched_sdk.zip'],
<String>['common', 'flutter_patched_sdk_product.zip'], <String>['common', 'flutter_patched_sdk_product.zip'],
if (cache.includeAllPlatforms) ...<List<String>>[ if (cache.includeAllPlatforms) ...<List<String>>[
<String>['windows-x64', 'windows-x64/artifacts.zip'], <String>['windows-$arch', 'windows-$arch/artifacts.zip'],
<String>['linux-$arch', 'linux-$arch/artifacts.zip'], <String>['linux-$arch', 'linux-$arch/artifacts.zip'],
<String>['darwin-x64', 'darwin-$arch/artifacts.zip'], <String>['darwin-x64', 'darwin-$arch/artifacts.zip'],
] ]
else if (_platform.isWindows) else if (_platform.isWindows)
<String>['windows-x64', 'windows-x64/artifacts.zip'] <String>['windows-$arch', 'windows-$arch/artifacts.zip']
else if (_platform.isMacOS) else if (_platform.isMacOS)
<String>['darwin-x64', 'darwin-$arch/artifacts.zip'] <String>['darwin-x64', 'darwin-$arch/artifacts.zip']
else if (_platform.isLinux) else if (_platform.isLinux)
...@@ -304,7 +304,8 @@ class WindowsEngineArtifacts extends EngineCachedArtifact { ...@@ -304,7 +304,8 @@ class WindowsEngineArtifacts extends EngineCachedArtifact {
@override @override
List<List<String>> getBinaryDirs() { List<List<String>> getBinaryDirs() {
if (_platform.isWindows || ignorePlatformFiltering) { if (_platform.isWindows || ignorePlatformFiltering) {
return _windowsDesktopBinaryDirs; final String arch = cache.getHostPlatformArchName();
return _getWindowsDesktopBinaryDirs(arch);
} }
return const <List<String>>[]; return const <List<String>>[];
} }
...@@ -739,12 +740,12 @@ class FontSubsetArtifacts extends EngineCachedArtifact { ...@@ -739,12 +740,12 @@ class FontSubsetArtifacts extends EngineCachedArtifact {
@override @override
List<List<String>> getBinaryDirs() { List<List<String>> getBinaryDirs() {
// Currently only Linux supports both arm64 and x64. // Linux and Windows both support arm64 and x64.
final String arch = cache.getHostPlatformArchName(); final String arch = cache.getHostPlatformArchName();
final Map<String, List<String>> artifacts = <String, List<String>> { final Map<String, List<String>> artifacts = <String, List<String>> {
'macos': <String>['darwin-x64', 'darwin-$arch/$artifactName.zip'], 'macos': <String>['darwin-x64', 'darwin-$arch/$artifactName.zip'],
'linux': <String>['linux-$arch', 'linux-$arch/$artifactName.zip'], 'linux': <String>['linux-$arch', 'linux-$arch/$artifactName.zip'],
'windows': <String>['windows-x64', 'windows-x64/$artifactName.zip'], 'windows': <String>['windows-$arch', 'windows-$arch/$artifactName.zip'],
}; };
if (cache.includeAllPlatforms) { if (cache.includeAllPlatforms) {
return artifacts.values.toList(); return artifacts.values.toList();
...@@ -846,12 +847,15 @@ class IosUsbArtifacts extends CachedArtifact { ...@@ -846,12 +847,15 @@ class IosUsbArtifacts extends CachedArtifact {
// TODO(zanderso): upload debug desktop artifacts to host-debug and // TODO(zanderso): upload debug desktop artifacts to host-debug and
// remove from existing host folder. // remove from existing host folder.
// https://github.com/flutter/flutter/issues/38935 // https://github.com/flutter/flutter/issues/38935
const List<List<String>> _windowsDesktopBinaryDirs = <List<String>>[
<String>['windows-x64', 'windows-x64-debug/windows-x64-flutter.zip'], List<List<String>> _getWindowsDesktopBinaryDirs(String arch) {
<String>['windows-x64', 'windows-x64/flutter-cpp-client-wrapper.zip'], return <List<String>>[
<String>['windows-x64-profile', 'windows-x64-profile/windows-x64-flutter.zip'], <String>['windows-$arch', 'windows-$arch-debug/windows-$arch-flutter.zip'],
<String>['windows-x64-release', 'windows-x64-release/windows-x64-flutter.zip'], <String>['windows-$arch', 'windows-$arch/flutter-cpp-client-wrapper.zip'],
]; <String>['windows-$arch-profile', 'windows-$arch-profile/windows-$arch-flutter.zip'],
<String>['windows-$arch-release', 'windows-$arch-release/windows-$arch-flutter.zip'],
];
}
const List<List<String>> _macOSDesktopBinaryDirs = <List<String>>[ const List<List<String>> _macOSDesktopBinaryDirs = <List<String>>[
<String>['darwin-x64', 'darwin-x64/FlutterMacOS.framework.zip'], <String>['darwin-x64', 'darwin-x64/FlutterMacOS.framework.zip'],
......
...@@ -529,6 +529,7 @@ class MDnsVmServiceDiscovery { ...@@ -529,6 +529,7 @@ class MDnsVmServiceDiscovery {
case TargetPlatform.tester: case TargetPlatform.tester:
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
_logger.printTrace('No interface with an ipv4 link local address was found.'); _logger.printTrace('No interface with an ipv4 link local address was found.');
} }
} }
......
...@@ -379,6 +379,7 @@ Future<Uri?> dryRunNativeAssets({ ...@@ -379,6 +379,7 @@ Future<Uri?> dryRunNativeAssets({
fileSystem: fileSystem, fileSystem: fileSystem,
buildRunner: buildRunner, buildRunner: buildRunner,
); );
case build_info.TargetPlatform.windows_arm64:
case build_info.TargetPlatform.windows_x64: case build_info.TargetPlatform.windows_x64:
nativeAssetsYaml = await dryRunNativeAssetsWindows( nativeAssetsYaml = await dryRunNativeAssetsWindows(
projectUri: projectUri, projectUri: projectUri,
...@@ -441,7 +442,8 @@ Future<Uri?> dryRunNativeAssetsMultipleOSes({ ...@@ -441,7 +442,8 @@ Future<Uri?> dryRunNativeAssetsMultipleOSes({
false, false,
buildRunner, 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)) (targetPlatforms.contains(build_info.TargetPlatform.tester) && OS.current == OS.windows))
...await dryRunNativeAssetsWindowsInternal( ...await dryRunNativeAssetsWindowsInternal(
fileSystem, fileSystem,
...@@ -652,6 +654,8 @@ Target _getNativeTarget(build_info.TargetPlatform targetPlatform) { ...@@ -652,6 +654,8 @@ Target _getNativeTarget(build_info.TargetPlatform targetPlatform) {
return Target.linuxArm64; return Target.linuxArm64;
case build_info.TargetPlatform.windows_x64: case build_info.TargetPlatform.windows_x64:
return Target.windowsX64; return Target.windowsX64;
case build_info.TargetPlatform.windows_arm64:
return Target.windowsArm64;
case build_info.TargetPlatform.android: case build_info.TargetPlatform.android:
case build_info.TargetPlatform.ios: case build_info.TargetPlatform.ios:
case build_info.TargetPlatform.darwin: case build_info.TargetPlatform.darwin:
......
...@@ -1630,6 +1630,7 @@ Future<String?> getMissingPackageHintForPlatform(TargetPlatform platform) async ...@@ -1630,6 +1630,7 @@ Future<String?> getMissingPackageHintForPlatform(TargetPlatform platform) async
case TargetPlatform.tester: case TargetPlatform.tester:
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
return null; return null;
} }
} }
......
...@@ -1962,6 +1962,7 @@ DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) { ...@@ -1962,6 +1962,7 @@ DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) {
} }
return null; return null;
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
if (featureFlags.isWindowsEnabled) { if (featureFlags.isWindowsEnabled) {
return DevelopmentArtifact.windows; return DevelopmentArtifact.windows;
} }
......
...@@ -54,6 +54,7 @@ Future<String?> sharedSkSlWriter(Device device, Map<String, Object?>? data, { ...@@ -54,6 +54,7 @@ Future<String?> sharedSkSlWriter(Device device, Map<String, Object?>? data, {
case TargetPlatform.tester: case TargetPlatform.tester:
case TargetPlatform.web_javascript: case TargetPlatform.web_javascript:
case TargetPlatform.windows_x64: case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
break; break;
} }
final Map<String, Object> manifest = <String, Object>{ final Map<String, Object> manifest = <String, Object>{
......
...@@ -10,6 +10,7 @@ import 'package:meta/meta.dart'; ...@@ -10,6 +10,7 @@ import 'package:meta/meta.dart';
import '../artifacts.dart'; import '../artifacts.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/os.dart' show HostPlatform;
import '../base/platform.dart'; import '../base/platform.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../bundle.dart'; import '../bundle.dart';
...@@ -197,8 +198,15 @@ class TestCompiler { ...@@ -197,8 +198,15 @@ class TestCompiler {
buildRunner: buildRunner, buildRunner: buildRunner,
); );
} else if (globals.platform.isWindows) { } 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( (nativeAssetsYaml, _) = await buildNativeAssetsWindows(
buildMode: buildInfo.mode, buildMode: buildInfo.mode,
targetPlatform: targetPlatform,
projectUri: projectUri, projectUri: projectUri,
flutterTester: true, flutterTester: true,
fileSystem: globals.fs, fileSystem: globals.fs,
......
...@@ -78,7 +78,7 @@ abstract class WindowsApp extends ApplicationPackage { ...@@ -78,7 +78,7 @@ abstract class WindowsApp extends ApplicationPackage {
@override @override
String get displayName => id; String get displayName => id;
String executable(BuildMode buildMode); String executable(BuildMode buildMode, TargetPlatform targetPlatform);
} }
class PrebuiltWindowsApp extends WindowsApp implements PrebuiltApplicationPackage { class PrebuiltWindowsApp extends WindowsApp implements PrebuiltApplicationPackage {
...@@ -91,7 +91,7 @@ class PrebuiltWindowsApp extends WindowsApp implements PrebuiltApplicationPackag ...@@ -91,7 +91,7 @@ class PrebuiltWindowsApp extends WindowsApp implements PrebuiltApplicationPackag
final String _executable; final String _executable;
@override @override
String executable(BuildMode buildMode) => _executable; String executable(BuildMode buildMode, TargetPlatform targetPlatform) => _executable;
@override @override
String get name => _executable; String get name => _executable;
...@@ -108,10 +108,10 @@ class BuildableWindowsApp extends WindowsApp { ...@@ -108,10 +108,10 @@ class BuildableWindowsApp extends WindowsApp {
final WindowsProject project; final WindowsProject project;
@override @override
String executable(BuildMode buildMode) { String executable(BuildMode buildMode, TargetPlatform targetPlatform) {
final String? binaryName = getCmakeExecutableName(project); final String? binaryName = getCmakeExecutableName(project);
return globals.fs.path.join( return globals.fs.path.join(
getWindowsBuildDirectory(TargetPlatform.windows_x64), getWindowsBuildDirectory(targetPlatform),
'runner', 'runner',
sentenceCase(buildMode.cliName), sentenceCase(buildMode.cliName),
'$binaryName.exe', '$binaryName.exe',
......
...@@ -30,7 +30,10 @@ import 'visual_studio.dart'; ...@@ -30,7 +30,10 @@ import 'visual_studio.dart';
const String _kBadCharacters = r"'#!$^&*=|,;<>?"; const String _kBadCharacters = r"'#!$^&*=|,;<>?";
/// Builds the Windows project using msbuild. /// Builds the Windows project using msbuild.
Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { Future<void> buildWindows(
WindowsProject windowsProject,
BuildInfo buildInfo,
TargetPlatform targetPlatform, {
String? target, String? target,
VisualStudio? visualStudioOverride, VisualStudio? visualStudioOverride,
SizeAnalyzer? sizeAnalyzer, SizeAnalyzer? sizeAnalyzer,
...@@ -56,8 +59,6 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { ...@@ -56,8 +59,6 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
'to learn about adding Windows support to a project.'); '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( final Directory buildDirectory = globals.fs.directory(globals.fs.path.join(
projectPath, projectPath,
getWindowsBuildDirectory(targetPlatform), getWindowsBuildDirectory(targetPlatform),
...@@ -83,6 +84,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { ...@@ -83,6 +84,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
platform: globals.platform, platform: globals.platform,
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
osUtils: globals.os,
); );
final String? cmakePath = visualStudio.cmakePath; final String? cmakePath = visualStudio.cmakePath;
final String? cmakeGenerator = visualStudio.cmakeGenerator; final String? cmakeGenerator = visualStudio.cmakeGenerator;
...@@ -99,9 +101,9 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { ...@@ -99,9 +101,9 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
await _runCmakeGeneration( await _runCmakeGeneration(
cmakePath: cmakePath, cmakePath: cmakePath,
generator: cmakeGenerator, generator: cmakeGenerator,
targetPlatform: targetPlatform,
buildDir: buildDirectory, buildDir: buildDirectory,
sourceDir: windowsProject.cmakeFile.parent, sourceDir: windowsProject.cmakeFile.parent,
targetPlatform: targetPlatform,
); );
if (visualStudio.displayVersion == '17.1.0') { if (visualStudio.displayVersion == '17.1.0') {
_fixBrokenCmakeGeneration(buildDirectory); _fixBrokenCmakeGeneration(buildDirectory);
...@@ -128,7 +130,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { ...@@ -128,7 +130,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
} }
if (buildInfo.codeSizeDirectory != null && sizeAnalyzer != null) { 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) final File codeSizeFile = globals.fs.directory(buildInfo.codeSizeDirectory)
.childFile('snapshot.$arch.json'); .childFile('snapshot.$arch.json');
final File precompilerTrace = globals.fs.directory(buildInfo.codeSizeDirectory) final File precompilerTrace = globals.fs.directory(buildInfo.codeSizeDirectory)
...@@ -165,23 +167,26 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, { ...@@ -165,23 +167,26 @@ Future<void> 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<void> _runCmakeGeneration({ Future<void> _runCmakeGeneration({
required String cmakePath, required String cmakePath,
required String generator, required String generator,
required TargetPlatform targetPlatform,
required Directory buildDir, required Directory buildDir,
required Directory sourceDir, required Directory sourceDir,
required TargetPlatform targetPlatform,
}) async { }) async {
if (targetPlatform != TargetPlatform.windows_x64) {
throwToolExit('Windows build supports only x64 target architecture');
}
final Stopwatch sw = Stopwatch()..start(); final Stopwatch sw = Stopwatch()..start();
await buildDir.create(recursive: true); await buildDir.create(recursive: true);
int result; int result;
const String arch = 'x64';
const String flutterTargetPlatform = 'windows-x64';
try { try {
result = await globals.processUtils.stream( result = await globals.processUtils.stream(
<String>[ <String>[
...@@ -193,8 +198,8 @@ Future<void> _runCmakeGeneration({ ...@@ -193,8 +198,8 @@ Future<void> _runCmakeGeneration({
'-G', '-G',
generator, generator,
'-A', '-A',
arch, getCmakeWindowsArch(targetPlatform),
'-DFLUTTER_TARGET_PLATFORM=$flutterTargetPlatform', '-DFLUTTER_TARGET_PLATFORM=${getNameForTargetPlatform(targetPlatform)}',
], ],
trace: true, trace: true,
); );
......
...@@ -73,6 +73,7 @@ Future<CCompilerConfig> cCompilerConfigWindows() async { ...@@ -73,6 +73,7 @@ Future<CCompilerConfig> cCompilerConfigWindows() async {
platform: globals.platform, platform: globals.platform,
logger: globals.logger, logger: globals.logger,
processManager: globals.processManager, processManager: globals.processManager,
osUtils: globals.os,
); );
return CCompilerConfig( return CCompilerConfig(
......
...@@ -9,6 +9,7 @@ import '../base/common.dart'; ...@@ -9,6 +9,7 @@ import '../base/common.dart';
import '../base/file_system.dart'; import '../base/file_system.dart';
import '../base/io.dart'; import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/os.dart' show HostPlatform, OperatingSystemUtils;
import '../base/platform.dart'; import '../base/platform.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../base/version.dart'; import '../base/version.dart';
...@@ -21,15 +22,18 @@ class VisualStudio { ...@@ -21,15 +22,18 @@ class VisualStudio {
required ProcessManager processManager, required ProcessManager processManager,
required Platform platform, required Platform platform,
required Logger logger, required Logger logger,
required OperatingSystemUtils osUtils,
}) : _platform = platform, }) : _platform = platform,
_fileSystem = fileSystem, _fileSystem = fileSystem,
_processUtils = ProcessUtils(processManager: processManager, logger: logger), _processUtils = ProcessUtils(processManager: processManager, logger: logger),
_logger = logger; _logger = logger,
_osUtils = osUtils;
final FileSystem _fileSystem; final FileSystem _fileSystem;
final Platform _platform; final Platform _platform;
final ProcessUtils _processUtils; final ProcessUtils _processUtils;
final Logger _logger; final Logger _logger;
final OperatingSystemUtils _osUtils;
/// Matches the description property from the vswhere.exe JSON output. /// Matches the description property from the vswhere.exe JSON output.
final RegExp _vswhereDescriptionProperty = RegExp(r'\s*"description"\s*:\s*".*"\s*,?'); final RegExp _vswhereDescriptionProperty = RegExp(r'\s*"description"\s*:\s*".*"\s*,?');
...@@ -208,6 +212,8 @@ class VisualStudio { ...@@ -208,6 +212,8 @@ class VisualStudio {
return null; return null;
} }
final String arch = _osUtils.hostPlatform == HostPlatform.windows_arm64 ? 'arm64': 'x64';
return _fileSystem.path.joinAll(<String>[ return _fileSystem.path.joinAll(<String>[
details.installationPath!, details.installationPath!,
'VC', 'VC',
...@@ -215,8 +221,8 @@ class VisualStudio { ...@@ -215,8 +221,8 @@ class VisualStudio {
'MSVC', 'MSVC',
details.msvcVersion!, details.msvcVersion!,
'bin', 'bin',
'Hostx64', 'Host$arch',
'x64', arch,
executable, executable,
]); ]);
} }
...@@ -229,12 +235,14 @@ class VisualStudio { ...@@ -229,12 +235,14 @@ class VisualStudio {
return null; return null;
} }
final String arch = _osUtils.hostPlatform == HostPlatform.windows_arm64 ? 'arm64': '64';
return _fileSystem.path.joinAll(<String>[ return _fileSystem.path.joinAll(<String>[
details.installationPath!, details.installationPath!,
'VC', 'VC',
'Auxiliary', 'Auxiliary',
'Build', 'Build',
'vcvars64.bat', 'vcvars$arch.bat',
]); ]);
} }
......
...@@ -24,7 +24,8 @@ class WindowsDevice extends DesktopDevice { ...@@ -24,7 +24,8 @@ class WindowsDevice extends DesktopDevice {
required Logger logger, required Logger logger,
required FileSystem fileSystem, required FileSystem fileSystem,
required OperatingSystemUtils operatingSystemUtils, required OperatingSystemUtils operatingSystemUtils,
}) : super( }) : _operatingSystemUtils = operatingSystemUtils,
super(
'windows', 'windows',
platformType: PlatformType.windows, platformType: PlatformType.windows,
ephemeral: false, ephemeral: false,
...@@ -34,6 +35,8 @@ class WindowsDevice extends DesktopDevice { ...@@ -34,6 +35,8 @@ class WindowsDevice extends DesktopDevice {
operatingSystemUtils: operatingSystemUtils, operatingSystemUtils: operatingSystemUtils,
); );
final OperatingSystemUtils _operatingSystemUtils;
@override @override
bool isSupported() => true; bool isSupported() => true;
...@@ -41,7 +44,12 @@ class WindowsDevice extends DesktopDevice { ...@@ -41,7 +44,12 @@ class WindowsDevice extends DesktopDevice {
String get name => 'Windows'; String get name => 'Windows';
@override @override
Future<TargetPlatform> get targetPlatform async => TargetPlatform.windows_x64; Future<TargetPlatform> get targetPlatform async => _targetPlatform;
TargetPlatform get _targetPlatform => switch (_operatingSystemUtils.hostPlatform) {
HostPlatform.windows_arm64 => TargetPlatform.windows_arm64,
_ => TargetPlatform.windows_x64,
};
@override @override
bool isSupportedForProject(FlutterProject flutterProject) { bool isSupportedForProject(FlutterProject flutterProject) {
...@@ -56,13 +64,14 @@ class WindowsDevice extends DesktopDevice { ...@@ -56,13 +64,14 @@ class WindowsDevice extends DesktopDevice {
await buildWindows( await buildWindows(
FlutterProject.current().windows, FlutterProject.current().windows,
buildInfo, buildInfo,
_targetPlatform,
target: mainPath, target: mainPath,
); );
} }
@override @override
String executablePathForDevice(covariant WindowsApp package, BuildInfo buildInfo) { String executablePathForDevice(covariant WindowsApp package, BuildInfo buildInfo) {
return package.executable(buildInfo.mode); return package.executable(buildInfo.mode, _targetPlatform);
} }
} }
......
...@@ -7,10 +7,12 @@ import 'package:file_testing/file_testing.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/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.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/cache.dart';
import 'package:flutter_tools/src/commands/build_windows.dart'; import 'package:flutter_tools/src/commands/build_windows.dart';
import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/reporting/reporting.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:flutter_tools/src/windows/visual_studio.dart';
import 'package:test/fake.dart'; import 'package:test/fake.dart';
import 'package:unified_analytics/unified_analytics.dart'; import 'package:unified_analytics/unified_analytics.dart';
...@@ -81,6 +83,7 @@ void main() { ...@@ -81,6 +83,7 @@ void main() {
FakeCommand cmakeGenerationCommand({ FakeCommand cmakeGenerationCommand({
void Function(List<String> command)? onRun, void Function(List<String> command)? onRun,
String generator = _defaultGenerator, String generator = _defaultGenerator,
TargetPlatform targetPlatform = TargetPlatform.windows_x64,
}) { }) {
return FakeCommand( return FakeCommand(
command: <String>[ command: <String>[
...@@ -92,7 +95,7 @@ void main() { ...@@ -92,7 +95,7 @@ void main() {
'-G', '-G',
generator, generator,
'-A', '-A',
'x64', getCmakeWindowsArch(targetPlatform),
'-DFLUTTER_TARGET_PLATFORM=windows-x64', '-DFLUTTER_TARGET_PLATFORM=windows-x64',
], ],
onRun: onRun, onRun: onRun,
...@@ -126,7 +129,7 @@ void main() { ...@@ -126,7 +129,7 @@ void main() {
} }
testUsingContext('Windows build fails when there is no cmake path', () async { 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); ..visualStudioOverride = FakeVisualStudio(cmakePath: null);
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -142,7 +145,7 @@ void main() { ...@@ -142,7 +145,7 @@ void main() {
testUsingContext('Windows build fails when there is no windows project', () async { testUsingContext('Windows build fails when there is no windows project', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockCoreProjectFiles(); setUpMockCoreProjectFiles();
...@@ -160,7 +163,7 @@ void main() { ...@@ -160,7 +163,7 @@ void main() {
testUsingContext('Windows build fails on non windows platform', () async { testUsingContext('Windows build fails on non windows platform', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -176,7 +179,7 @@ void main() { ...@@ -176,7 +179,7 @@ void main() {
testUsingContext('Windows build fails when feature is disabled', () async { testUsingContext('Windows build fails when feature is disabled', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -192,7 +195,7 @@ void main() { ...@@ -192,7 +195,7 @@ void main() {
testUsingContext('Windows build does not spew stdout to status logger', () async { testUsingContext('Windows build does not spew stdout to status logger', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -217,7 +220,7 @@ void main() { ...@@ -217,7 +220,7 @@ void main() {
testUsingContext('Windows build sends timing events', () async { testUsingContext('Windows build sends timing events', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -257,7 +260,7 @@ void main() { ...@@ -257,7 +260,7 @@ void main() {
testUsingContext('Windows build extracts errors from stdout', () async { testUsingContext('Windows build extracts errors from stdout', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -315,7 +318,7 @@ C:\foo\windows\x64\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identif ...@@ -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 { testUsingContext('Windows verbose build sets VERBOSE_SCRIPT_LOGGING', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -341,7 +344,7 @@ C:\foo\windows\x64\runner\main.cpp(17,1): error C2065: 'Baz': undeclared identif ...@@ -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 { testUsingContext('Windows build works around CMake generation bug', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(displayVersion: '17.1.0'); 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; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -478,7 +481,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -478,7 +481,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Windows build invokes build and writes generated files', () async { testUsingContext('Windows build invokes build and writes generated files', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -548,7 +551,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -548,7 +551,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Windows profile build passes Profile configuration', () async { testUsingContext('Windows profile build passes Profile configuration', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -571,7 +574,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -571,7 +574,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
const String generator = 'A different generator'; const String generator = 'A different generator';
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio( final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(
cmakeGenerator: generator); cmakeGenerator: generator);
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -592,7 +595,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -592,7 +595,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext("Windows build uses pubspec's version", () async { testUsingContext("Windows build uses pubspec's version", () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -638,7 +641,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -638,7 +641,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Windows build uses build-name and build-number', () async { testUsingContext('Windows build uses build-name and build-number', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -682,7 +685,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -682,7 +685,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Windows build build-name overrides pubspec', () async { testUsingContext('Windows build build-name overrides pubspec', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -729,7 +732,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -729,7 +732,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Windows build build-number overrides pubspec', () async { testUsingContext('Windows build build-number overrides pubspec', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -776,7 +779,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -776,7 +779,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Windows build build-name and build-number override pubspec', () async { testUsingContext('Windows build build-name and build-number override pubspec', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -824,7 +827,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -824,7 +827,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Windows build warns on non-numeric build-number', () async { testUsingContext('Windows build warns on non-numeric build-number', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -874,7 +877,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -874,7 +877,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Windows build warns on complex build-number', () async { testUsingContext('Windows build warns on complex build-number', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -923,14 +926,14 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -923,14 +926,14 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
}); });
testUsingContext('hidden when not enabled on Windows host', () { 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: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(), FeatureFlags: () => TestFeatureFlags(),
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
}); });
testUsingContext('Not hidden when enabled and on Windows host', () { 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: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true), FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
...@@ -938,7 +941,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -938,7 +941,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
testUsingContext('Performs code size analysis and sends analytics', () async { testUsingContext('Performs code size analysis and sends analytics', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
...@@ -994,7 +997,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -994,7 +997,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
// is resolved on the VS side, we can allow these paths again // is resolved on the VS side, we can allow these paths again
testUsingContext('Test bad path characters', () async { testUsingContext('Test bad path characters', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
fileSystem.currentDirectory = fileSystem.directory("test_'path") fileSystem.currentDirectory = fileSystem.directory("test_'path")
..createSync(); ..createSync();
...@@ -1021,7 +1024,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command> ...@@ -1021,7 +1024,7 @@ if %errorlevel% neq 0 goto :VCEnd</Command>
// And tests the case where stdout contains the error about missing assets // And tests the case where stdout contains the error about missing assets
testUsingContext('Windows build extracts errors related to pubspec.yaml from stdout', () async { testUsingContext('Windows build extracts errors related to pubspec.yaml from stdout', () async {
final FakeVisualStudio fakeVisualStudio = FakeVisualStudio(); final FakeVisualStudio fakeVisualStudio = FakeVisualStudio();
final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test()) final BuildWindowsCommand command = BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils())
..visualStudioOverride = fakeVisualStudio; ..visualStudioOverride = fakeVisualStudio;
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
......
...@@ -160,7 +160,7 @@ void main() { ...@@ -160,7 +160,7 @@ void main() {
expect(utils.hostPlatform, HostPlatform.linux_x64); expect(utils.hostPlatform, HostPlatform.linux_x64);
}); });
testWithoutContext('Windows', () async { testWithoutContext('Windows default', () async {
final OperatingSystemUtils utils = final OperatingSystemUtils utils =
createOSUtils(FakePlatform(operatingSystem: 'windows')); createOSUtils(FakePlatform(operatingSystem: 'windows'));
expect(utils.hostPlatform, HostPlatform.windows_x64); expect(utils.hostPlatform, HostPlatform.windows_x64);
......
...@@ -55,7 +55,7 @@ void main() { ...@@ -55,7 +55,7 @@ void main() {
} }
fileSystem.directory('windows').createSync(); fileSystem.directory('windows').createSync();
await const UnpackWindows().build(environment); await const UnpackWindows(TargetPlatform.windows_x64).build(environment);
// Output files are copied correctly. // Output files are copied correctly.
expect(fileSystem.file(r'C:\windows\flutter\ephemeral\flutter_export.h'), exists); expect(fileSystem.file(r'C:\windows\flutter\ephemeral\flutter_export.h'), exists);
...@@ -147,7 +147,7 @@ void main() { ...@@ -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. // Depfile is created and dill is copied.
expect(environment.buildDir.childFile('flutter_assets.d'), exists); expect(environment.buildDir.childFile('flutter_assets.d'), exists);
...@@ -175,7 +175,7 @@ void main() { ...@@ -175,7 +175,7 @@ void main() {
environment.buildDir.childFile('app.so').createSync(recursive: true); environment.buildDir.childFile('app.so').createSync(recursive: true);
await const WindowsAotBundle(AotElfProfile(TargetPlatform.windows_x64)).build(environment); 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. // Depfile is created and so is copied.
expect(environment.buildDir.childFile('flutter_assets.d'), exists); expect(environment.buildDir.childFile('flutter_assets.d'), exists);
...@@ -202,7 +202,7 @@ void main() { ...@@ -202,7 +202,7 @@ void main() {
environment.buildDir.childFile('app.so').createSync(recursive: true); environment.buildDir.childFile('app.so').createSync(recursive: true);
await const WindowsAotBundle(AotElfRelease(TargetPlatform.windows_x64)).build(environment); 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. // Depfile is created and so is copied.
expect(environment.buildDir.childFile('flutter_assets.d'), exists); expect(environment.buildDir.childFile('flutter_assets.d'), exists);
......
...@@ -615,7 +615,7 @@ void main() { ...@@ -615,7 +615,7 @@ void main() {
expect(artifacts.getBinaryDirs(), <List<String>>[ expect(artifacts.getBinaryDirs(), <List<String>>[
<String>['darwin-x64', 'darwin-arm64/font-subset.zip'], <String>['darwin-x64', 'darwin-arm64/font-subset.zip'],
<String>['linux-arm64', 'linux-arm64/font-subset.zip'], <String>['linux-arm64', 'linux-arm64/font-subset.zip'],
<String>['windows-x64', 'windows-x64/font-subset.zip'], // arm64 windows hosts are not supported now <String>['windows-arm64', 'windows-arm64/font-subset.zip'],
]); ]);
}); });
......
...@@ -52,7 +52,7 @@ void main() { ...@@ -52,7 +52,7 @@ void main() {
final Platform platform = FakePlatform(); final Platform platform = FakePlatform();
final BufferLogger logger = BufferLogger.test(); final BufferLogger logger = BufferLogger.test();
final List<FlutterCommand> commands = <FlutterCommand>[ final List<FlutterCommand> commands = <FlutterCommand>[
BuildWindowsCommand(logger: BufferLogger.test()), BuildWindowsCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()),
BuildLinuxCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()), BuildLinuxCommand(logger: BufferLogger.test(), operatingSystemUtils: FakeOperatingSystemUtils()),
BuildMacosCommand(logger: BufferLogger.test(), verboseHelp: false), BuildMacosCommand(logger: BufferLogger.test(), verboseHelp: false),
BuildWebCommand(fileSystem: fileSystem, logger: BufferLogger.test(), verboseHelp: false), BuildWebCommand(fileSystem: fileSystem, logger: BufferLogger.test(), verboseHelp: false),
......
...@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/windows/visual_studio.dart'; ...@@ -12,6 +12,7 @@ import 'package:flutter_tools/src/windows/visual_studio.dart';
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/fakes.dart';
const String programFilesPath = r'C:\Program Files (x86)'; const String programFilesPath = r'C:\Program Files (x86)';
const String visualStudioPath = programFilesPath + r'\Microsoft Visual Studio\2017\Community'; const String visualStudioPath = programFilesPath + r'\Microsoft Visual Studio\2017\Community';
...@@ -344,6 +345,7 @@ VisualStudioFixture setUpVisualStudio() { ...@@ -344,6 +345,7 @@ VisualStudioFixture setUpVisualStudio() {
platform: windowsPlatform, platform: windowsPlatform,
logger: logger, logger: logger,
processManager: processManager, processManager: processManager,
osUtils: FakeOperatingSystemUtils(),
); );
return VisualStudioFixture(visualStudio, fileSystem, processManager, logger); return VisualStudioFixture(visualStudio, fileSystem, processManager, logger);
} }
...@@ -382,6 +384,7 @@ void main() { ...@@ -382,6 +384,7 @@ void main() {
fileSystem: MemoryFileSystem.test(style: FileSystemStyle.windows), fileSystem: MemoryFileSystem.test(style: FileSystemStyle.windows),
platform: FakePlatform(operatingSystem: 'windows'), platform: FakePlatform(operatingSystem: 'windows'),
processManager: FakeProcessManager.any(), processManager: FakeProcessManager.any(),
osUtils: FakeOperatingSystemUtils(),
); );
expect(() => visualStudio.isInstalled, expect(() => visualStudio.isInstalled,
...@@ -404,6 +407,7 @@ void main() { ...@@ -404,6 +407,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
platform: windowsPlatform, platform: windowsPlatform,
processManager: fakeProcessManager, processManager: fakeProcessManager,
osUtils: FakeOperatingSystemUtils(),
); );
expect(visualStudio.isInstalled, false); expect(visualStudio.isInstalled, false);
...@@ -426,6 +430,7 @@ void main() { ...@@ -426,6 +430,7 @@ void main() {
fileSystem: fileSystem, fileSystem: fileSystem,
platform: windowsPlatform, platform: windowsPlatform,
processManager: fakeProcessManager, processManager: fakeProcessManager,
osUtils: FakeOperatingSystemUtils(),
); );
expect(visualStudio.isInstalled, false); expect(visualStudio.isInstalled, false);
......
...@@ -130,5 +130,5 @@ WindowsDevice setUpWindowsDevice({ ...@@ -130,5 +130,5 @@ WindowsDevice setUpWindowsDevice({
class FakeWindowsApp extends Fake implements WindowsApp { class FakeWindowsApp extends Fake implements WindowsApp {
@override @override
String executable(BuildMode buildMode) => '${buildMode.cliName}/executable'; String executable(BuildMode buildMode, TargetPlatform targetPlatform) => '${buildMode.cliName}/executable';
} }
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:ffi' show Abi;
import 'dart:io' as io; import 'dart:io' as io;
import 'package:file/file.dart'; import 'package:file/file.dart';
...@@ -41,11 +42,18 @@ void main() { ...@@ -41,11 +42,18 @@ void main() {
projectRoot = tempDir.childDirectory('hello'); projectRoot = tempDir.childDirectory('hello');
final String arch;
if (Abi.current() == Abi.windowsArm64) {
arch = 'arm64';
} else {
arch = 'x64';
}
releaseDir = fileSystem.directory(fileSystem.path.join( releaseDir = fileSystem.directory(fileSystem.path.join(
projectRoot.path, projectRoot.path,
'build', 'build',
'windows', 'windows',
'x64', arch,
'runner', 'runner',
'Release', 'Release',
)); ));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment