Skip to content

Commit 5405592

Browse files
authored
Enable native compilation for windows-arm64 (#137618)
It's now possible to natively compile a flutter app for windows-arm64. Cross-compilation is not yet implemented. Uses arm64 artifacts now available for Dart/Flutter. Platform detection is based on Abi class, provided by Dart. Depending if Dart is an arm64 or x64 binary, the Abi is set accordingly. Initial bootstrap of dart artifacts (update_dart_sdk.ps1) is checking PROCESSOR_ARCHITECTURE environment variable, which is the way to detect host architecture on Windows. This is available only for master channel (on other channels, it fallbacks to windows-x64). On windows-x64, it produces an x64 app. On windows-arm64, it produces an arm64 app.
1 parent 6e39eb7 commit 5405592

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+258
-110
lines changed

bin/internal/update_dart_sdk.ps1

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,22 @@ if (-not $dartSdkBaseUrl) {
4747
if ($engineRealm) {
4848
$dartSdkBaseUrl = "$dartSdkBaseUrl/$engineRealm"
4949
}
50-
$dartZipName = "dart-sdk-windows-x64.zip"
50+
51+
# It's important to use the native Dart SDK as the default target architecture
52+
# for Flutter Windows builds depend on the Dart executable's architecture.
53+
$dartZipNameX64 = "dart-sdk-windows-x64.zip"
54+
$dartZipNameArm64 = "dart-sdk-windows-arm64.zip"
55+
$dartZipName = $dartZipNameX64
56+
if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64") {
57+
$dartSdkArm64Url = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipNameArm64"
58+
Try {
59+
Invoke-WebRequest -Uri $dartSdkArm64Url -UseBasicParsing -Method Head | Out-Null
60+
$dartZipName = $dartZipNameArm64
61+
}
62+
Catch {
63+
Write-Host "The current channel's Dart SDK does not support Windows Arm64, falling back to Windows x64..."
64+
}
65+
}
5166
$dartSdkUrl = "$dartSdkBaseUrl/flutter_infra_release/flutter/$engineVersion/$dartZipName"
5267

5368
if ((Test-Path $dartSdkPath) -or (Test-Path $dartSdkLicense)) {

dev/devicelab/lib/tasks/perf_tests.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:async';
66
import 'dart:convert' show LineSplitter, json, utf8;
7+
import 'dart:ffi' show Abi;
78
import 'dart:io';
89
import 'dart:math' as math;
910

@@ -953,11 +954,12 @@ class StartupTest {
953954
'--target=$target',
954955
]);
955956
final String basename = path.basename(testDirectory);
957+
final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64';
956958
applicationBinaryPath = path.join(
957959
testDirectory,
958960
'build',
959961
'windows',
960-
'x64',
962+
arch,
961963
'runner',
962964
'Profile',
963965
'$basename.exe'
@@ -1763,11 +1765,12 @@ class CompileTest {
17631765
await flutter('build', options: options);
17641766
watch.stop();
17651767
final String basename = path.basename(cwd);
1768+
final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64';
17661769
final String exePath = path.join(
17671770
cwd,
17681771
'build',
17691772
'windows',
1770-
'x64',
1773+
arch,
17711774
'runner',
17721775
'release',
17731776
'$basename.exe');

dev/devicelab/lib/tasks/plugin_tests.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:ffi';
56
import 'dart:io';
67

78
import 'package:path/path.dart' as path;
@@ -328,8 +329,9 @@ public class $pluginClass: NSObject, FlutterPlugin {
328329
throw TaskResult.failure('Platform unit tests failed');
329330
}
330331
case 'windows':
332+
final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64';
331333
if (await exec(
332-
path.join(rootPath, 'build', 'windows', 'x64', 'plugins', 'plugintest', 'Release', 'plugintest_test.exe'),
334+
path.join(rootPath, 'build', 'windows', arch, 'plugins', 'plugintest', 'Release', 'plugintest_test.exe'),
333335
<String>[],
334336
canFail: true,
335337
) != 0) {

dev/devicelab/lib/tasks/run_tests.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import 'dart:async';
66
import 'dart:convert';
7+
import 'dart:ffi';
78
import 'dart:io';
89

910
import '../framework/devices.dart';
@@ -173,12 +174,14 @@ class WindowsRunOutputTest extends DesktopRunOutputTest {
173174
}
174175
);
175176

177+
final String arch = Abi.current() == Abi.windowsX64 ? 'x64': 'arm64';
178+
176179
static final RegExp _buildOutput = RegExp(
177180
r'Building Windows application\.\.\.\s*\d+(\.\d+)?(ms|s)',
178181
multiLine: true,
179182
);
180183
static final RegExp _builtOutput = RegExp(
181-
r'Built build\\windows\\x64\\runner\\(Debug|Release)\\\w+\.exe( \(\d+(\.\d+)?MB\))?\.',
184+
r'Built build\\windows\\(x64|arm64)\\runner\\(Debug|Release)\\\w+\.exe( \(\d+(\.\d+)?MB\))?\.',
182185
);
183186

184187
@override
@@ -205,7 +208,7 @@ class WindowsRunOutputTest extends DesktopRunOutputTest {
205208

206209
return true;
207210
},
208-
'Built build\\windows\\x64\\runner\\$buildMode\\app.exe',
211+
'Built build\\windows\\$arch\\runner\\$buildMode\\app.exe',
209212
);
210213
}
211214
}

