| // 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'; |
| } |