Skip to content

Commit

Permalink
Enable native compilation for windows-arm64 (#137618)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
pbo-linaro authored Jan 18, 2024
1 parent 6e39eb7 commit 5405592
Show file tree
Hide file tree
Showing 41 changed files with 258 additions and 110 deletions.
17 changes: 16 additions & 1 deletion bin/internal/update_dart_sdk.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
7 changes: 5 additions & 2 deletions dev/devicelab/lib/tasks/perf_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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'
Expand Down Expand Up @@ -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');
Expand Down
4 changes: 3 additions & 1 deletion dev/devicelab/lib/tasks/plugin_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
7 changes: 5 additions & 2 deletions dev/devicelab/lib/tasks/run_tests.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:async';
import 'dart:convert';
import 'dart:ffi';
import 'dart:io';

import '../framework/devices.dart';
Expand Down Expand Up @@ -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
Expand All @@ -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',
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter_tools/bin/tool_backend.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions packages/flutter_tools/lib/src/android/android_device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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');
}
}
Expand Down Expand Up @@ -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();
Expand Down
15 changes: 12 additions & 3 deletions packages/flutter_tools/lib/src/artifacts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.');
}
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions packages/flutter_tools/lib/src/base/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ class AOTSnapshotter {
TargetPlatform.linux_x64,
TargetPlatform.linux_arm64,
TargetPlatform.windows_x64,
TargetPlatform.windows_arm64,
].contains(platform);
}
}
22 changes: 18 additions & 4 deletions packages/flutter_tools/lib/src/base/os.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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) {}
Expand Down Expand Up @@ -607,15 +618,17 @@ enum HostPlatform {
darwin_arm64,
linux_x64,
linux_arm64,
windows_x64;
windows_x64,
windows_arm64;

String get platformName {
return switch (this) {
HostPlatform.darwin_x64 => 'x64',
HostPlatform.darwin_arm64 => 'arm64',
HostPlatform.linux_x64 => 'x64',
HostPlatform.linux_arm64 => 'arm64',
HostPlatform.windows_x64 => 'x64'
HostPlatform.windows_x64 => 'x64',
HostPlatform.windows_arm64 => 'arm64',
};
}
}
Expand All @@ -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',
};
}
7 changes: 7 additions & 0 deletions packages/flutter_tools/lib/src/build_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,7 @@ enum TargetPlatform {
linux_x64,
linux_arm64,
windows_x64,
windows_arm64,
fuchsia_arm64,
fuchsia_x64,
tester,
Expand Down Expand Up @@ -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');
}
}
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class NativeAssets extends Target {
fileSystem,
buildRunner,
);
case TargetPlatform.windows_arm64:
case TargetPlatform.windows_x64:
dependencies = await _buildWindows(
environment,
Expand Down Expand Up @@ -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.');
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading

0 comments on commit 5405592

Please sign in to comment.