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) {
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)) {
......
......@@ -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');
......
......@@ -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'),
<String>[],
canFail: true,
) != 0) {
......
......@@ -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',
);
}
}
......
......@@ -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,
......
......@@ -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();
......
......@@ -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:
......
......@@ -347,6 +347,7 @@ class AOTSnapshotter {
TargetPlatform.linux_x64,
TargetPlatform.linux_arm64,
TargetPlatform.windows_x64,
TargetPlatform.windows_arm64,
].contains(platform);
}
}
......@@ -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',
};
}
......@@ -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':
......
......@@ -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,
};
......
......@@ -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.');
}
}
......
......@@ -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:
......
......@@ -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: <String>[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<Target> get dependencies => const <Target>[
KernelSnapshot(),
UnpackWindows(),
List<Target> get dependencies => <Target>[
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<Source> get outputs => const <Source>[];
......@@ -198,15 +202,15 @@ class ReleaseBundleWindowsAssets extends BundleWindowsAssets {
@override
List<Target> get dependencies => <Target>[
...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<Source> get outputs => const <Source>[];
......@@ -214,15 +218,15 @@ class ProfileBundleWindowsAssets extends BundleWindowsAssets {
@override
List<Target> get dependencies => <Target>[
...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<Source> get inputs => <Source>[
......
......@@ -73,10 +73,14 @@ List<Target> _kDefaultTargets = <Target>[
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
......
......@@ -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!,
......
......@@ -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.');
}
......
......@@ -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
......
......@@ -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(
......
......@@ -351,6 +351,7 @@ Future<T> runInContext<T>(
platform: globals.platform,
logger: globals.logger,
processManager: globals.processManager,
osUtils: globals.os,
)
),
WebWorkflow: () => WebWorkflow(
......
......@@ -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);
......
......@@ -235,18 +235,18 @@ class FlutterSdk extends EngineCachedArtifact {
@override
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();
return <List<String>>[
<String>['common', 'flutter_patched_sdk.zip'],
<String>['common', 'flutter_patched_sdk_product.zip'],
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>['darwin-x64', 'darwin-$arch/artifacts.zip'],
]
else if (_platform.isWindows)
<String>['windows-x64', 'windows-x64/artifacts.zip']
<String>['windows-$arch', 'windows-$arch/artifacts.zip']
else if (_platform.isMacOS)
<String>['darwin-x64', 'darwin-$arch/artifacts.zip']
else if (_platform.isLinux)
......@@ -304,7 +304,8 @@ class WindowsEngineArtifacts extends EngineCachedArtifact {
@override
List<List<String>> getBinaryDirs() {
if (_platform.isWindows || ignorePlatformFiltering) {
return _windowsDesktopBinaryDirs;
final String arch = cache.getHostPlatformArchName();
return _getWindowsDesktopBinaryDirs(arch);
}
return const <List<String>>[];
}
......@@ -739,12 +740,12 @@ class FontSubsetArtifacts extends EngineCachedArtifact {
@override
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 Map<String, List<String>> artifacts = <String, List<String>> {
'macos': <String>['darwin-x64', 'darwin-$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) {
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<List<String>> _windowsDesktopBinaryDirs = <List<String>>[
<String>['windows-x64', 'windows-x64-debug/windows-x64-flutter.zip'],
<String>['windows-x64', 'windows-x64/flutter-cpp-client-wrapper.zip'],
<String>['windows-x64-profile', 'windows-x64-profile/windows-x64-flutter.zip'],
<String>['windows-x64-release', 'windows-x64-release/windows-x64-flutter.zip'],
];
List<List<String>> _getWindowsDesktopBinaryDirs(String arch) {
return <List<String>>[
<String>['windows-$arch', 'windows-$arch-debug/windows-$arch-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>>[
<String>['darwin-x64', 'darwin-x64/FlutterMacOS.framework.zip'],
......
......@@ -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.');
}
}
......
......@@ -379,6 +379,7 @@ Future<Uri?> 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<Uri?> 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:
......
......@@ -1630,6 +1630,7 @@ Future<String?> getMissingPackageHintForPlatform(TargetPlatform platform) async
case TargetPlatform.tester:
case TargetPlatform.web_javascript:
case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
return null;
}
}
......
......@@ -1962,6 +1962,7 @@ DevelopmentArtifact? artifactFromTargetPlatform(TargetPlatform targetPlatform) {
}
return null;
case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
if (featureFlags.isWindowsEnabled) {
return DevelopmentArtifact.windows;
}
......
......@@ -54,6 +54,7 @@ Future<String?> sharedSkSlWriter(Device device, Map<String, Object?>? data, {
case TargetPlatform.tester:
case TargetPlatform.web_javascript:
case TargetPlatform.windows_x64:
case TargetPlatform.windows_arm64:
break;
}
final Map<String, Object> manifest = <String, Object>{
......
......@@ -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,
......
......@@ -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',
......
......@@ -30,7 +30,10 @@ import 'visual_studio.dart';
const String _kBadCharacters = r"'#!$^&*=|,;<>?";
/// Builds the Windows project using msbuild.
Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {
Future<void> buildWindows(
WindowsProject windowsProject,
BuildInfo buildInfo,
TargetPlatform targetPlatform, {
String? target,
VisualStudio? visualStudioOverride,
SizeAnalyzer? sizeAnalyzer,
......@@ -56,8 +59,6 @@ Future<void> 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<void> 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<void> 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<void> 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<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({
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(
<String>[
......@@ -193,8 +198,8 @@ Future<void> _runCmakeGeneration({
'-G',
generator,
'-A',
arch,
'-DFLUTTER_TARGET_PLATFORM=$flutterTargetPlatform',
getCmakeWindowsArch(targetPlatform),
'-DFLUTTER_TARGET_PLATFORM=${getNameForTargetPlatform(targetPlatform)}',
],
trace: true,
);
......
......@@ -73,6 +73,7 @@ Future<CCompilerConfig> cCompilerConfigWindows() async {
platform: globals.platform,
logger: globals.logger,
processManager: globals.processManager,
osUtils: globals.os,
);
return CCompilerConfig(
......
......@@ -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(<String>[
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(<String>[
details.installationPath!,
'VC',
'Auxiliary',
'Build',
'vcvars64.bat',
'vcvars$arch.bat',
]);
}
......
......@@ -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<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
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);
}
}
......
......@@ -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);
......
......@@ -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);
......
......@@ -615,7 +615,7 @@ void main() {
expect(artifacts.getBinaryDirs(), <List<String>>[
<String>['darwin-x64', 'darwin-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() {
final Platform platform = FakePlatform();
final BufferLogger logger = BufferLogger.test();
final List<FlutterCommand> commands = <FlutterCommand>[
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),
......
......@@ -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);
......
......@@ -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';
}
......@@ -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',
));
......
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