blob: fa186b47aba9956db39e7cded334f522983a3aba [file] [log] [blame]
Asger Feldthaus02604e92016-04-26 08:39:151#!/usr/bin/env dart
2// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
3// for details. All rights reserved. Use of this source code is governed by a
4// BSD-style license that can be found in the LICENSE file.
Martin Kustermann5f7ed252016-08-05 11:27:225
Asger Feldthausa44bf702016-06-28 09:15:486import 'dart:async';
7import 'dart:io';
Martin Kustermann5f7ed252016-08-05 11:27:228
9import 'batch_util.dart';
10
Asger Feldthaus02604e92016-04-26 08:39:1511import 'package:args/args.dart';
Asger Feldthausc9244b42016-07-22 15:42:3212import 'package:kernel/analyzer/loader.dart';
Asger Feldthausa44bf702016-06-28 09:15:4813import 'package:kernel/checks.dart';
Asger Feldthaus02604e92016-04-26 08:39:1514import 'package:kernel/kernel.dart';
15import 'package:kernel/log.dart';
Asger Feldthaus760da8e2016-08-24 14:46:5016import 'package:kernel/target/targets.dart';
Martin Kustermann5f7ed252016-08-05 11:27:2217import 'package:path/path.dart' as path;
Martin Kustermann5f7ed252016-08-05 11:27:2218
19// Returns the path to the current sdk based on `Platform.resolvedExecutable`.
20String currentSdk() {
21 // The dart executable should be inside dart-sdk/bin/dart.
22 return path.dirname(path.dirname(path.absolute(Platform.resolvedExecutable)));
23}
Asger Feldthaus02604e92016-04-26 08:39:1524
Asger Feldthausdee38eb2016-07-20 12:57:5925ArgParser parser = new ArgParser(allowTrailingOptions: true)
Asger Feldthaus02604e92016-04-26 08:39:1526 ..addOption('format',
27 abbr: 'f',
28 allowed: ['text', 'bin'],
29 help: 'Output format.\n'
Asger Feldthaus5ad5fa82016-07-19 15:52:3330 '(defaults to "text" unless output file ends with ".dill")')
Asger Feldthaus02604e92016-04-26 08:39:1531 ..addOption('out',
32 abbr: 'o',
33 help: 'Output file.\n'
Asger Feldthaus5ad5fa82016-07-19 15:52:3334 '(defaults to "out.dill" if format is "bin", otherwise stdout)')
Asger Feldthaus760da8e2016-08-24 14:46:5035 ..addOption('sdk', defaultsTo: currentSdk(), help: 'Path to the Dart SDK.')
Asger Feldthausc7cbf952016-09-22 12:18:1836 ..addOption('packages',
37 abbr: 'p', help: 'Path to the .packages file or packages folder.')
38 ..addOption('package-root', help: 'Deprecated alias for --packages')
Asger Feldthaus760da8e2016-08-24 14:46:5039 ..addOption('target',
40 abbr: 't',
41 help: 'Tailor the IR to the given target.',
Asger Feldthaus6851cc42016-08-30 09:26:0542 allowed: targetNames,
43 defaultsTo: 'vm')
Asger Feldthaus02604e92016-04-26 08:39:1544 ..addFlag('strong',
45 help: 'Load .dart files in strong mode.\n'
46 'Does not affect loading of binary files. Strong mode support is very\n'
47 'unstable and not well integrated yet.')
48 ..addFlag('link', abbr: 'l', help: 'Link the whole program into one file.')
49 ..addFlag('no-output', negatable: false, help: 'Do not output any files.')
Martin Kustermann87c67ed2016-09-22 11:16:0850 ..addOption('url-mapping',
51 allowMultiple: true,
52 help: 'A custom url mapping of the form `<scheme>:<name>::<uri>`.')
Asger Feldthaus02604e92016-04-26 08:39:1553 ..addFlag('verbose',
54 abbr: 'v',
55 negatable: false,
56 help: 'Print internal warnings and diagnostics to stderr.')
57 ..addFlag('print-metrics',
58 negatable: false, help: 'Print performance metrics.')
59 ..addOption('write-dependencies',
Asger Feldthausa44bf702016-06-28 09:15:4860 help: 'Write all the .dart that were loaded to the given file.')
Asger Feldthausc9244b42016-07-22 15:42:3261 ..addFlag('sanity-check', help: 'Perform slow internal correctness checks.')
62 ..addFlag('tolerant',
63 help: 'Generate kernel even if there are compile-time errors.',
Asger Feldthausdf397062016-09-23 10:28:3364 defaultsTo: false)
65 ..addOption('D',
66 abbr: 'D',
67 allowMultiple: true,
68 help: 'Define an environment variable.',
Asger Feldthaus3ac36ac2016-10-04 11:30:4669 hide: true)
70 ..addFlag('show-external',
71 help: 'When printing a library as text, also print its dependencies\n'
72 'on external libraries.');
Asger Feldthaus02604e92016-04-26 08:39:1573
74String getUsage() => """
75Usage: dartk [options] FILE
76
Asger Feldthaus5ad5fa82016-07-19 15:52:3377Convert .dart or .dill files to kernel's IR and print out its textual
Asger Feldthaus02604e92016-04-26 08:39:1578or binary form.
79
80Examples:
81 dartk foo.dart # print text IR for foo.dart
Asger Feldthaus5ad5fa82016-07-19 15:52:3382 dartk foo.dart -ofoo.dill # write binary IR for foo.dart to foo.dill
83 dartk foo.dill # print text IR for binary file foo.dill
Asger Feldthaus02604e92016-04-26 08:39:1584
85Options:
86${parser.usage}
Asger Feldthausdf397062016-09-23 10:28:3387
88 -D<name>=<value> Define an environment variable.
Asger Feldthaus02604e92016-04-26 08:39:1589""";
90
91dynamic fail(String message) {
92 stderr.writeln(message);
93 exit(1);
94 return null;
95}
96
97ArgResults options;
98
99String defaultFormat() {
Asger Feldthaus5ad5fa82016-07-19 15:52:33100 if (options['out'] != null && options['out'].endsWith('.dill')) {
Asger Feldthaus02604e92016-04-26 08:39:15101 return 'bin';
102 }
103 return 'text';
104}
105
106String defaultOutput() {
107 if (options['format'] == 'bin') {
Asger Feldthaus5ad5fa82016-07-19 15:52:33108 return 'out.dill';
Asger Feldthaus02604e92016-04-26 08:39:15109 }
110 return null;
111}
112
113void checkIsDirectoryOrNull(String path, String option) {
114 if (path == null) return;
115 var stat = new File(path).statSync();
116 switch (stat.type) {
117 case FileSystemEntityType.DIRECTORY:
118 case FileSystemEntityType.LINK:
119 return;
120 case FileSystemEntityType.NOT_FOUND:
121 throw fail('$option not found: $path');
122 default:
Asger Feldthausc7cbf952016-09-22 12:18:18123 fail('$option is not a directory: $path');
Asger Feldthaus02604e92016-04-26 08:39:15124 }
125}
126
127void checkIsFile(String path, {String option}) {
128 var stat = new File(path).statSync();
129 switch (stat.type) {
130 case FileSystemEntityType.DIRECTORY:
131 throw fail('$option is a directory: $path');
132
133 case FileSystemEntityType.NOT_FOUND:
134 throw fail('$option not found: $path');
135 }
136}
137
Asger Feldthausc7cbf952016-09-22 12:18:18138void checkIsFileOrDirectoryOrNull(String path, String option) {
139 if (path == null) return;
140 var stat = new File(path).statSync();
141 if (stat.type == FileSystemEntityType.NOT_FOUND) {
142 fail('$option not found: $path');
143 }
144}
145
Asger Feldthaus02604e92016-04-26 08:39:15146int getTotalSourceSize(List<String> files) {
147 int size = 0;
148 for (var filename in files) {
149 size += new File(filename).statSync().size;
150 }
151 return size;
152}
153
154bool get shouldReportMetrics => options['print-metrics'];
155
156void dumpString(String value, [String filename]) {
157 if (filename == null) {
158 print(value);
159 } else {
160 new File(filename).writeAsStringSync(value);
161 }
162}
163
Martin Kustermann87c67ed2016-09-22 11:16:08164Map<Uri, Uri> parseCustomUriMappings(List<String> mappings) {
165 Map<Uri, Uri> customUriMappings = <Uri, Uri>{};
166
167 fatal(String mapping) {
168 fail('Invalid uri mapping "$mapping". Each mapping should have the '
Asger Feldthausc7cbf952016-09-22 12:18:18169 'form "<scheme>:<name>::<uri>".');
Martin Kustermann87c67ed2016-09-22 11:16:08170 }
171
172 // Each mapping has the form <uri>::<uri>.
173 for (var mapping in mappings) {
174 List<String> parts = mapping.split('::');
175 if (parts.length != 2) {
176 fatal(mapping);
177 }
178 Uri fromUri = Uri.parse(parts[0]);
Asger Feldthausc7cbf952016-09-22 12:18:18179 if (fromUri.scheme == '' || fromUri.path.contains('/')) {
Martin Kustermann87c67ed2016-09-22 11:16:08180 fatal(mapping);
181 }
182 Uri toUri = Uri.parse(parts[1]);
183 if (toUri.scheme == '') {
184 toUri = new Uri.file(path.absolute(parts[1]));
185 }
186 customUriMappings[fromUri] = toUri;
187 }
188
189 return customUriMappings;
190}
191
Asger Feldthausc9244b42016-07-22 15:42:32192/// Maintains state that should be shared between batched executions when
193/// running in batch mode (for testing purposes).
Asger Feldthaus60a8a7a2016-08-30 09:15:52194///
Asger Feldthausfc1d7b12016-09-07 11:15:58195/// This reuses the analyzer's in-memory copy of the Dart SDK between runs.
Asger Feldthausc9244b42016-07-22 15:42:32196class BatchModeState {
Asger Feldthausc7cbf952016-09-22 12:18:18197 bool isBatchMode = false;
Asger Feldthaus60928ce2016-09-23 14:11:41198 DartLoaderBatch batch = new DartLoaderBatch();
Asger Feldthausc9244b42016-07-22 15:42:32199}
200
201main(List<String> args) async {
202 if (args.isNotEmpty && args[0] == '--batch') {
203 if (args.length != 1) {
204 return fail('--batch cannot be used with other arguments');
205 }
Asger Feldthausc7cbf952016-09-22 12:18:18206 var batchModeState = new BatchModeState()..isBatchMode = true;
Asger Feldthausc9244b42016-07-22 15:42:32207 await runBatch((args) => batchMain(args, batchModeState));
208 } else {
209 CompilerOutcome outcome = await batchMain(args, new BatchModeState());
210 exit(outcome == CompilerOutcome.Ok ? 0 : 1);
211 }
212}
213
214bool isSupportedArgument(String arg) {
215 if (arg.startsWith('--')) {
216 int equals = arg.indexOf('=');
217 var name = equals != -1 ? arg.substring(2, equals) : arg.substring(2);
218 return parser.options.containsKey(name);
219 }
220 if (arg.startsWith('-')) {
221 return parser.findByAbbreviation(arg.substring(1)) != null;
222 }
223 return true;
224}
225
226Future<CompilerOutcome> batchMain(
227 List<String> args, BatchModeState batchModeState) async {
228 if (args.contains('--ignore-unrecognized-flags')) {
229 args = args.where(isSupportedArgument).toList();
230 }
231
Asger Feldthaus02604e92016-04-26 08:39:15232 if (args.isEmpty) {
233 return fail(getUsage());
234 }
235
Asger Feldthaus02604e92016-04-26 08:39:15236 try {
237 options = parser.parse(args);
238 } on FormatException catch (e) {
239 return fail(e.message); // Don't puke stack traces.
240 }
241
242 checkIsDirectoryOrNull(options['sdk'], 'Dart SDK');
Asger Feldthausc7cbf952016-09-22 12:18:18243
244 String packagePath = options['packages'] ?? options['package-root'];
245 checkIsFileOrDirectoryOrNull(packagePath, 'Package root or .packages');
Asger Feldthaus02604e92016-04-26 08:39:15246
247 // Set up logging.
248 if (options['verbose']) {
249 log.onRecord.listen((LogRecord rec) {
250 stderr.writeln(rec.message);
251 });
252 }
253
Asger Feldthausdee38eb2016-07-20 12:57:59254 if (options.rest.length != 1) {
255 return fail('Exactly one FILE should be given.');
256 }
257
Asger Feldthaus02604e92016-04-26 08:39:15258 var file = options.rest.single;
259
260 checkIsFile(file, option: 'Input file');
261
262 String format = options['format'] ?? defaultFormat();
263 String outputFile = options['out'] ?? defaultOutput();
Asger Feldthaus02604e92016-04-26 08:39:15264
Martin Kustermann87c67ed2016-09-22 11:16:08265 var customUriMappings = parseCustomUriMappings(options['url-mapping']);
Asger Feldthaus60928ce2016-09-23 14:11:41266 var repository = new Repository();
Asger Feldthaus02604e92016-04-26 08:39:15267
Asger Feldthaus02604e92016-04-26 08:39:15268 Program program;
269
270 var watch = new Stopwatch()..start();
271 List<String> loadedFiles;
272 Function getLoadedFiles;
Asger Feldthausc9244b42016-07-22 15:42:32273 List errors = const [];
Asger Feldthaus144bd992016-10-07 13:40:46274 TargetFlags targetFlags = new TargetFlags(strongMode: options['strong']);
Asger Feldthaus9677d682016-09-09 15:49:34275 Target target = getTarget(options['target'], targetFlags);
Asger Feldthaus02604e92016-04-26 08:39:15276
Asger Feldthausdf397062016-09-23 10:28:33277 var declaredVariables = <String, String>{};
278 declaredVariables.addAll(target.extraDeclaredVariables);
279 for (String define in options['D']) {
280 int separator = define.indexOf('=');
281 if (separator == -1) {
282 fail('Invalid define: -D$define. Format is -D<name>=<value>');
283 }
284 String name = define.substring(0, separator);
285 String value = define.substring(separator + 1);
286 declaredVariables[name] = value;
287 }
288
Asger Feldthaus5ad5fa82016-07-19 15:52:33289 if (file.endsWith('.dill')) {
Asger Feldthaus3ac36ac2016-10-04 11:30:46290 program = loadProgramFromBinary(file, repository);
Asger Feldthaus02604e92016-04-26 08:39:15291 getLoadedFiles = () => [file];
292 } else {
Asger Feldthaus60928ce2016-09-23 14:11:41293 DartOptions dartOptions = new DartOptions(
Asger Feldthaus144bd992016-10-07 13:40:46294 strongMode: target.strongMode,
295 strongModeSdk: target.strongModeSdk,
Asger Feldthaus60928ce2016-09-23 14:11:41296 sdk: options['sdk'],
297 packagePath: packagePath,
298 customUriMappings: customUriMappings,
299 declaredVariables: declaredVariables);
300 String packageDiscoveryPath = batchModeState.isBatchMode ? null : file;
301 DartLoader loader = await batchModeState.batch.getLoader(
302 repository, dartOptions,
303 packageDiscoveryPath: packageDiscoveryPath);
Asger Feldthaus02604e92016-04-26 08:39:15304 if (options['link']) {
Kevin Millikin420b00e2016-09-01 11:13:41305 program = loader.loadProgram(file, target: target);
Asger Feldthaus02604e92016-04-26 08:39:15306 } else {
Asger Feldthaus3ac36ac2016-10-04 11:30:46307 var library = loader.loadLibrary(file);
308 assert(library == repository.getLibrary(file));
309 program = new Program(repository.libraries);
Asger Feldthaus02604e92016-04-26 08:39:15310 }
Asger Feldthausc9244b42016-07-22 15:42:32311 errors = loader.errors;
312 if (errors.isNotEmpty) {
Asger Feldthauseb3c3af2016-09-13 11:16:05313 const int errorLimit = 100;
314 stderr.writeln(errors.take(errorLimit).join('\n'));
315 if (errors.length > errorLimit) {
316 stderr
317 .writeln('[error] ${errors.length - errorLimit} errors not shown');
318 }
Asger Feldthausc9244b42016-07-22 15:42:32319 }
320 getLoadedFiles = () => loadedFiles ??= loader.getLoadedFileNames();
Asger Feldthaus02604e92016-04-26 08:39:15321 }
322
Asger Feldthaus760da8e2016-08-24 14:46:50323 bool canContinueCompilation = errors.isEmpty || options['tolerant'];
324
Asger Feldthaus02604e92016-04-26 08:39:15325 int loadTime = watch.elapsedMilliseconds;
326 if (shouldReportMetrics) {
327 print('loader.time = $loadTime ms');
328 }
329
Asger Feldthaus760da8e2016-08-24 14:46:50330 void sanityCheck() {
331 if (options['sanity-check']) {
Asger Feldthausd5fe5f12016-09-27 11:01:09332 runSanityChecks(program);
Asger Feldthaus760da8e2016-08-24 14:46:50333 }
Asger Feldthausa44bf702016-06-28 09:15:48334 }
335
Asger Feldthaus760da8e2016-08-24 14:46:50336 sanityCheck();
337
Asger Feldthaus02604e92016-04-26 08:39:15338 String outputDependencies = options['write-dependencies'];
339 if (outputDependencies != null) {
340 new File(outputDependencies).writeAsStringSync(getLoadedFiles().join('\n'));
341 }
342
Asger Feldthaus760da8e2016-08-24 14:46:50343 // Apply target-specific transformations.
Asger Feldthaus3ac36ac2016-10-04 11:30:46344 if (target != null && options['link'] && canContinueCompilation) {
Asger Feldthaus760da8e2016-08-24 14:46:50345 target.transformProgram(program);
346 sanityCheck();
347 }
348
Asger Feldthaus02604e92016-04-26 08:39:15349 if (options['no-output']) {
Asger Feldthausc9244b42016-07-22 15:42:32350 return CompilerOutcome.Ok;
Asger Feldthaus02604e92016-04-26 08:39:15351 }
352
353 watch.reset();
354
355 Future ioFuture;
Asger Feldthaus760da8e2016-08-24 14:46:50356 if (canContinueCompilation) {
Asger Feldthausc9244b42016-07-22 15:42:32357 switch (format) {
358 case 'text':
Asger Feldthaus3ac36ac2016-10-04 11:30:46359 writeProgramToText(program,
360 path: outputFile, showExternal: options['show-external']);
Asger Feldthausc9244b42016-07-22 15:42:32361 break;
362 case 'bin':
Asger Feldthaus3ac36ac2016-10-04 11:30:46363 ioFuture = writeProgramToBinary(program, outputFile);
Asger Feldthausc9244b42016-07-22 15:42:32364 break;
365 }
Asger Feldthaus02604e92016-04-26 08:39:15366 }
367
Asger Feldthausc9244b42016-07-22 15:42:32368 int time = watch.elapsedMilliseconds;
Asger Feldthaus02604e92016-04-26 08:39:15369 if (shouldReportMetrics) {
Asger Feldthaus02604e92016-04-26 08:39:15370 print('writer.time = $time ms');
Asger Feldthaus02604e92016-04-26 08:39:15371 }
Asger Feldthausc9244b42016-07-22 15:42:32372
373 await ioFuture;
374
375 if (shouldReportMetrics) {
376 int flushTime = watch.elapsedMilliseconds - time;
377 print('writer.flush_time = $flushTime ms');
378 }
379
380 return errors.length > 0 ? CompilerOutcome.Fail : CompilerOutcome.Ok;
Asger Feldthaus02604e92016-04-26 08:39:15381}