blob: bb2a4fd00ad12e586a30411b99ad86afdffac5aa [file] [edit]
// Copyright (c) 2026, 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:front_end/src/api_unstable/compiler_state.dart';
import 'package:front_end/src/compute_platform_binaries_location.dart'
show computePlatformBinariesLocation;
import 'package:frontend_server/compute_kernel.dart';
import 'package:kernel/ast.dart';
import 'package:kernel/binary/ast_from_binary.dart';
Future<void> main() async {
await runHelper(
ddc_summary_sources_change_standalone_standalone_require_both,
);
await runHelper(
ddc_summary_sources_change_standalone_require_one_require_both,
);
if (_countFailures != 0) {
// Set the exit code so the bots go red.
throw "Got $_countFailures failures.";
}
}
int _countFailures = 0;
/// Compile one standalone package, then compile another standalone package,
/// then compile a third requiring both.
/// At one point we had a bug where the target wasn't updated properly and the
/// output of the second compile was empty. In that case the third compile would
/// be missing sources.
Future<void> ddc_summary_sources_change_standalone_standalone_require_both(
Directory dir,
) async {
Uri outDirUri = dir.uri.resolve("out");
new Directory.fromUri(outDirUri)..createSync();
Uri packagesFileUri = dir.uri.resolve("packages.json");
_writePackageFilePkg1To3(packagesFileUri);
Uri ddcOutlineUri = computePlatformBinariesLocation(
forceBuildDir: true,
).resolve("ddc_outline.dill");
final Map<Uri, List<int>> inputDigests = {
ddcOutlineUri: [0],
};
// Compile package:pkg1/file.dart - a standalone package.
Uri pkg1File = dir.uri.resolve("live/pkg1/lib/file.dart");
new File.fromUri(pkg1File)
..createSync(recursive: true)
..writeAsStringSync("int pkg1() { return 42; }");
InitializedCompilerState? previousState;
Uri pkg1Output = outDirUri.resolve("1.dill");
ComputeKernelResult result = await _compileSummaryAndCheck(
pkg1Output,
packagesFileUri,
ddcOutlineUri,
inputDigests,
"package:pkg1/file.dart",
previousState,
);
previousState = result.previousState;
new File.fromUri(pkg1File).deleteSync();
// Compile package:pkg2/file.dart - a standalone package.
Uri pkg2File = dir.uri.resolve("live/pkg2/lib/file.dart");
new File.fromUri(pkg2File)
..createSync(recursive: true)
..writeAsStringSync("int pkg2() { return 43; }");
Uri pkg2Output = outDirUri.resolve("2.dill");
result = await _compileSummaryAndCheck(
pkg2Output,
packagesFileUri,
ddcOutlineUri,
inputDigests,
"package:pkg2/file.dart",
previousState,
);
previousState = result.previousState;
new File.fromUri(pkg2File).deleteSync();
// Compile package:pkg3/file.dart - require both previous.
Uri pkg3File = dir.uri.resolve("live/pkg3/lib/file.dart");
new File.fromUri(pkg3File)
..createSync(recursive: true)
..writeAsStringSync("""
import "package:pkg1/file.dart";
import "package:pkg2/file.dart";
int pkg3() { pkg1() + pkg2() + 3; }
""");
Uri pkg3Output = outDirUri.resolve("3.dill");
inputDigests[pkg1Output] = [1];
inputDigests[pkg2Output] = [2];
result = await _compileSummaryAndCheck(
pkg3Output,
packagesFileUri,
ddcOutlineUri,
inputDigests,
"package:pkg3/file.dart",
previousState,
inputSummaries: [pkg1Output.toFilePath(), pkg2Output.toFilePath()],
);
previousState = result.previousState;
}
/// Compile one standalone package, then compile another that requires the
/// first. Then compile a third that requires both the two previous.
/// At one point we had a bug where the target wasn't updated properly and the
/// second output had the same output as the first output, and trying to compile
/// the third threw because it had two summaries as input with the same library
/// inside.
Future<void> ddc_summary_sources_change_standalone_require_one_require_both(
Directory dir,
) async {
Uri outDirUri = dir.uri.resolve("out");
new Directory.fromUri(outDirUri)..createSync();
Uri packagesFileUri = dir.uri.resolve("packages.json");
_writePackageFilePkg1To3(packagesFileUri);
Uri ddcOutlineUri = computePlatformBinariesLocation(
forceBuildDir: true,
).resolve("ddc_outline.dill");
final Map<Uri, List<int>> inputDigests = {
ddcOutlineUri: [0],
};
// Compile package:pkg1/file.dart - a standalone package.
Uri pkg1File = dir.uri.resolve("live/pkg1/lib/file.dart");
new File.fromUri(pkg1File)
..createSync(recursive: true)
..writeAsStringSync("int pkg1() { return 42; }");
InitializedCompilerState? previousState;
Uri pkg1Output = outDirUri.resolve("1.dill");
ComputeKernelResult result = await _compileSummaryAndCheck(
pkg1Output,
packagesFileUri,
ddcOutlineUri,
inputDigests,
"package:pkg1/file.dart",
previousState,
);
previousState = result.previousState;
new File.fromUri(pkg1File).deleteSync();
// Compile package:pkg2/file.dart - needs pkg1.
Uri pkg2File = dir.uri.resolve("live/pkg2/lib/file.dart");
new File.fromUri(pkg2File)
..createSync(recursive: true)
..writeAsStringSync("""
import "package:pkg1/file.dart";
int pkg2() { return pkg1() + 1; }
""");
inputDigests[pkg1Output] = [1];
Uri pkg2Output = outDirUri.resolve("2.dill");
result = await _compileSummaryAndCheck(
pkg2Output,
packagesFileUri,
ddcOutlineUri,
inputDigests,
"package:pkg2/file.dart",
previousState,
inputSummaries: [pkg1Output.toFilePath()],
);
previousState = result.previousState;
new File.fromUri(pkg2File).deleteSync();
// Compile package:pkg3/file.dart - needs pkg1 and pkg2.
Uri pkg3File = dir.uri.resolve("live/pkg3/lib/file.dart");
new File.fromUri(pkg3File)
..createSync(recursive: true)
..writeAsStringSync("""
import "package:pkg1/file.dart";
import "package:pkg2/file.dart";
int pkg3() { return pkg1() + pkg2() + 2; }
""");
inputDigests[pkg2Output] = [2];
Uri pkg3Output = outDirUri.resolve("3.dill");
result = await _compileSummaryAndCheck(
pkg3Output,
packagesFileUri,
ddcOutlineUri,
inputDigests,
"package:pkg3/file.dart",
previousState,
inputSummaries: [pkg1Output.toFilePath(), pkg2Output.toFilePath()],
);
}
Future<void> runHelper(Future<void> Function(Directory) runThis) async {
Directory tmpDir = Directory.systemTemp.createTempSync('compute_kernel_test');
try {
await runThis(tmpDir);
} catch (e, st) {
stderr.writeln("Failure running $runThis:\n\n$e\n\n");
stderr.writeln(st);
stderr.writeln("\n-----\n");
_countFailures++;
exitCode = 1;
} finally {
try {
tmpDir.deleteSync(recursive: true);
} catch (e) {
// Wait a little and retry.
sleep(const Duration(milliseconds: 42));
try {
tmpDir.deleteSync(recursive: true);
} catch (e) {
print('Warning: Got exception when deleting temp dir: $e');
}
}
}
}
Future<ComputeKernelResult> _compileSummaryAndCheck(
Uri outDill,
Uri packagesFileUri,
Uri ddcOutlineUri,
Map<Uri, List<int>> inputDigests,
String source,
InitializedCompilerState? previousState, {
List<String>? inputSummaries,
}) async {
ComputeKernelResult result = await computeKernel(
[
"--output=${outDill.toFilePath()}",
"--packages-file=${packagesFileUri.toFilePath()}",
"--dart-sdk-summary=${ddcOutlineUri.toFilePath()}",
"--exclude-non-sources",
"--summary-only",
"--reuse-compiler-result",
"--use-incremental-compiler",
"--sound-null-safety",
"--source=$source",
if (inputSummaries != null)
for (String summary in inputSummaries) "--input-summary=$summary",
],
isWorker: true,
outputBuffer: null,
inputDigests: inputDigests,
previousState: previousState,
);
if (!result.succeeded) throw "Failed to compile.";
File outFile = new File.fromUri(outDill);
Component component = new Component();
new BinaryBuilder(outFile.readAsBytesSync()).readComponent(component);
List<String> outputLibs = component.libraries
.map((lib) => lib.importUri.toString())
.toList();
if (outputLibs.length != 1 || outputLibs.single != source) {
throw "Failure: Output contained ${outputLibs.length} libraries, "
"expected exactly 1 with uri $source: "
"${outputLibs}";
}
return result;
}
void _writePackageFilePkg1To3(Uri packagesFileUri) {
new File.fromUri(packagesFileUri)..writeAsStringSync("""
{
"configVersion": 2,
"packages": [
{
"name": "pkg1",
"rootUri": "live/pkg1",
"packageUri": "lib/",
"languageVersion": "3.10"
},
{
"name": "pkg2",
"rootUri": "live/pkg2",
"packageUri": "lib/",
"languageVersion": "3.10"
},
{
"name": "pkg3",
"rootUri": "live/pkg3",
"packageUri": "lib/",
"languageVersion": "3.10"
}
]
}
""");
}