[ddc] Add support for simple DAG compiles to ddb

This enables some compiling and running with multiple modules
and simple import graphs.

Change-Id: I467c0dd0c4f5b41b19353ae5114bae20547b94f0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/355508
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Nicholas Shahan <nshahan@google.com>
This commit is contained in:
Nicholas Shahan 2024-03-08 17:55:58 +00:00 committed by Commit Queue
parent 206222265f
commit 0402fa606b

View file

@ -24,7 +24,13 @@ void main(List<String> args) async {
void printUsage() {
print('Usage: ddb [options] <dart-script-file>\n');
print('Compiles <dart-script-file> with the dev_compiler and runs it on a '
'JS platform.\n');
'JS platform.\n'
'Optionally, mulitple Dart source files can be passed as arguments and '
'they will be compiled into seperate modules in the order provided. '
'The order will be treated as an import DAG with the last file as the '
'application entrypoint. The .dill file outputs from each compile will '
'be collected and passed as dependency summaries for the next compile '
'step.');
}
// Parse flags.
@ -110,7 +116,7 @@ void main(List<String> args) async {
print(parser.usage);
exit(0);
}
if (options.rest.length != 1) {
if (options.rest.isEmpty) {
print('Dart script file required.\n');
printUsage();
exit(1);
@ -137,20 +143,19 @@ void main(List<String> args) async {
var weakNullSafetyErrors = options['weak-null-safety-errors'] as bool;
var ddcModules = options['ddc-modules'] as bool;
var canaryFeatures = options['canary'] as bool;
var entry = p.canonicalize(options.rest.first);
var out = (options['out'] as String?) ?? p.setExtension(entry, '.js');
var libRoot = p.dirname(entry);
var basename = p.basenameWithoutExtension(entry);
var libname =
js_names.pathToJSIdentifier(p.relative(p.withoutExtension(entry)));
var sourceFiles = options.rest.map(p.canonicalize);
var entryPoint = sourceFiles.last;
var libRoot = p.dirname(entryPoint);
var basename = p.basenameWithoutExtension(entryPoint);
var libname = pathToLibName(entryPoint);
// This is used in the DDC module system and usually corresponds to the
// entrypoint's path.
var appname = p.relative(p.withoutExtension(entry));
var appname = p.relative(p.withoutExtension(entryPoint));
// This is used in the DDC module system for multiapp workflows and is
// stubbed in ddb.
var uuid = "00000000-0000-0000-0000-000000000000";
var uuid = '00000000-0000-0000-0000-000000000000';
// By default (no `-d`), we use the `dartdevc` binary on the user's path to
// compute the SDK we use for execution. I.e., we assume that `dart` is
@ -259,7 +264,7 @@ void main(List<String> args) async {
if (verbose) {
print('');
}
var outputs = <String>[];
if (compile) {
var ddcArgs = [
if (summarizeText) '--summarize-text',
@ -271,11 +276,23 @@ void main(List<String> args) async {
if (options['packages'] != null) '--packages=${options['packages']}',
if (emitDebugSymbols) '--emit-debug-symbols',
if (canaryFeatures) '--canary',
'-o',
out,
entry
];
await runDdc(ddcArgs);
var summaryFiles = [];
for (var sourceFile in sourceFiles) {
var out = p.setExtension(sourceFile, '.js');
var requestArgs = [
for (var summary in summaryFiles) '--summary=$summary',
'-o',
out,
sourceFile,
];
await runDdc([...ddcArgs, ...requestArgs]);
outputs.add(out);
var summaryFile = p.setExtension(out, '.dill');
var libname =
js_names.pathToJSIdentifier(p.basenameWithoutExtension(sourceFile));
summaryFiles.add('$summaryFile=$libname');
}
}
if (run) {
@ -293,6 +310,10 @@ void main(List<String> args) async {
// Assume Linux
chromeBinary = 'google-chrome';
}
var amdModulePaths = [
for (var output in outputs)
'"${pathToLibName(output)}": "${p.withoutExtension(output)}"'
].join(',\n ');
// Seal the native JavaScript Object prototype to avoid pollution before
// loading the Dart SDK module.
@ -303,10 +324,11 @@ void main(List<String> args) async {
require.config({
paths: {
'dart_sdk': '$sdkJsPath/dart_sdk',
$amdModulePaths
},
waitSeconds: 15
});
require(['dart_sdk', '$basename'],
require(['dart_sdk', '$libname'],
function(sdk, app) {
'use strict';
@ -320,11 +342,14 @@ void main(List<String> args) async {
});
</script>
''';
var ddcModuleScriptTags = [
for (var output in outputs) '<script src="$output"></script>'
].join('\n');
var ddcModulesHtml = '''
<script src="$preamblesDir/seal_native_object.js"></script>
<script src="$ddcPath/lib/js/ddc/ddc_module_loader.js"></script>
<script src="$sdkJsPath/dart_sdk.js"></script>
<script src="$out"></script>
$ddcModuleScriptTags
<script>
let sdk = dart_library.import("dart_sdk");
sdk.dart.weakNullSafetyWarnings(
@ -336,7 +361,7 @@ sdk.dart.nativeNonNullAsserts($nativeNonNullAsserts);
dart_library.start("$appname", "$uuid", "$basename", "$libname", false);
</script>
''';
var htmlFile = p.setExtension(out, '.html');
var htmlFile = p.setExtension(entryPoint, '.html');
File(htmlFile)
.writeAsStringSync(ddcModules ? ddcModulesHtml : amdModulesHtml);
var tmp = p.join(Directory.systemTemp.path, 'ddc');
@ -382,17 +407,19 @@ try {
process.exit(1);
}
''';
var nodeFile = p.setExtension(out, '.run.js');
var nodeFile = p.setExtension(entryPoint, '.run.js');
File(nodeFile).writeAsStringSync(runjs);
var nodeBinary = binary ?? 'node';
var process = await startProcess('Node', nodeBinary,
['--inspect=localhost:$port', nodeFile], {'NODE_PATH': nodePath});
if (await process.exitCode != 0) exit(await process.exitCode);
} else if (d8) {
var ddcModuleScriptTags =
[for (var output in outputs) 'load("$output");'].join('\n');
var runjs = '''
load("$ddcPath/lib/js/ddc/ddc_module_loader.js");
load("$sdkJsPath/dart_sdk.js");
load("$out");
$ddcModuleScriptTags
let sdk = dart_library.import('dart_sdk');
// Create a self reference for JS interop tests that set fields on self.
@ -409,7 +436,7 @@ self.dartMainRunner(function () {
dart_library.start("$appname", "$uuid", "$basename", "$libname", false);
});
''';
var d8File = p.setExtension(out, '.d8.js');
var d8File = p.setExtension(entryPoint, '.d8.js');
File(d8File).writeAsStringSync(runjs);
var d8Binary = binary ?? p.join(dartCheckoutPath, _d8executable);
var process = await startProcess('D8', d8Binary, [
@ -422,6 +449,11 @@ self.dartMainRunner(function () {
}
}
/// Converts a path to the expected default library name DDC will use.
String pathToLibName(String path) =>
js_names.pathToJSIdentifier(p.withoutExtension(
p.isWithin(p.current, path) ? p.relative(path) : p.absolute(path)));
String get _d8executable {
final arch = Abi.current().toString().split('_')[1];
if (Platform.isWindows) {