packages/flutter_tools/bin/tool_backend.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ or
7676
else
7777
'flutter',
7878
]);
79-
final String bundlePlatform = targetPlatform.startsWith('windows') ? 'windows' : targetPlatform;
79+
final String bundlePlatform = targetPlatform;
8080
final String target = '${buildMode}_bundle_${bundlePlatform}_assets';
8181
final Process assembleProcess = await Process.start(
8282
flutterExecutable,

packages/flutter_tools/lib/src/android/android_device.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ class AndroidDevice extends Device {
234234
case TargetPlatform.tester:
235235
case TargetPlatform.web_javascript:
236236
case TargetPlatform.windows_x64:
237+
case TargetPlatform.windows_arm64:
237238
throw UnsupportedError('Invalid target platform for Android');
238239
}
239240
}
@@ -570,6 +571,7 @@ class AndroidDevice extends Device {
570571
case TargetPlatform.linux_x64:
571572
case TargetPlatform.tester:
572573
case TargetPlatform.web_javascript:
574+
case TargetPlatform.windows_arm64:
573575
case TargetPlatform.windows_x64:
574576
_logger.printError('Android platforms are only supported.');
575577
return LaunchResult.failed();

packages/flutter_tools/lib/src/artifacts.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ TargetPlatform? _mapTargetPlatform(TargetPlatform? targetPlatform) {
144144
case TargetPlatform.linux_x64:
145145
case TargetPlatform.linux_arm64:
146146
case TargetPlatform.windows_x64:
147+
case TargetPlatform.windows_arm64:
147148
case TargetPlatform.fuchsia_arm64:
148149
case TargetPlatform.fuchsia_x64:
149150
case TargetPlatform.tester:
@@ -526,6 +527,7 @@ class CachedArtifacts implements Artifacts {
526527
case TargetPlatform.linux_x64:
527528
case TargetPlatform.linux_arm64:
528529
case TargetPlatform.windows_x64:
530+
case TargetPlatform.windows_arm64:
529531
return _getDesktopArtifactPath(artifact, platform, mode);
530532
case TargetPlatform.fuchsia_arm64:
531533
case TargetPlatform.fuchsia_x64:
@@ -743,8 +745,9 @@ class CachedArtifacts implements Artifacts {
743745
final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
744746
return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode));
745747
case Artifact.windowsCppClientWrapper:
748+
final String platformDirName = _enginePlatformDirectoryName(platform);
746749
final String engineArtifactsPath = _cache.getArtifactDirectory('engine').path;
747-
return _fileSystem.path.join(engineArtifactsPath, 'windows-x64', _artifactToFileName(artifact, _platform, mode));
750+
return _fileSystem.path.join(engineArtifactsPath, platformDirName, _artifactToFileName(artifact, _platform, mode));
748751
case Artifact.skyEnginePath:
749752
final Directory dartPackageDirectory = _cache.getCacheDir('pkg');
750753
return _fileSystem.path.join(dartPackageDirectory.path, _artifactToFileName(artifact, _platform));
@@ -775,6 +778,7 @@ class CachedArtifacts implements Artifacts {
775778
case TargetPlatform.linux_arm64:
776779
case TargetPlatform.darwin:
777780
case TargetPlatform.windows_x64:
781+
case TargetPlatform.windows_arm64:
778782
// TODO(zanderso): remove once debug desktop artifacts are uploaded
779783
// under a separate directory from the host artifacts.
780784
// https://github.com/flutter/flutter/issues/38935
@@ -813,10 +817,11 @@ TargetPlatform _currentHostPlatform(Platform platform, OperatingSystemUtils oper
813817
}
814818
if (platform.isLinux) {
815819
return operatingSystemUtils.hostPlatform == HostPlatform.linux_x64 ?
816-
TargetPlatform.linux_x64 : TargetPlatform.linux_arm64;
820+
TargetPlatform.linux_x64 : TargetPlatform.linux_arm64;
817821
}
818822
if (platform.isWindows) {
819-
return TargetPlatform.windows_x64;
823+
return operatingSystemUtils.hostPlatform == HostPlatform.windows_arm64 ?
824+
TargetPlatform.windows_arm64 : TargetPlatform.windows_x64;
820825
}
821826
throw UnimplementedError('Host OS not supported.');
822827
}
@@ -1089,6 +1094,8 @@ class CachedLocalEngineArtifacts implements Artifacts {
10891094
return 'linux-x64';
10901095
case TargetPlatform.windows_x64:
10911096
return 'windows-x64';
1097+
case TargetPlatform.windows_arm64:
1098+
return 'windows-arm64';
10921099
case TargetPlatform.ios:
10931100
case TargetPlatform.android:
10941101
case TargetPlatform.android_arm:
@@ -1290,6 +1297,8 @@ class CachedLocalWebSdkArtifacts implements Artifacts {
12901297
return 'linux-x64';
12911298
case TargetPlatform.windows_x64:
12921299
return 'windows-x64';
1300+
case TargetPlatform.windows_arm64:
1301+
return 'windows-arm64';
12931302
case TargetPlatform.ios:
12941303
case TargetPlatform.android:
12951304
case TargetPlatform.android_arm:

packages/flutter_tools/lib/src/base/build.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ class AOTSnapshotter {
347347
TargetPlatform.linux_x64,
348348
TargetPlatform.linux_arm64,
349349
TargetPlatform.windows_x64,
350+
TargetPlatform.windows_arm64,
350351
].contains(platform);
351352
}
352353
}

packages/flutter_tools/lib/src/base/os.dart

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:ffi' show Abi;
6+
57
import 'package:archive/archive.dart';
68
import 'package:file/file.dart';
79
import 'package:meta/meta.dart';
@@ -472,8 +474,17 @@ class _WindowsUtils extends OperatingSystemUtils {
472474
required super.processManager,
473475
}) : super._private();
474476

477+
HostPlatform? _hostPlatform;
478+
475479
@override
476-
HostPlatform hostPlatform = HostPlatform.windows_x64;
480+
HostPlatform get hostPlatform {
481+
if (_hostPlatform == null) {
482+
final Abi abi = Abi.current();
483+
_hostPlatform = (abi == Abi.windowsArm64) ? HostPlatform.windows_arm64 :
484+
HostPlatform.windows_x64;
485+
}
486+
return _hostPlatform!;
487+
}
477488

478489
@override
479490
void makeExecutable(File file) {}
@@ -607,15 +618,17 @@ enum HostPlatform {
607618
darwin_arm64,
608619
linux_x64,
609620
linux_arm64,
610-
windows_x64;
621+
windows_x64,
622+
windows_arm64;
611623

612624
String get platformName {
613625
return switch (this) {
614626
HostPlatform.darwin_x64 => 'x64',
615627
HostPlatform.darwin_arm64 => 'arm64',
616628
HostPlatform.linux_x64 => 'x64',
617629
HostPlatform.linux_arm64 => 'arm64',
618-
HostPlatform.windows_x64 => 'x64'
630+
HostPlatform.windows_x64 => 'x64',
631+
HostPlatform.windows_arm64 => 'arm64',
619632
};
620633
}
621634
}
@@ -626,6 +639,7 @@ String getNameForHostPlatform(HostPlatform platform) {
626639
HostPlatform.darwin_arm64 => 'darwin-arm64',
627640
HostPlatform.linux_x64 => 'linux-x64',
628641
HostPlatform.linux_arm64 => 'linux-arm64',
629-
HostPlatform.windows_x64 => 'windows-x64'
642+
HostPlatform.windows_x64 => 'windows-x64',
643+
HostPlatform.windows_arm64 => 'windows-arm64',
630644
};
631645
}

