blob: a304aec071ad28c813f01708eaa292ed20a8c6d2 [file] [log] [blame]
// Copyright (c) 2017, 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.
/// Defines the front-end API for converting source code to Dart Kernel objects.
library front_end.kernel_generator_impl;
import 'dart:async' show Future;
import 'dart:async';
import 'package:kernel/kernel.dart' show Program, CanonicalName;
import 'base/processed_options.dart';
import 'fasta/compiler_command_line.dart' show CompilerCommandLine;
import 'fasta/compiler_context.dart' show CompilerContext;
import 'fasta/deprecated_problems.dart' show deprecated_InputError, reportCrash;
import 'fasta/dill/dill_target.dart' show DillTarget;
import 'fasta/kernel/kernel_outline_shaker.dart';
import 'fasta/kernel/kernel_target.dart' show KernelTarget;
import 'fasta/kernel/utils.dart';
import 'fasta/kernel/verifier.dart';
import 'fasta/uri_translator.dart' show UriTranslator;
/// Implementation for the `package:front_end/kernel_generator.dart` and
/// `package:front_end/summary_generator.dart` APIs.
Future<CompilerResult> generateKernel(ProcessedOptions options,
{bool buildSummary: false,
bool buildProgram: true,
bool trimDependencies: false}) async {
// TODO(sigmund): Replace CompilerCommandLine and instead simply use a
// CompilerContext that directly uses the ProcessedOptions through the
// system.
String programName = "";
List<String> arguments = <String>[programName, "--target=none"];
if (options.strongMode) {
arguments.add("--strong-mode");
}
if (options.verbose) {
arguments.add("--verbose");
}
if (options.setExitCodeOnProblem) {
arguments.add("--set-exit-code-on-problem");
}
return await CompilerCommandLine.withGlobalOptions(programName, arguments,
(CompilerContext context) async {
context.options.options["--target"] = options.target;
return await generateKernelInternal(options,
buildSummary: buildSummary,
buildProgram: buildProgram,
trimDependencies: trimDependencies);
});
}
Future<CompilerResult> generateKernelInternal(ProcessedOptions options,
{bool buildSummary: false,
bool buildProgram: true,
bool trimDependencies: false}) async {
var fs = options.fileSystem;
if (!await options.validateOptions()) return null;
options.ticker.logMs("Validated arguments");
try {
UriTranslator uriTranslator = await options.getUriTranslator();
var dillTarget =
new DillTarget(options.ticker, uriTranslator, options.target);
CanonicalName nameRoot = new CanonicalName.root();
Set<Uri> externalLibs(Program program) {
return program.libraries
.where((lib) => lib.isExternal)
.map((lib) => lib.importUri)
.toSet();
}
var sdkSummary = await options.loadSdkSummary(nameRoot);
if (sdkSummary != null) {
var excluded = externalLibs(sdkSummary);
dillTarget.loader
.appendLibraries(sdkSummary, (uri) => !excluded.contains(uri));
}
// TODO(sigmund): provide better error reporting if input summaries or
// linked dependencies were listed out of order (or provide mechanism to
// sort them).
for (var inputSummary in await options.loadInputSummaries(nameRoot)) {
var excluded = externalLibs(inputSummary);
dillTarget.loader
.appendLibraries(inputSummary, (uri) => !excluded.contains(uri));
}
// All summaries are considered external and shouldn't include source-info.
dillTarget.loader.libraries.forEach((lib) => lib.isExternal = true);
// Linked dependencies are meant to be part of the program so they are not
// marked external.
for (var dependency in await options.loadLinkDependencies(nameRoot)) {
var excluded = externalLibs(dependency);
dillTarget.loader
.appendLibraries(dependency, (uri) => !excluded.contains(uri));
}
await dillTarget.buildOutlines();
var kernelTarget = new KernelTarget(fs, false, dillTarget, uriTranslator);
options.inputs.forEach(kernelTarget.read);
Program summaryProgram =
await kernelTarget.buildOutlines(nameRoot: nameRoot);
List<int> summary = null;
if (buildSummary) {
if (trimDependencies) {
// TODO(sigmund): see if it is worth supporting this. Note: trimming the
// program is destructive, so if we are emitting summaries and the
// program in a single API call, we would need to clone the program here
// to avoid deleting pieces that are needed by kernelTarget.buildProgram
// below.
assert(!buildProgram);
var excluded =
dillTarget.loader.libraries.map((lib) => lib.importUri).toSet();
trimProgram(summaryProgram, (uri) => !excluded.contains(uri));
}
if (options.verify) {
verifyProgram(summaryProgram).forEach(options.reportMessage);
}
if (options.debugDump) {
printProgramText(summaryProgram,
libraryFilter: kernelTarget.isSourceLibrary);
}
if (kernelTarget.errors.isEmpty) {
summary = serializeProgram(summaryProgram, excludeUriToSource: true);
}
options.ticker.logMs("Generated outline");
}
Program program;
if (buildProgram && kernelTarget.errors.isEmpty) {
program = await kernelTarget.buildProgram(verify: options.verify);
if (trimDependencies) {
var excluded =
dillTarget.loader.libraries.map((lib) => lib.importUri).toSet();
trimProgram(program, (uri) => !excluded.contains(uri));
}
if (options.debugDump) {
printProgramText(program, libraryFilter: kernelTarget.isSourceLibrary);
}
options.ticker.logMs("Generated program");
}
if (kernelTarget.errors.isNotEmpty) {
// TODO(ahe): The errors have already been reported via CompilerContext.
kernelTarget.errors.forEach(options.reportMessage);
return null;
}
return new CompilerResult(
summary: summary,
program: program,
deps: kernelTarget.loader.getDependencies());
} on deprecated_InputError catch (e) {
options.reportMessage(deprecated_InputError.toMessage(e));
return null;
} catch (e, t) {
return reportCrash(e, t);
}
}
/// Result object of [generateKernel].
class CompilerResult {
/// The generated summary bytes, if it was requested.
final List<int> summary;
/// The generated program, if it was requested.
final Program program;
/// Dependencies traversed by the compiler. Used only for generating
/// dependency .GN files in the dart-sdk build system.
/// Note this might be removed when we switch to compute depencencies without
/// using the compiler itself.
final List<Uri> deps;
CompilerResult({this.summary, this.program, this.deps});
}