| // Copyright (c) 2019, 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:convert'; | |
| import 'dart:io'; | |
| import 'package:compiler/src/commandline_options.dart'; | |
| Future<void> main(List<String> args) async { | |
| Stopwatch stopwatch = Stopwatch(); | |
| String? input; | |
| String? serializedInput; | |
| String output = 'out.js'; | |
| List<String> arguments = []; | |
| int start = 0; | |
| int stop = 3; | |
| int? shards; | |
| bool enableAssertions = false; | |
| for (String arg in args) { | |
| if (arg.startsWith('-')) { | |
| if (arg.startsWith('--start=')) { | |
| start = int.parse(arg.substring('--start='.length)); | |
| } else if (arg.startsWith('--stop=')) { | |
| stop = int.parse(arg.substring('--stop='.length)); | |
| } else if (arg.startsWith('--shards=')) { | |
| shards = int.parse(arg.substring('--shards='.length)); | |
| } else if (arg == '-ea' || arg == '--enable_asserts') { | |
| enableAssertions = true; | |
| } else if (arg.startsWith('--in=')) { | |
| serializedInput = arg.substring('--in='.length); | |
| } else if (arg.startsWith('-o')) { | |
| output = arg.substring('-o'.length); | |
| } else if (arg.startsWith('--out=')) { | |
| output = arg.substring('--out='.length); | |
| } else { | |
| arguments.add(arg); | |
| } | |
| } else { | |
| if (input != null) { | |
| print("Multiple entrypoints provided: '$input' and '$arg'."); | |
| exit(-1); | |
| } | |
| input = arg; | |
| } | |
| } | |
| if (input == null) { | |
| print("No entrypoint provided."); | |
| exit(-1); | |
| } | |
| serializedInput ??= output; | |
| String inputPrefix = serializedInput; | |
| if (serializedInput.endsWith('.js')) { | |
| inputPrefix = output.substring(0, output.length - '.js'.length); | |
| } | |
| String outputPrefix = output; | |
| if (output.endsWith('.js')) { | |
| outputPrefix = output.substring(0, output.length - '.js'.length); | |
| } | |
| List<String> baseOptions = ['--packages=${Platform.packageConfig}']; | |
| if (enableAssertions) { | |
| baseOptions.add('--enable_asserts'); | |
| } | |
| baseOptions.add('package:compiler/src/dart2js.dart'); | |
| baseOptions.addAll(arguments); | |
| String cfeOutput = '${inputPrefix}0.dill'; | |
| String dillOutput = '$inputPrefix.dill'; | |
| String dataOutput = '$inputPrefix.dill.data'; | |
| String codeOutput = '$outputPrefix.code'; | |
| shards ??= 2; | |
| stopwatch.start(); | |
| if (start <= 0 && stop >= 0) { | |
| await subProcess(baseOptions, [ | |
| input, | |
| '${Flags.stage}=cfe', | |
| '--out=$cfeOutput', | |
| ], '0:\t'); | |
| } | |
| if (start <= 1 && stop >= 1) { | |
| await subProcess(baseOptions, [ | |
| cfeOutput, | |
| '--out=$dillOutput', | |
| '${Flags.closedWorldUri}=$dataOutput', | |
| '${Flags.stage}=closed-world', | |
| ], '1:\t'); | |
| } | |
| if (shards <= 1) { | |
| await subProcess(baseOptions, [ | |
| dillOutput, | |
| '${Flags.globalInferenceUri}=$dataOutput', | |
| '${Flags.stage}=codegen-emit-js', | |
| '--out=$output', | |
| ], '3:\t'); | |
| } else { | |
| if (start <= 2 && stop >= 2) { | |
| List<List<String>> additionalArguments = []; | |
| List<String> outputPrefixes = []; | |
| for (int shard = 0; shard < shards; shard++) { | |
| additionalArguments.add([ | |
| dillOutput, | |
| '${Flags.globalInferenceUri}=$dataOutput', | |
| '${Flags.codegenShard}=$shard', | |
| '${Flags.codegenShards}=$shards', | |
| '${Flags.codegenUri}=$codeOutput', | |
| '${Flags.stage}=codegen', | |
| ]); | |
| outputPrefixes.add('2:${shard + 1}/$shards\t'); | |
| } | |
| Stopwatch subwatch = Stopwatch(); | |
| subwatch.start(); | |
| await Future.wait( | |
| List<Future<void>>.generate(shards, (int shard) { | |
| return subProcess( | |
| baseOptions, | |
| additionalArguments[shard], | |
| outputPrefixes[shard], | |
| ); | |
| }), | |
| ); | |
| subwatch.stop(); | |
| print('2:\tTotal time: ${_formatMs(subwatch.elapsedMilliseconds)}'); | |
| } | |
| if (start <= 3 && stop >= 3) { | |
| await subProcess(baseOptions, [ | |
| dillOutput, | |
| '${Flags.globalInferenceUri}=$dataOutput', | |
| '${Flags.codegenUri}=$codeOutput', | |
| '${Flags.codegenShards}=$shards', | |
| '${Flags.stage}=emit-js', | |
| '--out=$output', | |
| ], '3:\t'); | |
| } | |
| } | |
| stopwatch.stop(); | |
| print('Total time: ${_formatMs(stopwatch.elapsedMilliseconds)}'); | |
| } | |
| Future<void> subProcess( | |
| List<String> baseOptions, | |
| List<String> additionalOptions, | |
| String outputPrefix, | |
| ) async { | |
| List<String> options = [...baseOptions, ...additionalOptions]; | |
| print( | |
| '${outputPrefix}Command: ${Platform.resolvedExecutable} ${options.join(' ')}', | |
| ); | |
| Process process = await Process.start( | |
| Platform.resolvedExecutable, | |
| options, | |
| runInShell: true, | |
| ); | |
| _Prefixer stdoutPrefixer = _Prefixer(outputPrefix, stdout); | |
| _Prefixer stderrOutputter = _Prefixer(outputPrefix, stderr); | |
| process.stdout.transform(utf8.decoder).listen(stdoutPrefixer.call); | |
| process.stderr.transform(utf8.decoder).listen(stderrOutputter.call); | |
| int exitCode = await process.exitCode; | |
| if (exitCode != 0) { | |
| exit(exitCode); | |
| } | |
| } | |
| class _Prefixer { | |
| final String _prefix; | |
| final Stdout _stdout; | |
| bool _atNewLine = true; | |
| _Prefixer(this._prefix, this._stdout); | |
| void call(String text) { | |
| int index = 0; | |
| while (index < text.length) { | |
| if (_atNewLine) { | |
| _stdout.write(_prefix); | |
| _atNewLine = false; | |
| } | |
| int pos = text.indexOf('\n', index); | |
| if (pos != -1) { | |
| _stdout.write(text.substring(index, pos + 1)); | |
| _atNewLine = true; | |
| index = pos + 1; | |
| } else { | |
| _stdout.write(text.substring(index)); | |
| index = text.length; | |
| } | |
| } | |
| } | |
| } | |
| String _formatMs(int ms) { | |
| return '${(ms / 1000).toStringAsFixed(3)}s'; | |
| } |