packages/flutter_tools/lib/src/build_info.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@ enum TargetPlatform {
513513
linux_x64,
514514
linux_arm64,
515515
windows_x64,
516+
windows_arm64,
516517
fuchsia_arm64,
517518
fuchsia_x64,
518519
tester,
@@ -544,6 +545,7 @@ enum TargetPlatform {
544545
case TargetPlatform.tester:
545546
case TargetPlatform.web_javascript:
546547
case TargetPlatform.windows_x64:
548+
case TargetPlatform.windows_arm64:
547549
throw UnsupportedError('Unexpected Fuchsia platform $this');
548550
}
549551
}
@@ -555,6 +557,7 @@ enum TargetPlatform {
555557
case TargetPlatform.windows_x64:
556558
return 'x64';
557559
case TargetPlatform.linux_arm64:
560+
case TargetPlatform.windows_arm64:
558561
return 'arm64';
559562
case TargetPlatform.android:
560563
case TargetPlatform.android_arm:
@@ -713,6 +716,8 @@ String getNameForTargetPlatform(TargetPlatform platform, {DarwinArch? darwinArch
713716
return 'linux-arm64';
714717
case TargetPlatform.windows_x64:
715718
return 'windows-x64';
719+
case TargetPlatform.windows_arm64:
720+
return 'windows-arm64';
716721
case TargetPlatform.fuchsia_arm64:
717722
return 'fuchsia-arm64';
718723
case TargetPlatform.fuchsia_x64:
@@ -756,6 +761,8 @@ TargetPlatform getTargetPlatformForName(String platform) {
756761
return TargetPlatform.linux_arm64;
757762
case 'windows-x64':
758763
return TargetPlatform.windows_x64;
764+
case 'windows-arm64':
765+
return TargetPlatform.windows_arm64;
759766
case 'web-javascript':
760767
return TargetPlatform.web_javascript;
761768
case 'flutter-tester':

0 commit comments

Comments
 (0)