65c4d768f1
Changes are reformatting and using the nullable list element operator. Change-Id: Iea1f4d2fcb06056f14804c8fe8b33c0b4d9037f2 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/477561 Commit-Queue: Sigurd Meldgaard <sigurdm@google.com> Reviewed-by: Daco Harkes <dacoharkes@google.com>
163 lines
5.2 KiB
Dart
163 lines
5.2 KiB
Dart
// Copyright (c) 2025, 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.
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:code_assets/code_assets.dart';
|
|
import 'package:dartdev/src/commands/compile.dart'
|
|
show CompileNativeCommand, crossCompileErrorExitCode;
|
|
import 'package:hooks_runner/hooks_runner.dart';
|
|
import 'package:path/path.dart' as path;
|
|
import 'package:test/test.dart';
|
|
|
|
import '../utils.dart';
|
|
import 'compile_test.dart' show targetingHostOSMessage, usingTargetOSMessage;
|
|
|
|
void main() {
|
|
ensureRunFromSdkBinDart();
|
|
|
|
// Cross compilation is not available on 32-bit architectures.
|
|
final hostArch = Target.current.architecture;
|
|
final bool isRunningOn32Bit =
|
|
hostArch == Architecture.ia32 ||
|
|
hostArch == Architecture.arm ||
|
|
hostArch == Architecture.riscv32;
|
|
|
|
group(
|
|
'cross compile -',
|
|
defineCrossCompileTests,
|
|
timeout: longTimeout,
|
|
skip: isRunningOn32Bit,
|
|
);
|
|
}
|
|
|
|
String unsupportedTargetMessage(Target target) =>
|
|
'Unsupported target platform $target';
|
|
typedef TestFunction = Future<void> Function();
|
|
|
|
void defineCrossCompileTests() {
|
|
final subcommands = [
|
|
CompileNativeCommand.aotSnapshotCmdName,
|
|
CompileNativeCommand.exeCmdName,
|
|
];
|
|
final crossCompileTargets = CompileNativeCommand.supportedTargetPlatforms;
|
|
String mainMessage(Target target) => 'I love ${target.os}';
|
|
|
|
Future<(ProcessResult, String)> crossCompile(
|
|
String subcommand,
|
|
Target target,
|
|
) async {
|
|
final p = project(
|
|
mainSrc: 'void main() {print("${mainMessage(target)}");}',
|
|
);
|
|
final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
|
|
final filename = subcommand == CompileNativeCommand.exeCmdName
|
|
? 'myexe'
|
|
: subcommand == CompileNativeCommand.aotSnapshotCmdName
|
|
? 'out.so'
|
|
: throw ArgumentError(
|
|
'Unexpected subcommand $subcommand',
|
|
'subcommand',
|
|
);
|
|
final outFile = path.canonicalize(path.join(p.dirPath, filename));
|
|
final result = await p.run([
|
|
'compile',
|
|
subcommand,
|
|
'-v',
|
|
'--target-os',
|
|
target.os.name,
|
|
'--target-arch',
|
|
target.architecture.name,
|
|
'-o',
|
|
outFile,
|
|
inFile,
|
|
]);
|
|
|
|
print('Subcommand terminated with exit code ${result.exitCode}.');
|
|
if (result.stdout.isNotEmpty) {
|
|
print('Subcommand stdout:');
|
|
print(result.stdout);
|
|
}
|
|
if (result.stderr.isNotEmpty) {
|
|
print('Subcommand stderr:');
|
|
print(result.stderr);
|
|
}
|
|
|
|
return (result, outFile);
|
|
}
|
|
|
|
TestFunction crossCompileTest(String subcommand, Target target) => () async {
|
|
expect(subcommand, isIn(subcommands));
|
|
expect(target, isIn(crossCompileTargets));
|
|
var (result, outFile) = await crossCompile(subcommand, target);
|
|
|
|
expect(result.stdout, contains(usingTargetOSMessage(target.os)));
|
|
expect(result.stderr, isNot(contains(unsupportedTargetMessage(target))));
|
|
expect(result.exitCode, 0);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
true,
|
|
reason: 'File not found: $outFile',
|
|
);
|
|
|
|
if (target != Target.current) return;
|
|
|
|
if (subcommand == CompileNativeCommand.exeCmdName) {
|
|
result = Process.runSync(outFile, const []);
|
|
} else {
|
|
expect(subcommand, CompileNativeCommand.aotSnapshotCmdName);
|
|
final Directory binDir = File(Platform.resolvedExecutable).parent;
|
|
result = Process.runSync(path.join(binDir.path, 'dartaotruntime'), [
|
|
outFile,
|
|
]);
|
|
}
|
|
|
|
expect(result.stdout, contains(mainMessage(target)));
|
|
expect(result.stderr, isEmpty);
|
|
expect(result.exitCode, 0);
|
|
};
|
|
|
|
TestFunction crossCompileFailureTest(String subcommand, Target target) =>
|
|
() async {
|
|
expect(subcommand, isIn(subcommands));
|
|
expect(target, isNot(Target.current));
|
|
expect(target, isNot(isIn(crossCompileTargets)));
|
|
final (result, outFile) = await crossCompile(subcommand, target);
|
|
|
|
expect(result.stdout, isNot(contains(targetingHostOSMessage)));
|
|
expect(result.stdout, isNot(contains(usingTargetOSMessage(target.os))));
|
|
expect(result.stderr, contains(unsupportedTargetMessage(target)));
|
|
expect(result.exitCode, crossCompileErrorExitCode);
|
|
expect(
|
|
File(outFile).existsSync(),
|
|
false,
|
|
reason: 'File created despite failure: $outFile',
|
|
);
|
|
};
|
|
|
|
for (final subcommand in subcommands) {
|
|
for (final target in crossCompileTargets) {
|
|
test(
|
|
'Compile $subcommand can cross compile to $target',
|
|
crossCompileTest(subcommand, target),
|
|
);
|
|
}
|
|
var targetOS = Platform.isWindows ? OS.macOS : OS.windows;
|
|
var targetArch = Architecture.arm64;
|
|
var target = Target.fromArchitectureAndOS(targetArch, targetOS);
|
|
test(
|
|
'Compile $subcommand fails on invalid target OS',
|
|
crossCompileFailureTest(subcommand, target),
|
|
);
|
|
|
|
targetOS = OS.linux;
|
|
targetArch = Architecture.riscv32;
|
|
target = Target.fromArchitectureAndOS(targetArch, targetOS);
|
|
test(
|
|
'Compile $subcommand fails on invalid target architecture',
|
|
crossCompileFailureTest(subcommand, target),
|
|
);
|
|
}
|
|
}
|