Skip to content

Commit 9c88769

Browse files
iinozemtsevCommit Queue
authored andcommitted
Dartdev cross compilation support
- Add `target-arch` option to `dart compile exe|aot-snapshot` - Add artifacts cache in `~/.dart`, and download gen_snapshot and dartaotruntime from cloud storage if necessary I've manually built an aot snapshot and exe on macOS ARM64 for Linux X64, copied them over to a linux machine, and made sure they work. Change-Id: I74dd581ecb573ff4069a2fe19f9d04aaa352538e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417801 Reviewed-by: Tess Strickland <[email protected]> Commit-Queue: Ivan Inozemtsev <[email protected]> Reviewed-by: Ben Konyi <[email protected]>
1 parent cfba919 commit 9c88769

File tree

11 files changed

+777
-142
lines changed

11 files changed

+777
-142
lines changed

pkg/dart2native/lib/dart2native.dart

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'dart:typed_data';
77

88
import 'package:collection/collection.dart';
99
import 'package:kernel/binary/tag.dart' show Tag;
10+
import 'package:native_assets_cli/code_assets_builder.dart' show OS;
1011
import 'package:path/path.dart' as path;
1112

1213
import 'dart2native_macho.dart' show writeAppendedMachOExecutable;
@@ -19,7 +20,7 @@ final genKernel = path.join(
1920
'snapshots',
2021
'gen_kernel_aot.dart.snapshot',
2122
);
22-
final genSnapshot = path.join(
23+
final genSnapshotHost = path.join(
2324
binDir.path,
2425
'utils',
2526
'gen_snapshot$executableSuffix',
@@ -65,36 +66,38 @@ Future<bool> isKernelFile(String path) async {
6566
// WARNING: this method is used within google3, so don't try to refactor so
6667
// [dartaotruntime] is a constant inside this file.
6768
Future<void> writeAppendedExecutable(
68-
String dartaotruntime,
69+
String dartAotRuntime,
6970
String payloadPath,
7071
String outputPath,
72+
OS targetOS,
7173
) async {
72-
if (Platform.isMacOS) {
73-
return await writeAppendedMachOExecutable(
74-
dartaotruntime, payloadPath, outputPath);
75-
} else if (Platform.isWindows) {
76-
return await writeAppendedPortableExecutable(
77-
dartaotruntime, payloadPath, outputPath);
74+
switch (targetOS) {
75+
case OS.macOS:
76+
return await writeAppendedMachOExecutable(
77+
dartAotRuntime, payloadPath, outputPath);
78+
case OS.windows:
79+
return await writeAppendedPortableExecutable(
80+
dartAotRuntime, payloadPath, outputPath);
81+
default:
82+
final dartAotRuntimeFile = File(dartAotRuntime);
83+
final dartAotRuntimeLength = dartAotRuntimeFile.lengthSync();
84+
85+
final padding = (elfPageSize - dartAotRuntimeLength) % elfPageSize;
86+
final padBytes = Uint8List(padding);
87+
final offset = dartAotRuntimeLength + padding;
88+
89+
// Note: The offset is always Little Endian regardless of host.
90+
final offsetBytes = ByteData(8) // 64 bit in bytes.
91+
..setUint64(0, offset, Endian.little);
92+
93+
final outputFile = File(outputPath).openWrite();
94+
outputFile.add(dartAotRuntimeFile.readAsBytesSync());
95+
outputFile.add(padBytes);
96+
outputFile.add(File(payloadPath).readAsBytesSync());
97+
outputFile.add(offsetBytes.buffer.asUint8List());
98+
outputFile.add(appJitMagicNumber);
99+
await outputFile.close();
78100
}
79-
80-
final dartaotruntimeFile = File(dartaotruntime);
81-
final dartaotruntimeLength = dartaotruntimeFile.lengthSync();
82-
83-
final padding = (elfPageSize - dartaotruntimeLength) % elfPageSize;
84-
final padBytes = Uint8List(padding);
85-
final offset = dartaotruntimeLength + padding;
86-
87-
// Note: The offset is always Little Endian regardless of host.
88-
final offsetBytes = ByteData(8) // 64 bit in bytes.
89-
..setUint64(0, offset, Endian.little);
90-
91-
final outputFile = File(outputPath).openWrite();
92-
outputFile.add(dartaotruntimeFile.readAsBytesSync());
93-
outputFile.add(padBytes);
94-
outputFile.add(File(payloadPath).readAsBytesSync());
95-
outputFile.add(offsetBytes.buffer.asUint8List());
96-
outputFile.add(appJitMagicNumber);
97-
await outputFile.close();
98101
}
99102

100103
Future<ProcessResult> markExecutable(String outputFile) {
@@ -106,13 +109,13 @@ Future<ProcessResult> markExecutable(String outputFile) {
106109
/// Also takes a path to the [recordedUsagesFile] JSON file, where the method
107110
/// calls to static functions annotated with `@RecordUse` will be collected.
108111
Future<ProcessResult> generateKernelHelper({
109-
required String dartaotruntime,
112+
required String hostDartAotRuntime,
110113
String? sourceFile,
111114
required String kernelFile,
112115
String? packages,
113116
List<String> defines = const [],
114117
String enableExperiment = '',
115-
String? targetOS,
118+
OS? targetOS,
116119
List<String> extraGenKernelOptions = const [],
117120
String? nativeAssets,
118121
String? recordedUsagesFile,
@@ -145,10 +148,11 @@ Future<ProcessResult> generateKernelHelper({
145148
...extraGenKernelOptions,
146149
if (sourceFile != null) sourceFile,
147150
];
148-
return Process.run(dartaotruntime, args);
151+
return Process.run(hostDartAotRuntime, args);
149152
}
150153

151154
Future<ProcessResult> generateAotSnapshotHelper(
155+
String genSnapshot,
152156
String kernelFile,
153157
String snapshotFile,
154158
String? debugFile,

pkg/dart2native/lib/generate.dart

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44

55
import 'dart:io';
66

7+
import 'package:native_assets_cli/code_assets_builder.dart' show OS;
78
import 'package:path/path.dart' as path;
89

910
import 'dart2native.dart';
1011
import 'src/generate_utils.dart';
1112

12-
export 'dart2native.dart' show genKernel, genSnapshot;
13+
export 'dart2native.dart' show genKernel, genSnapshotHost;
1314

14-
final dartaotruntime = path.join(
15+
final hostDartAotRuntime = path.join(
1516
binDir.path,
1617
'dartaotruntime$executableSuffix',
1718
);
@@ -34,20 +35,24 @@ enum Kind {
3435
/// See also the docs for [_Generator].
3536
extension type KernelGenerator._(_Generator _generator) {
3637
KernelGenerator({
38+
required String genSnapshot,
39+
required String targetDartAotRuntime,
3740
required String sourceFile,
3841
required List<String> defines,
3942
Kind kind = Kind.exe,
4043
String? outputFile,
4144
String? debugFile,
4245
String? packages,
43-
String? targetOS,
46+
OS? targetOS,
4447
String? depFile,
4548
String enableExperiment = '',
4649
bool enableAsserts = false,
4750
bool verbose = false,
4851
String verbosity = 'all',
4952
required Directory tempDir,
5053
}) : _generator = _Generator(
54+
genSnapshot: genSnapshot,
55+
targetDartAotRuntime: targetDartAotRuntime,
5156
sourceFile: sourceFile,
5257
defines: defines,
5358
tempDir: tempDir,
@@ -123,7 +128,7 @@ class _Generator {
123128
/// Specifies the operating system the executable is being generated for. This
124129
/// must be provided when [_kind] is [Kind.exe], and it must match the current
125130
/// operating system.
126-
final String? _targetOS;
131+
final OS? _targetOS;
127132

128133
/// A comma separated list of language experiments to be enabled.
129134
final String _enableExperiment;
@@ -153,14 +158,22 @@ class _Generator {
153158
/// The path to the [depfile](https://ninja-build.org/manual.html#_depfile).
154159
final String? _depFile;
155160

161+
/// The path to the `gen_snapshot` tool.
162+
final String _genSnapshot;
163+
164+
/// The path to the `dartaotruntime` for a target platform.
165+
final String _targetDartAotRuntime;
166+
156167
_Generator({
168+
required String genSnapshot,
169+
required String targetDartAotRuntime,
157170
required String sourceFile,
158171
required List<String> defines,
159172
required Kind kind,
160173
String? outputFile,
161174
String? debugFile,
162175
String? packages,
163-
String? targetOS,
176+
OS? targetOS,
164177
String? depFile,
165178
required String enableExperiment,
166179
required bool enableAsserts,
@@ -180,13 +193,12 @@ class _Generator {
180193
_depFile = depFile,
181194
_programKernelFile = path.join(tempDir.path, 'program.dill'),
182195
_sourcePath = _normalize(sourceFile)!,
183-
_packages = _normalize(packages) {
196+
_packages = _normalize(packages),
197+
_genSnapshot = genSnapshot,
198+
_targetDartAotRuntime = targetDartAotRuntime {
184199
if (_kind == Kind.exe) {
185200
if (_targetOS == null) {
186201
throw ArgumentError('targetOS must be specified for executables.');
187-
} else if (_targetOS != Platform.operatingSystem) {
188-
throw UnsupportedError(
189-
'Cross compilation not supported for executables.');
190202
}
191203
}
192204
}
@@ -203,7 +215,7 @@ class _Generator {
203215
}
204216

205217
final kernelResult = await generateKernelHelper(
206-
dartaotruntime: dartaotruntime,
218+
hostDartAotRuntime: hostDartAotRuntime,
207219
sourceFile: _sourcePath,
208220
kernelFile: _programKernelFile,
209221
packages: _packages,
@@ -256,12 +268,13 @@ class _Generator {
256268

257269
if (_verbose) {
258270
print('Compiling $_sourcePath to $outputPath using format $_kind:');
259-
print('Generating AOT snapshot. $genSnapshot $extraOptions');
271+
print('Generating AOT snapshot. $_genSnapshot $extraOptions');
260272
}
261273
final snapshotFile = _kind == Kind.aot
262274
? outputPath
263275
: path.join(_tempDir.path, 'snapshot.aot');
264276
final snapshotResult = await generateAotSnapshotHelper(
277+
_genSnapshot,
265278
kernelFile,
266279
snapshotFile,
267280
debugPath,
@@ -280,7 +293,8 @@ class _Generator {
280293
if (_verbose) {
281294
print('Generating executable.');
282295
}
283-
await writeAppendedExecutable(dartaotruntime, snapshotFile, outputPath);
296+
await writeAppendedExecutable(
297+
_targetDartAotRuntime, snapshotFile, outputPath, _targetOS!);
284298

285299
if (Platform.isLinux || Platform.isMacOS) {
286300
if (_verbose) {
@@ -302,7 +316,7 @@ class _Generator {
302316
final nativeAssetsDillFile =
303317
path.join(_tempDir.path, 'native_assets.dill');
304318
final kernelResult = await generateKernelHelper(
305-
dartaotruntime: dartaotruntime,
319+
hostDartAotRuntime: hostDartAotRuntime,
306320
kernelFile: nativeAssetsDillFile,
307321
packages: _packages,
308322
defines: _defines,
@@ -391,7 +405,7 @@ Future<void> generateKernel({
391405
packages = _normalize(packages);
392406

393407
final kernelResult = await generateKernelHelper(
394-
dartaotruntime: dartaotruntime,
408+
hostDartAotRuntime: hostDartAotRuntime,
395409
sourceFile: sourcePath,
396410
kernelFile: outputPath,
397411
packages: packages,

pkg/dart2native/pubspec.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ executables:
1313

1414
# Use 'any' constraints here; we get our versions from the DEPS file.
1515
dependencies:
16-
collection: any
17-
kernel: any
18-
path: any
16+
collection: any
17+
kernel: any
18+
native_assets_cli: any
19+
path: any
1920

2021
# Use 'any' constraints here; we get our versions from the DEPS file.
2122
dev_dependencies:

pkg/dartdev/lib/src/commands/build.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class BuildCommand extends DartdevCommand {
6363
@override
6464
Future<int> run() async {
6565
if (!Sdk.checkArtifactExists(genKernel) ||
66-
!Sdk.checkArtifactExists(genSnapshot) ||
66+
!Sdk.checkArtifactExists(genSnapshotHost) ||
6767
!Sdk.checkArtifactExists(sdk.dart)) {
6868
return 255;
6969
}
@@ -152,14 +152,16 @@ class BuildCommand extends DartdevCommand {
152152
recordedUsagesPath = path.join(tempDir.path, 'recorded_usages.json');
153153
}
154154
final generator = KernelGenerator(
155+
genSnapshot: genSnapshotHost,
156+
targetDartAotRuntime: hostDartAotRuntime,
155157
kind: format,
156158
sourceFile: sourceUri.toFilePath(),
157159
outputFile: outputExeUri.toFilePath(),
158160
verbose: verbose,
159161
verbosity: args.option('verbosity')!,
160162
defines: [],
161163
packages: packageConfig.toFilePath(),
162-
targetOS: targetOS,
164+
targetOS: targetOS == null ? null : OS.fromString(targetOS),
163165
enableExperiment: args.enabledExperiments.join(','),
164166
tempDir: tempDir,
165167
);

0 commit comments

Comments
 (0)