Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(392)

Side by Side Diff: pkg/kernel/bin/dartk.dart

Issue 2842643002: Move dartk to the tool folder (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/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.
5
6 import 'dart:async';
7 import 'dart:io';
8
9 import 'batch_util.dart';
10 import 'util.dart';
11
12 import 'package:args/args.dart';
13 import 'package:analyzer/src/kernel/loader.dart';
14 import 'package:kernel/application_root.dart';
15 import 'package:kernel/verifier.dart';
16 import 'package:kernel/kernel.dart';
17 import 'package:kernel/log.dart';
18 import 'package:kernel/target/targets.dart';
19 import 'package:kernel/transformations/treeshaker.dart';
20 import 'package:path/path.dart' as path;
21
22 // Returns the path to the current sdk based on `Platform.resolvedExecutable`.
23 String currentSdk() {
24 // The dart executable should be inside dart-sdk/bin/dart.
25 return path.dirname(path.dirname(path.absolute(Platform.resolvedExecutable)));
26 }
27
28 ArgParser parser = new ArgParser(allowTrailingOptions: true)
29 ..addOption('format',
30 abbr: 'f',
31 allowed: ['text', 'bin'],
32 help: 'Output format.\n'
33 '(defaults to "text" unless output file ends with ".dill")')
34 ..addOption('out',
35 abbr: 'o',
36 help: 'Output file.\n'
37 '(defaults to "out.dill" if format is "bin", otherwise stdout)')
38 ..addOption('sdk', defaultsTo: currentSdk(), help: 'Path to the Dart SDK.')
39 ..addOption('packages',
40 abbr: 'p', help: 'Path to the .packages file or packages folder.')
41 ..addOption('package-root', help: 'Deprecated alias for --packages')
42 ..addOption('app-root',
43 help: 'Store library paths relative to the given directory.\n'
44 'If none is given, absolute paths are used.\n'
45 'Application libraries not inside the application root are stored '
46 'using absolute paths')
47 ..addOption('target',
48 abbr: 't',
49 help: 'Tailor the IR to the given target.',
50 allowed: targetNames,
51 defaultsTo: 'vm')
52 ..addFlag('strong',
53 help: 'Load .dart files in strong mode.\n'
54 'Does not affect loading of binary files. Strong mode support is very\ n'
55 'unstable and not well integrated yet.')
56 ..addFlag('link', abbr: 'l', help: 'Link the whole program into one file.')
57 ..addFlag('no-output', negatable: false, help: 'Do not output any files.')
58 ..addOption('url-mapping',
59 allowMultiple: true,
60 help: 'A custom url mapping of the form `<scheme>:<name>::<uri>`.')
61 ..addOption('embedder-entry-points-manifest',
62 allowMultiple: true,
63 help: 'A path to a file describing entrypoints '
64 '(lines of the form `<library>,<class>,<member>`).')
65 ..addFlag('verbose',
66 abbr: 'v',
67 negatable: false,
68 help: 'Print internal warnings and diagnostics to stderr.')
69 ..addFlag('print-metrics',
70 negatable: false, help: 'Print performance metrics.')
71 ..addFlag('verify-ir', help: 'Perform slow internal correctness checks.')
72 ..addFlag('tolerant',
73 help: 'Generate kernel even if there are compile-time errors.',
74 defaultsTo: false)
75 ..addOption('D',
76 abbr: 'D',
77 allowMultiple: true,
78 help: 'Define an environment variable.',
79 hide: true)
80 ..addFlag('show-external',
81 help: 'When printing a library as text, also print its dependencies\n'
82 'on external libraries.')
83 ..addFlag('show-offsets',
84 help: 'When printing a library as text, also print node offsets')
85 ..addFlag('include-sdk',
86 help: 'Include the SDK in the output. Implied by --link.')
87 ..addFlag('tree-shake',
88 defaultsTo: false, help: 'Enable tree-shaking if the target supports it');
89
90 String getUsage() => """
91 Usage: dartk [options] FILE
92
93 Convert .dart or .dill files to kernel's IR and print out its textual
94 or binary form.
95
96 Examples:
97 dartk foo.dart # print text IR for foo.dart
98 dartk foo.dart -ofoo.dill # write binary IR for foo.dart to foo.dill
99 dartk foo.dill # print text IR for binary file foo.dill
100
101 Options:
102 ${parser.usage}
103
104 -D<name>=<value> Define an environment variable.
105 """;
106
107 dynamic fail(String message) {
108 stderr.writeln(message);
109 exit(1);
110 return null;
111 }
112
113 ArgResults options;
114
115 String defaultFormat() {
116 if (options['out'] != null && options['out'].endsWith('.dill')) {
117 return 'bin';
118 }
119 return 'text';
120 }
121
122 String defaultOutput() {
123 if (options['format'] == 'bin') {
124 return 'out.dill';
125 }
126 return null;
127 }
128
129 void checkIsDirectoryOrNull(String path, String option) {
130 if (path == null) return;
131 var stat = new File(path).statSync();
132 switch (stat.type) {
133 case FileSystemEntityType.DIRECTORY:
134 case FileSystemEntityType.LINK:
135 return;
136 case FileSystemEntityType.NOT_FOUND:
137 throw fail('$option not found: $path');
138 default:
139 fail('$option is not a directory: $path');
140 }
141 }
142
143 void checkIsFile(String path, {String option}) {
144 var stat = new File(path).statSync();
145 switch (stat.type) {
146 case FileSystemEntityType.DIRECTORY:
147 throw fail('$option is a directory: $path');
148
149 case FileSystemEntityType.NOT_FOUND:
150 throw fail('$option not found: $path');
151 }
152 }
153
154 void checkIsFileOrDirectoryOrNull(String path, String option) {
155 if (path == null) return;
156 var stat = new File(path).statSync();
157 if (stat.type == FileSystemEntityType.NOT_FOUND) {
158 fail('$option not found: $path');
159 }
160 }
161
162 int getTotalSourceSize(List<String> files) {
163 int size = 0;
164 for (var filename in files) {
165 size += new File(filename).statSync().size;
166 }
167 return size;
168 }
169
170 bool get shouldReportMetrics => options['print-metrics'];
171
172 void dumpString(String value, [String filename]) {
173 if (filename == null) {
174 print(value);
175 } else {
176 new File(filename).writeAsStringSync(value);
177 }
178 }
179
180 Map<Uri, Uri> parseCustomUriMappings(List<String> mappings) {
181 Map<Uri, Uri> customUriMappings = <Uri, Uri>{};
182
183 fatal(String mapping) {
184 fail('Invalid uri mapping "$mapping". Each mapping should have the '
185 'form "<scheme>:<name>::<uri>".');
186 }
187
188 // Each mapping has the form <uri>::<uri>.
189 for (var mapping in mappings) {
190 List<String> parts = mapping.split('::');
191 if (parts.length != 2) {
192 fatal(mapping);
193 }
194 Uri fromUri = Uri.parse(parts[0]);
195 if (fromUri.scheme == '' || fromUri.path.contains('/')) {
196 fatal(mapping);
197 }
198 Uri toUri = Uri.parse(parts[1]);
199 if (toUri.scheme == '') {
200 toUri = new Uri.file(path.absolute(parts[1]));
201 }
202 customUriMappings[fromUri] = toUri;
203 }
204
205 return customUriMappings;
206 }
207
208 /// Maintains state that should be shared between batched executions when
209 /// running in batch mode (for testing purposes).
210 ///
211 /// This reuses the analyzer's in-memory copy of the Dart SDK between runs.
212 class BatchModeState {
213 bool isBatchMode = false;
214 DartLoaderBatch batch = new DartLoaderBatch();
215 }
216
217 main(List<String> args) async {
218 if (args.isNotEmpty && args[0] == '--batch') {
219 if (args.length != 1) {
220 return fail('--batch cannot be used with other arguments');
221 }
222 var batchModeState = new BatchModeState()..isBatchMode = true;
223 await runBatch((args) => batchMain(args, batchModeState));
224 } else {
225 CompilerOutcome outcome = await batchMain(args, new BatchModeState());
226 exit(outcome == CompilerOutcome.Ok ? 0 : 1);
227 }
228 }
229
230 bool isSupportedArgument(String arg) {
231 if (arg.startsWith('--')) {
232 int equals = arg.indexOf('=');
233 var name = equals != -1 ? arg.substring(2, equals) : arg.substring(2);
234 return parser.options.containsKey(name);
235 }
236 if (arg.startsWith('-')) {
237 return parser.findByAbbreviation(arg.substring(1)) != null;
238 }
239 return true;
240 }
241
242 Future<CompilerOutcome> batchMain(
243 List<String> args, BatchModeState batchModeState) async {
244 if (args.contains('--ignore-unrecognized-flags')) {
245 args = args.where(isSupportedArgument).toList();
246 }
247
248 if (args.isEmpty) {
249 return fail(getUsage());
250 }
251
252 try {
253 options = parser.parse(args);
254 } on FormatException catch (e) {
255 return fail(e.message); // Don't puke stack traces.
256 }
257
258 checkIsDirectoryOrNull(options['sdk'], 'Dart SDK');
259
260 String packagePath = options['packages'] ?? options['package-root'];
261 checkIsFileOrDirectoryOrNull(packagePath, 'Package root or .packages');
262
263 String applicationRootOption = options['app-root'];
264 checkIsDirectoryOrNull(applicationRootOption, 'Application root');
265 if (applicationRootOption != null) {
266 applicationRootOption = new File(applicationRootOption).absolute.path;
267 }
268 var applicationRoot = new ApplicationRoot(applicationRootOption);
269
270 // Set up logging.
271 if (options['verbose']) {
272 log.onRecord.listen((LogRecord rec) {
273 stderr.writeln(rec.message);
274 });
275 }
276
277 bool includeSdk = options['include-sdk'];
278
279 List<String> inputFiles = options.rest;
280 if (inputFiles.length < 1 && !includeSdk) {
281 return fail('At least one file should be given.');
282 }
283
284 bool hasBinaryInput = false;
285 bool hasDartInput = includeSdk;
286 for (String file in inputFiles) {
287 checkIsFile(file, option: 'Input file');
288 if (file.endsWith('.dill')) {
289 hasBinaryInput = true;
290 } else if (file.endsWith('.dart')) {
291 hasDartInput = true;
292 } else {
293 fail('Unrecognized file extension: $file');
294 }
295 }
296
297 if (hasBinaryInput && hasDartInput) {
298 fail('Mixed binary and dart input is not currently supported');
299 }
300
301 String format = options['format'] ?? defaultFormat();
302 String outputFile = options['out'] ?? defaultOutput();
303
304 List<String> urlMapping = options['url-mapping'] as List<String>;
305 var customUriMappings = parseCustomUriMappings(urlMapping);
306
307 List<String> embedderEntryPointManifests =
308 options['embedder-entry-points-manifest'] as List<String>;
309 List<ProgramRoot> programRoots =
310 parseProgramRoots(embedderEntryPointManifests);
311
312 var program = new Program();
313
314 var watch = new Stopwatch()..start();
315 List errors = const [];
316 TargetFlags targetFlags = new TargetFlags(
317 strongMode: options['strong'],
318 treeShake: options['tree-shake'],
319 kernelRuntime: Platform.script.resolve('../runtime/'),
320 programRoots: programRoots);
321 Target target = getTarget(options['target'], targetFlags);
322
323 var declaredVariables = <String, String>{};
324 declaredVariables.addAll(target.extraDeclaredVariables);
325 for (String define in options['D']) {
326 int separator = define.indexOf('=');
327 if (separator == -1) {
328 fail('Invalid define: -D$define. Format is -D<name>=<value>');
329 }
330 String name = define.substring(0, separator);
331 String value = define.substring(separator + 1);
332 declaredVariables[name] = value;
333 }
334
335 DartLoader loader;
336 if (hasDartInput) {
337 String packageDiscoveryPath =
338 batchModeState.isBatchMode || inputFiles.isEmpty
339 ? null
340 : inputFiles.first;
341 loader = await batchModeState.batch.getLoader(
342 program,
343 new DartOptions(
344 strongMode: target.strongMode,
345 strongModeSdk: target.strongModeSdk,
346 sdk: options['sdk'],
347 packagePath: packagePath,
348 customUriMappings: customUriMappings,
349 declaredVariables: declaredVariables,
350 applicationRoot: applicationRoot),
351 packageDiscoveryPath: packageDiscoveryPath);
352 if (includeSdk) {
353 for (var uri in batchModeState.batch.dartSdk.uris) {
354 loader.loadLibrary(Uri.parse(uri));
355 }
356 }
357 loader.loadSdkInterface(program, target);
358 }
359
360 for (String file in inputFiles) {
361 Uri fileUri = Uri.base.resolve(file);
362
363 if (file.endsWith('.dill')) {
364 loadProgramFromBinary(file, program);
365 } else {
366 if (options['link']) {
367 loader.loadProgram(fileUri, target: target);
368 } else {
369 var library = loader.loadLibrary(fileUri);
370 program.mainMethod ??= library.procedures
371 .firstWhere((p) => p.name.name == 'main', orElse: () => null);
372 }
373 errors = loader.errors;
374 if (errors.isNotEmpty) {
375 const int errorLimit = 100;
376 stderr.writeln(errors.take(errorLimit).join('\n'));
377 if (errors.length > errorLimit) {
378 stderr.writeln(
379 '[error] ${errors.length - errorLimit} errors not shown');
380 }
381 }
382 }
383 }
384
385 bool canContinueCompilation = errors.isEmpty || options['tolerant'];
386
387 int loadTime = watch.elapsedMilliseconds;
388 if (shouldReportMetrics) {
389 print('loader.time = $loadTime ms');
390 }
391
392 void runVerifier() {
393 if (options['verify-ir']) {
394 verifyProgram(program);
395 }
396 }
397
398 if (canContinueCompilation) {
399 runVerifier();
400 }
401
402 if (options['link'] && program.mainMethodName == null) {
403 fail('[error] The program has no main method.');
404 }
405
406 // Apply target-specific transformations.
407 if (target != null && canContinueCompilation) {
408 target.performModularTransformations(program);
409 runVerifier();
410 if (options['link']) {
411 target.performGlobalTransformations(program);
412 runVerifier();
413 }
414 }
415
416 if (options['no-output']) {
417 return CompilerOutcome.Ok;
418 }
419
420 watch.reset();
421
422 Future ioFuture;
423 if (canContinueCompilation) {
424 switch (format) {
425 case 'text':
426 writeProgramToText(program,
427 path: outputFile,
428 showExternal: options['show-external'],
429 showOffsets: options['show-offsets']);
430 break;
431 case 'bin':
432 ioFuture = writeProgramToBinary(program, outputFile);
433 break;
434 }
435 }
436
437 int time = watch.elapsedMilliseconds;
438 if (shouldReportMetrics) {
439 print('writer.time = $time ms');
440 }
441
442 await ioFuture;
443
444 if (shouldReportMetrics) {
445 int flushTime = watch.elapsedMilliseconds - time;
446 print('writer.flush_time = $flushTime ms');
447 }
448
449 if (options['tolerant']) {
450 return CompilerOutcome.Ok;
451 }
452
453 return errors.length > 0 ? CompilerOutcome.Fail : CompilerOutcome.Ok;
454 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698