Skip to content

Commit

Permalink
[dartdev] Add --target-arch flag to pair with --target-os
Browse files Browse the repository at this point in the history
  • Loading branch information
RossComputerGuy committed Oct 25, 2024
1 parent 6712eb6 commit e15d869
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 6 deletions.
2 changes: 2 additions & 0 deletions pkg/dart2native/lib/dart2native.dart
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ Future<ProcessResult> generateKernelHelper({
String? packages,
List<String> defines = const [],
String enableExperiment = '',
String? targetArch,
String? targetOS,
List<String> extraGenKernelOptions = const [],
String? nativeAssets,
Expand All @@ -129,6 +130,7 @@ Future<ProcessResult> generateKernelHelper({
'--platform=${product ? productPlatformDill : platformDill}',
if (product) '-Ddart.vm.product=true',
if (enableExperiment.isNotEmpty) '--enable-experiment=$enableExperiment',
if (targetArch != null) '--target-arch=$targetArch',
if (targetOS != null) '--target-os=$targetOS',
if (fromDill) '--from-dill=$sourceFile',
if (aot) '--aot',
Expand Down
23 changes: 23 additions & 0 deletions pkg/dart2native/lib/generate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ extension type KernelGenerator._(_Generator _generator) {
String? outputFile,
String? debugFile,
String? packages,
String? targetArch,
String? targetOS,
String? depFile,
String enableExperiment = '',
Expand All @@ -57,6 +58,7 @@ extension type KernelGenerator._(_Generator _generator) {
kind: kind,
outputFile: outputFile,
packages: packages,
targetArch: targetArch,
targetOS: targetOS,
verbose: verbose,
verbosity: verbosity,
Expand Down Expand Up @@ -120,6 +122,12 @@ class _Generator {
/// Specifies the file debugging information should be written to.
final String? _debugFile;

/// Specifies the CPU architecture the executable is being generated for.
///
/// This must be provided when [_kind] is [Kind.exe], and it must match the current
/// CPU architecture.
final String? _targetArch;

/// Specifies the operating system the executable is being generated for. This
/// must be provided when [_kind] is [Kind.exe], and it must match the current
/// operating system.
Expand Down Expand Up @@ -160,6 +168,7 @@ class _Generator {
String? outputFile,
String? debugFile,
String? packages,
String? targetArch,
String? targetOS,
String? depFile,
required String enableExperiment,
Expand All @@ -173,6 +182,7 @@ class _Generator {
_verbosity = verbosity,
_enableAsserts = enableAsserts,
_enableExperiment = enableExperiment,
_targetArch = targetArch,
_targetOS = targetOS,
_debugFile = debugFile,
_outputFile = outputFile,
Expand All @@ -182,6 +192,13 @@ class _Generator {
_sourcePath = _normalize(sourceFile)!,
_packages = _normalize(packages) {
if (_kind == Kind.exe) {
if (_targetArch == null) {
throw ArgumentError('targetArch must be specified for executables.');
} else if (_targetArch != Platform.architecture) {
throw UnsupportedError(
'Cross compilation not supported for executables.');
}

if (_targetOS == null) {
throw ArgumentError('targetOS must be specified for executables.');
} else if (_targetOS != Platform.operatingSystem) {
Expand All @@ -196,6 +213,10 @@ class _Generator {
List<String>? extraOptions,
}) async {
if (_verbose) {
if (_targetArch != null) {
print('Specializing Platform getters for target arch $_targetArch.');
}

if (_targetOS != null) {
print('Specializing Platform getters for target OS $_targetOS.');
}
Expand All @@ -212,6 +233,7 @@ class _Generator {
fromDill: await isKernelFile(_sourcePath),
enableAsserts: _enableAsserts,
enableExperiment: _enableExperiment,
targetArch: _targetArch,
targetOS: _targetOS,
extraGenKernelOptions: [
'--invocation-modes=compile',
Expand Down Expand Up @@ -308,6 +330,7 @@ class _Generator {
defines: _defines,
enableAsserts: _enableAsserts,
enableExperiment: _enableExperiment,
targetArch: _targetArch,
targetOS: _targetOS,
extraGenKernelOptions: [
'--invocation-modes=compile',
Expand Down
21 changes: 21 additions & 0 deletions pkg/dartdev/lib/src/commands/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:front_end/src/api_prototype/compiler_options.dart'
import 'package:native_assets_builder/native_assets_builder.dart';
import 'package:native_assets_cli/native_assets_cli_internal.dart';
import 'package:path/path.dart' as path;
import 'package:vm/target_arch.dart'; // For possible --target-arch values.
import 'package:vm/target_os.dart'; // For possible --target-os values.

import '../core.dart';
Expand Down Expand Up @@ -48,6 +49,9 @@ class BuildCommand extends DartdevCommand {
allowed: ['exe', 'aot'],
defaultsTo: 'exe',
)
..addOption('target-arch',
help: 'Compile to a specific target CPU architecture.',
allowed: TargetArch.names)
..addOption('target-os',
help: 'Compile to a specific target operating system.',
allowed: TargetOS.names)
Expand Down Expand Up @@ -108,6 +112,22 @@ class BuildCommand extends DartdevCommand {
sourceUri.pathSegments.last.split('.').first,
),
);
String? targetArch = args['target-arch'];
if (format != Kind.exe) {
assert(format == Kind.aot);
// If we're generating an AOT snapshot and not an executable, then
// targetArch is allowed to be null for a platform-independent snapshot
// or a different platform than the host.
} else if (targetArch == null) {
targetArch = Platform.architecture;
} else if (targetArch != Platform.architecture) {
stderr.writeln(
"'dart build -f ${format.name}' does not support cross-arch compilation.");
stderr.writeln('Host arch: ${Platform.architecture}');
stderr.writeln('Target arch: $targetArch');
return 128;
}

String? targetOS = args['target-os'];
if (format != Kind.exe) {
assert(format == Kind.aot);
Expand Down Expand Up @@ -181,6 +201,7 @@ class BuildCommand extends DartdevCommand {
verbosity: args.option('verbosity')!,
defines: [],
packages: packageConfig?.toFilePath(),
targetArch: targetArch,
targetOS: targetOS,
enableExperiment: args.enabledExperiments.join(','),
tempDir: tempDir,
Expand Down
22 changes: 22 additions & 0 deletions pkg/dartdev/lib/src/commands/compile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import 'package:dart2native/generate.dart';
import 'package:front_end/src/api_prototype/compiler_options.dart'
show Verbosity;
import 'package:path/path.dart' as path;
import 'package:vm/target_arch.dart'; // For possible --target-arch values.
import 'package:vm/target_os.dart'; // For possible --target-os values.

import '../core.dart';
Expand Down Expand Up @@ -455,6 +456,9 @@ Remove debugging information from the output and save it separately to the speci
hide: true,
valueHelp: 'opt1,opt2,...',
)
..addOption('target-arch',
help: 'Compile to a specific target CPU architecture.',
allowed: TargetArch.names)
..addOption('target-os',
help: 'Compile to a specific target operating system.',
allowed: TargetOS.names)
Expand Down Expand Up @@ -512,6 +516,22 @@ Remove debugging information from the output and save it separately to the speci
}
}

String? targetArch = args.option('target-arch');
if (format != Kind.exe) {
assert(format == Kind.aot);
// If we're generating an AOT snapshot and not an executable, then
// targetOS is allowed to be null for a platform-independent snapshot
// or a different platform than the host.
} else if (targetArch == null) {
targetArch = Platform.architecture;
} else if (targetArch != Platform.architecture) {
stderr.writeln(
"'dart compile $commandName' does not support cross-arch compilation.");
stderr.writeln('Host arch: ${Platform.architecture}');
stderr.writeln('Target arch: $targetArch');
return 128;
}

String? targetOS = args.option('target-os');
if (format != Kind.exe) {
assert(format == Kind.aot);
Expand All @@ -527,6 +547,7 @@ Remove debugging information from the output and save it separately to the speci
stderr.writeln('Target OS: $targetOS');
return 128;
}

final tempDir = Directory.systemTemp.createTempSync();
try {
final kernelGenerator = KernelGenerator(
Expand All @@ -540,6 +561,7 @@ Remove debugging information from the output and save it separately to the speci
debugFile: args.option('save-debugging-info'),
verbose: verbose,
verbosity: args.option('verbosity')!,
targetArch: targetArch,
targetOS: targetOS,
tempDir: tempDir,
depFile: args.option('depfile'),
Expand Down
6 changes: 6 additions & 0 deletions pkg/dartdev/test/commands/compile_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -417,13 +417,16 @@ void defineCompileTests() {
mainSrc: 'void main() {print(const String.fromEnvironment("cross"));}');
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
final targetArch = Platform.architecture;
final targetOS = Platform.isLinux ? 'macos' : 'linux';

final result = await p.run(
[
'compile',
'exe',
'-v',
'--target-arch',
targetArch,
'--target-os',
targetOS,
'-o',
Expand Down Expand Up @@ -474,6 +477,7 @@ void defineCompileTests() {
}, skip: isRunningOnIA32);

test('Compile aot snapshot can compile to host platform', () async {
final targetArch = Platform.architecture;
final targetOS = Platform.operatingSystem;
final p = project(mainSrc: 'void main() { print("I love $targetOS"); }');
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
Expand All @@ -484,6 +488,8 @@ void defineCompileTests() {
'compile',
'aot-snapshot',
'-v',
'--target-arch',
targetArch,
'--target-os',
targetOS,
'-o',
Expand Down
12 changes: 12 additions & 0 deletions pkg/frontend_server/lib/frontend_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import 'package:kernel/target/targets.dart' show targets, TargetFlags;
import 'package:package_config/package_config.dart';
import 'package:vm/incremental_compiler.dart' show IncrementalCompiler;
import 'package:vm/kernel_front_end.dart';
import 'package:vm/target_arch.dart'; // For possible --target-arch values.
import 'package:vm/target_os.dart'; // For possible --target-os values.

import 'src/javascript_bundle.dart';
Expand All @@ -50,6 +51,9 @@ ArgParser argParser = new ArgParser(allowTrailingOptions: true)
..addFlag('aot',
help: 'Run compiler in AOT mode (enables whole-program transformations)',
defaultsTo: false)
..addOption('target-arch',
help: 'Compile to a specific target CPU architecture.',
allowed: TargetArch.names)
..addOption('target-os',
help: 'Compile to a specific target operating system.',
allowed: TargetOS.names)
Expand Down Expand Up @@ -572,6 +576,13 @@ class FrontendCompiler implements CompilerInterface {
}
}

if (options['target-arch'] != null) {
if (!options['aot']) {
print('Error: --target-arch option must be used with --aot');
return false;
}
}

if (options['target-os'] != null) {
if (!options['aot']) {
print('Error: --target-os option must be used with --aot');
Expand Down Expand Up @@ -673,6 +684,7 @@ class FrontendCompiler implements CompilerInterface {
options['keep-class-names-implementing'],
dynamicInterface: dynamicInterfaceUri,
aot: options['aot'],
targetArch: options['target-arch'],
targetOS: options['target-os'],
useGlobalTypeFlowAnalysis: options['tfa'],
useRapidTypeAnalysis: options['rta'],
Expand Down
12 changes: 11 additions & 1 deletion pkg/vm/lib/kernel_front_end.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import 'modular/target/install.dart' show installAdditionalTargets;
import 'modular/transformations/call_site_annotator.dart'
as call_site_annotator;
import 'native_assets/synthesizer.dart';
import 'target_arch.dart';
import 'target_os.dart';
import 'transformations/deferred_loading.dart' as deferred_loading;
import 'transformations/devirtualization.dart' as devirtualization
Expand Down Expand Up @@ -123,6 +124,9 @@ void declareCompilerOptions(ArgParser args) {
help:
'Enable global type flow analysis and related transformations in AOT mode.',
defaultsTo: true);
args.addOption('target-arch',
help: 'Compile for a specific target CPU architecture when in AOT mode.',
allowed: TargetArch.names);
args.addOption('target-os',
help: 'Compile for a specific target operating system when in AOT mode.',
allowed: TargetOS.names);
Expand Down Expand Up @@ -222,6 +226,7 @@ Future<int> runCompiler(ArgResults options, String usage) async {
final String? depfileTarget = options['depfile-target'];
final String? fromDillFile = options['from-dill'];
final List<String>? fileSystemRoots = options['filesystem-root'];
final String? targetArch = options['target-arch'];
final String? targetOS = options['target-os'];
final bool aot = options['aot'];
final bool tfa = options['tfa'];
Expand Down Expand Up @@ -353,6 +358,7 @@ Future<int> runCompiler(ArgResults options, String usage) async {
useProtobufTreeShakerV2: useProtobufTreeShakerV2,
minimalKernel: minimalKernel,
treeShakeWriteOnlyFields: treeShakeWriteOnlyFields,
targetArch: targetArch,
targetOS: targetOS,
fromDillFile: fromDillFile));

Expand Down Expand Up @@ -463,6 +469,7 @@ class KernelCompilationArguments {
final bool treeShakeWriteOnlyFields;
final bool useProtobufTreeShakerV2;
final bool minimalKernel;
final String? targetArch;
final String? targetOS;
final String? fromDillFile;

Expand All @@ -485,6 +492,7 @@ class KernelCompilationArguments {
this.treeShakeWriteOnlyFields = false,
this.useProtobufTreeShakerV2 = false,
this.minimalKernel = false,
this.targetArch,
this.targetOS,
this.fromDillFile,
}) : environmentDefines = environmentDefines ?? {};
Expand Down Expand Up @@ -625,10 +633,12 @@ Future runGlobalTransformations(Target target, Component component,

// Perform unreachable code elimination, which should be performed before
// type flow analysis so TFA won't take unreachable code into account.
final targetArch = args.targetArch;
final arch = targetArch != null ? TargetArch.fromString(targetArch)! : null;
final targetOS = args.targetOS;
final os = targetOS != null ? TargetOS.fromString(targetOS)! : null;
final evaluator = vm_constant_evaluator.VMConstantEvaluator.create(
target, component, os,
target, component, arch, os,
enableAsserts: args.enableAsserts,
environmentDefines: args.environmentDefines,
coreTypes: coreTypes);
Expand Down
27 changes: 27 additions & 0 deletions pkg/vm/lib/target_arch.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

enum TargetArch {
arm64('arm64'),
ia32('ia32'),
riscv32('riscv32'),
riscv64('riscv64'),
x64('x64');

final String name;

const TargetArch(this.name);

static final Iterable<String> names = values.map((v) => v.name);

static TargetArch? fromString(String s) {
for (final arch in values) {
if (arch.name == s) return arch;
}
return null;
}

@override
String toString() => name;
}
Loading

0 comments on commit e15d869

Please sign in to comment.