blob: 7662b367e164bd29b7d890aefa62a564820e6e8d [file] [log] [blame]
#!/usr/bin/env dart
import 'dart:async';
import 'dart:io';
import 'package:args/args.dart';
import 'package:front_end/src/api_prototype/compilation_message.dart';
import 'package:front_end/src/api_prototype/compiler_options.dart';
import 'package:front_end/src/api_prototype/summary_generator.dart';
import 'package:path/path.dart' as p;
import 'package:dev_compiler/src/analyzer/command.dart' as analyzer;
import 'package:dev_compiler/src/kernel/target.dart';
final String scriptDirectory = p.dirname(p.fromUri(Platform.script));
final String repoDirectory = p.normalize(p.join(scriptDirectory, "../../../"));
/// Path to the SDK analyzer summary file, "ddc_sdk.sum".
String analyzerSummary;
/// Path to the SDK kernel summary file, "ddc_sdk.dill".
String kernelSummary;
/// The directory that output is written to.
///
/// The DDC kernel SDK should be directly in this directory. The resulting
/// packages will be placed in a "pkg" subdirectory of this.
String outputDirectory;
String get pkgDirectory => p.join(outputDirectory, "pkg");
/// Compiles the packages that the DDC tests use to JS into the given output
/// directory.
///
/// If "--travis" is passed, builds the all of the modules tested on Travis.
/// Otherwise, only builds the modules needed by the tests.
///
/// If "--analyzer-sdk" is provided, uses that summary file and compiles the
/// packages to JS and analyzer summaries against that SDK summary. Otherwise,
/// it skips generating analyzer summaries and compiling to JS.
///
/// If "--kernel-sdk" is provided, uses that summary file and generates kernel
/// summaries for the test packages against that SDK summary. Otherwise, skips
/// generating kernel summaries.
Future main(List<String> arguments) async {
var argParser = new ArgParser();
argParser.addOption("analyzer-sdk",
help: "Path to SDK analyzer summary '.sum' file");
argParser.addOption("kernel-sdk",
help: "Path to SDK Kernel summary '.dill' file");
argParser.addOption("output",
abbr: "o", help: "Directory to write output to.");
argParser.addFlag("travis",
help: "Build the additional packages tested on Travis.");
ArgResults argResults;
try {
argResults = argParser.parse(arguments);
} on ArgParserException catch (ex) {
_usageError(argParser, ex.message);
}
if (argResults.rest.isNotEmpty) {
_usageError(
argParser, 'Unexpected arguments "${argResults.rest.join(' ')}".');
}
var isTravis = argResults["travis"];
analyzerSummary = argResults["analyzer-sdk"];
kernelSummary = argResults["kernel-sdk"];
outputDirectory = argResults["output"];
new Directory(pkgDirectory).createSync(recursive: true);
// Build leaf packages. These have no other package dependencies.
// Under pkg.
await compileModule('async_helper');
await compileModule('expect', libs: ['minitest']);
await compileModule('js', libs: ['js_util']);
await compileModule('meta');
if (isTravis) {
await compileModule('microlytics', libs: ['html_channels']);
}
// Under third_party/pkg.
await compileModule('collection');
await compileModule('path');
if (isTravis) {
await compileModule('args', libs: ['command_runner']);
await compileModule('charcode');
await compileModule('fixnum');
await compileModule('logging');
await compileModule('markdown');
await compileModule('mime');
await compileModule('plugin', libs: ['manager']);
await compileModule('typed_data');
await compileModule('usage');
await compileModule('utf');
}
// Composite packages with dependencies.
await compileModule('stack_trace', deps: ['path']);
await compileModule('matcher', deps: ['stack_trace']);
if (isTravis) {
await compileModule('async', deps: ['collection']);
}
if (!isTravis) {
await compileModule('unittest', deps: [
'matcher',
'path',
'stack_trace'
], libs: [
'html_config',
'html_individual_config',
'html_enhanced_config'
]);
}
}
void _usageError(ArgParser parser, [String message]) {
if (message != null) {
stderr.writeln(message);
stderr.writeln();
}
stderr.writeln("Usage: dart build_pkgs.dart ...");
stderr.writeln();
stderr.writeln(parser.usage);
exit(1);
}
/// Compiles a [module] with a single matching ".dart" library and additional
/// [libs] and [deps] on other modules.
Future compileModule(String module,
{List<String> libs, List<String> deps}) async {
if (analyzerSummary != null) compileModuleUsingAnalyzer(module, libs, deps);
if (kernelSummary != null) await compileKernelSummary(module, libs, deps);
}
void compileModuleUsingAnalyzer(
String module, List<String> libraries, List<String> dependencies) {
var args = [
'--dart-sdk-summary=$analyzerSummary',
'-o${pkgDirectory}/$module.js'
];
// There is always a library that matches the module.
args.add('package:$module/$module.dart');
// Add any additional libraries.
if (libraries != null) {
for (var lib in libraries) {
args.add('package:$module/$lib.dart');
}
}
// Add summaries for any modules this depends on.
if (dependencies != null) {
for (var dep in dependencies) {
args.add('-s${pkgDirectory}/$dep.sum');
}
}
// TODO(rnystrom): Hack. DDC has its own forked copy of async_helper that
// has a couple of differences from pkg/async_helper. We should unfork them,
// but I'm not sure how they'll affect the other non-DDC tests. For now, just
// use ours.
if (module == 'async_helper') {
args.add('--url-mapping=package:async_helper/async_helper.dart,' +
p.join(scriptDirectory, "../test/codegen/async_helper.dart"));
}
var exitCode = analyzer.compile(args);
if (exitCode != 0) exit(exitCode);
}
Future compileKernelSummary(
String module, List<String> libraries, List<String> dependencies) async {
var succeeded = true;
void errorHandler(CompilationMessage error) {
if (error.severity == Severity.error) succeeded = false;
}
var options = new CompilerOptions()
..sdkSummary = p.toUri(kernelSummary)
..packagesFileUri = _uriInRepo(".packages")
..strongMode = true
..debugDump = true
..chaseDependencies = true
..onError = errorHandler
..reportMessages = true
..target = new DevCompilerTarget();
var inputs = <Uri>[];
if (module == "async_helper") {
// TODO(rnystrom): Hack. DDC has its own forked copy of async_helper that
// has a couple of differences from pkg/async_helper. We should unfork them,
// but I'm not sure how they'll affect the other non-DDC tests. For now,
// just use ours.
inputs.add(_uriInRepo("pkg/dev_compiler/test/codegen/async_helper.dart"));
} else {
// There is always a library that matches the module.
inputs.add(Uri.parse("package:$module/$module.dart"));
// Add any other libraries too.
if (libraries != null) {
for (var lib in libraries) {
inputs.add(Uri.parse("package:$module/$lib.dart"));
}
}
}
// Add summaries for any modules this depends on.
if (dependencies != null) {
var uris = <Uri>[];
for (var dep in dependencies) {
uris.add(p.toUri(p.absolute(p.join(pkgDirectory, "$dep.dill"))));
}
options.inputSummaries = uris;
}
// Compile the summary.
var bytes = await summaryFor(inputs, options);
var dillFile = new File(p.join(pkgDirectory, "$module.dill"));
if (succeeded) {
dillFile.writeAsBytesSync(bytes);
} else {
// Don't leave the previous version of the file on failure.
if (dillFile.existsSync()) dillFile.deleteSync();
stderr.writeln("Could not generate kernel summary for $module.");
exit(1);
}
}
Uri _uriInRepo(String pathInRepo) {
// Walk up to repo root.
var result = p.join(scriptDirectory, "../../../");
result = p.join(result, pathInRepo);
return p.toUri(p.absolute(p.normalize(result)));
}