90d89a0ca1
Change-Id: I9d3b498ec0b4ae631cc2240dfad589166eae0c4b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/510340 Commit-Queue: Jens Johansen <jensj@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
406 lines
13 KiB
Dart
406 lines
13 KiB
Dart
// Copyright (c) 2016, 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:io' show exit;
|
|
|
|
import 'package:_fe_analyzer_shared/src/messages/severity.dart'
|
|
show CfeSeverity;
|
|
import 'package:_fe_analyzer_shared/src/util/options.dart';
|
|
import 'package:_fe_analyzer_shared/src/util/resolve_input_uri.dart'
|
|
show resolveInputUri;
|
|
import 'package:build_integration/file_system/single_root.dart'
|
|
show SingleRootFileSystem;
|
|
import 'package:front_end/src/api_prototype/compiler_options.dart';
|
|
import 'package:front_end/src/api_prototype/experimental_flags.dart'
|
|
show ExperimentalFlag;
|
|
import 'package:front_end/src/api_prototype/file_system.dart' show FileSystem;
|
|
import 'package:front_end/src/api_prototype/standard_file_system.dart'
|
|
show StandardFileSystem;
|
|
import 'package:front_end/src/api_prototype/terminal_color_support.dart';
|
|
import 'package:front_end/src/base/command_line_options.dart';
|
|
import 'package:front_end/src/base/compiler_context.dart' show CompilerContext;
|
|
import 'package:front_end/src/base/file_system_dependency_tracker.dart';
|
|
import 'package:front_end/src/base/problems.dart' show DebugAbort;
|
|
import 'package:front_end/src/base/processed_options.dart'
|
|
show ProcessedOptions;
|
|
import 'package:front_end/src/codes/cfe_codes.dart'
|
|
show Message, PlainAndColorizedString;
|
|
import 'package:front_end/src/codes/diagnostic.dart' as diag;
|
|
import 'package:front_end/src/compute_platform_binaries_location.dart'
|
|
show computePlatformBinariesLocation, computePlatformDillName;
|
|
import 'package:front_end/src/scheme_based_file_system.dart'
|
|
show SchemeBasedFileSystem;
|
|
import 'package:kernel/target/targets.dart'
|
|
show Target, TargetFlags, TestTargetFlags, getTarget, targets;
|
|
|
|
// Before adding new options here, you must:
|
|
// * Document the option.
|
|
// * Get an explicit approval from the front-end team.
|
|
const List<Option> optionSpecification = [
|
|
Options.compileSdk,
|
|
Options.dumpIr,
|
|
Options.showOffsets,
|
|
Options.enableExperiment,
|
|
Options.excludeSource,
|
|
Options.omitPlatform,
|
|
Options.fatal,
|
|
Options.fatalSkip,
|
|
Options.forceLateLowering,
|
|
Options.forceLateLoweringSentinel,
|
|
Options.forceStaticFieldLowering,
|
|
Options.forceNoExplicitGetterCalls,
|
|
Options.forceConstructorTearOffLowering,
|
|
Options.forceClosureContextLowering,
|
|
Options.help,
|
|
Options.librariesJson,
|
|
Options.noDefines,
|
|
Options.output,
|
|
Options.packages,
|
|
Options.platform,
|
|
Options.sdk,
|
|
Options.singleRootBase,
|
|
Options.singleRootScheme,
|
|
Options.nnbdWeakMode,
|
|
Options.nnbdStrongMode,
|
|
Options.target,
|
|
Options.verbose,
|
|
Options.verbosity,
|
|
Options.verify,
|
|
Options.skipPlatformVerification,
|
|
Options.linkDependencies,
|
|
Options.noDeps,
|
|
Options.invocationModes,
|
|
Options.defines,
|
|
];
|
|
|
|
void throwCommandLineProblem(String message) {
|
|
throw new CommandLineProblem.deprecated(message);
|
|
}
|
|
|
|
ProcessedOptions analyzeCommandLine(
|
|
FileSystemDependencyTracker? tracker,
|
|
String programName,
|
|
ParsedOptions parsedOptions,
|
|
bool areRestArgumentsInputs,
|
|
) {
|
|
final List<String> arguments = parsedOptions.arguments;
|
|
|
|
final bool help = Options.help.read(parsedOptions);
|
|
|
|
final bool verbose = Options.verbose.read(parsedOptions);
|
|
|
|
if (help) {
|
|
print(computeUsage(programName, verbose).problemMessage);
|
|
exit(0);
|
|
}
|
|
|
|
if (parsedOptions.options.containsKey(Flags.compileSdk) &&
|
|
parsedOptions.options.containsKey(Flags.platform)) {
|
|
return throw new CommandLineProblem.deprecated(
|
|
"Can't specify both '${Flags.compileSdk}' and '${Flags.platform}'.",
|
|
);
|
|
}
|
|
|
|
final String targetName = Options.target.read(parsedOptions);
|
|
|
|
Map<ExperimentalFlag, bool> explicitExperimentalFlags =
|
|
parseExperimentalFlags(
|
|
parseExperimentalArguments(
|
|
Options.enableExperiment.read(parsedOptions),
|
|
),
|
|
onError: throwCommandLineProblem,
|
|
onWarning: print,
|
|
);
|
|
|
|
final TargetFlags flags = new TestTargetFlags(
|
|
forceLateLoweringsForTesting: Options.forceLateLowering.read(parsedOptions),
|
|
forceStaticFieldLoweringForTesting: Options.forceStaticFieldLowering.read(
|
|
parsedOptions,
|
|
),
|
|
forceNoExplicitGetterCallsForTesting: Options.forceNoExplicitGetterCalls
|
|
.read(parsedOptions),
|
|
forceConstructorTearOffLoweringForTesting: Options
|
|
.forceConstructorTearOffLowering
|
|
.read(parsedOptions),
|
|
forceLateLoweringSentinelForTesting: Options.forceLateLoweringSentinel.read(
|
|
parsedOptions,
|
|
),
|
|
isClosureContextLoweringEnabled: Options.forceClosureContextLowering.read(
|
|
parsedOptions,
|
|
),
|
|
);
|
|
|
|
final Target? target = getTarget(targetName, flags);
|
|
if (target == null) {
|
|
return throw new CommandLineProblem.deprecated(
|
|
"Target '${targetName}' not recognized. "
|
|
"Valid targets are:\n ${targets.keys.join("\n ")}",
|
|
);
|
|
}
|
|
|
|
final bool noDefines = Options.noDefines.read(parsedOptions);
|
|
|
|
final bool noDeps = Options.noDeps.read(parsedOptions);
|
|
|
|
final bool verify = Options.verify.read(parsedOptions);
|
|
|
|
final bool skipPlatformVerification = Options.skipPlatformVerification.read(
|
|
parsedOptions,
|
|
);
|
|
|
|
final bool showOffsets = Options.showOffsets.read(parsedOptions);
|
|
|
|
final bool dumpIr = Options.dumpIr.read(parsedOptions) || showOffsets;
|
|
|
|
final bool excludeSource = Options.excludeSource.read(parsedOptions);
|
|
|
|
final bool omitPlatform = Options.omitPlatform.read(parsedOptions);
|
|
|
|
final Uri? packages = Options.packages.read(parsedOptions);
|
|
|
|
final Set<String> fatal = new Set<String>.from(
|
|
Options.fatal.read(parsedOptions) ?? <String>[],
|
|
);
|
|
|
|
final bool errorsAreFatal = fatal.contains("errors");
|
|
|
|
final bool warningsAreFatal = fatal.contains("warnings");
|
|
|
|
final int fatalSkip =
|
|
int.tryParse(Options.fatalSkip.read(parsedOptions) ?? "0") ?? -1;
|
|
|
|
final bool compileSdk = Options.compileSdk.read(parsedOptions) != null;
|
|
|
|
final String? singleRootScheme = Options.singleRootScheme.read(parsedOptions);
|
|
final Uri? singleRootBase = Options.singleRootBase.read(parsedOptions);
|
|
|
|
final List<Uri> linkDependencies =
|
|
Options.linkDependencies.read(parsedOptions) ?? [];
|
|
|
|
final String invocationModes =
|
|
Options.invocationModes.read(parsedOptions) ?? '';
|
|
|
|
final String verbosity = Options.verbosity.read(parsedOptions);
|
|
|
|
FileSystem fileSystem;
|
|
if (tracker != null) {
|
|
fileSystem = StandardFileSystem.instanceWithTracking(tracker);
|
|
} else {
|
|
fileSystem = StandardFileSystem.instance;
|
|
}
|
|
if (singleRootScheme != null) {
|
|
fileSystem = new SchemeBasedFileSystem({
|
|
'file': fileSystem,
|
|
'data': fileSystem,
|
|
// TODO(askesc): remove also when fixing StandardFileSystem (empty schemes
|
|
// should have been handled elsewhere).
|
|
'': fileSystem,
|
|
singleRootScheme: new SingleRootFileSystem(
|
|
singleRootScheme,
|
|
singleRootBase!,
|
|
fileSystem,
|
|
),
|
|
});
|
|
}
|
|
|
|
// In order to facilitate the roll out of CFE constants on Dart2js, we need to
|
|
// be able to support both passing '--no-defines' and also evaluating CFE
|
|
// constants when the target supports it. This is so we can easily enable or
|
|
// disable fully evaluating constants in the CFE with a flag. This can be
|
|
// deleted when the CFE fully evaluates constants for Dart2js in all cases.
|
|
Map<String, String>? environmentDefines;
|
|
if (noDefines && target.constantsBackend.supportsUnevaluatedConstants) {
|
|
// Pass a null environment.
|
|
} else {
|
|
environmentDefines = parsedOptions.defines;
|
|
}
|
|
|
|
CompilerOptions compilerOptions = new CompilerOptions()
|
|
..compileSdk = compileSdk
|
|
..fileSystem = fileSystem
|
|
..packagesFileUri = packages
|
|
..target = target
|
|
..throwOnErrorsForDebugging = errorsAreFatal
|
|
..throwOnWarningsForDebugging = warningsAreFatal
|
|
..skipForDebugging = fatalSkip
|
|
..embedSourceText = !excludeSource
|
|
..debugDump = dumpIr
|
|
..debugDumpShowOffsets = showOffsets
|
|
..omitPlatform = omitPlatform
|
|
..verbose = verbose
|
|
..verify = verify
|
|
..skipPlatformVerification = skipPlatformVerification
|
|
..explicitExperimentalFlags = explicitExperimentalFlags
|
|
..environmentDefines = environmentDefines
|
|
..additionalDillModules = linkDependencies
|
|
..emitDeps = !noDeps
|
|
..invocationModes = InvocationMode.parseArguments(invocationModes)
|
|
..verbosity = Verbosity.parseArgument(verbosity);
|
|
|
|
if (programName == "compile_platform") {
|
|
if (arguments.length != 5) {
|
|
return throw new CommandLineProblem.deprecated(
|
|
"Expected five arguments.",
|
|
);
|
|
}
|
|
if (compileSdk) {
|
|
return throw new CommandLineProblem.deprecated(
|
|
"Cannot specify '${Flags.compileSdk}' option to compile_platform.",
|
|
);
|
|
}
|
|
if (parsedOptions.options.containsKey(Flags.output)) {
|
|
return throw new CommandLineProblem.deprecated(
|
|
"Cannot specify '${Flags.output}' option to compile_platform.",
|
|
);
|
|
}
|
|
|
|
return new ProcessedOptions(
|
|
options: compilerOptions
|
|
..sdkSummary = Options.platform.read(parsedOptions)
|
|
..librariesSpecificationUri = resolveInputUri(arguments[1])
|
|
..setExitCodeOnProblem = true,
|
|
inputs: arguments[0].split(',').map(Uri.parse).toList(),
|
|
output: resolveInputUri(arguments[3]),
|
|
);
|
|
} else if (arguments.isEmpty) {
|
|
return throw new CommandLineProblem.deprecated("No Dart file specified.");
|
|
}
|
|
|
|
final Uri defaultOutput = resolveInputUri("${arguments.first}.dill");
|
|
|
|
final Uri output = Options.output.read(parsedOptions) ?? defaultOutput;
|
|
|
|
final Uri? sdk =
|
|
Options.sdk.read(parsedOptions) ?? Options.compileSdk.read(parsedOptions);
|
|
|
|
final Uri? librariesJson = Options.librariesJson.read(parsedOptions);
|
|
|
|
final Uri? platform = compileSdk
|
|
? null
|
|
: (Options.platform.read(parsedOptions) ??
|
|
computePlatformBinariesLocation(forceBuildDir: true).resolve(
|
|
computePlatformDillName(target, () {
|
|
throwCommandLineProblem(
|
|
"Target '${target.name}' requires an explicit "
|
|
"'${Flags.platform}' option.",
|
|
);
|
|
})!,
|
|
));
|
|
compilerOptions
|
|
..sdkRoot = sdk
|
|
..sdkSummary = platform
|
|
..librariesSpecificationUri = librariesJson;
|
|
|
|
List<Uri> inputs = <Uri>[];
|
|
if (areRestArgumentsInputs) {
|
|
for (String argument in arguments) {
|
|
inputs.add(resolveInputUri(argument));
|
|
}
|
|
}
|
|
return new ProcessedOptions(
|
|
options: compilerOptions,
|
|
inputs: inputs,
|
|
output: output,
|
|
);
|
|
}
|
|
|
|
Future<T> withGlobalOptions<T>(
|
|
String programName,
|
|
List<String> arguments,
|
|
bool areRestArgumentsInputs,
|
|
Future<T> f(CompilerContext context, List<String> restArguments), {
|
|
FileSystemDependencyTracker? tracker,
|
|
}) {
|
|
ParsedOptions? parsedOptions;
|
|
ProcessedOptions options;
|
|
CommandLineProblem? problem;
|
|
try {
|
|
parsedOptions = ParsedOptions.parse(arguments, optionSpecification);
|
|
options = analyzeCommandLine(
|
|
tracker,
|
|
programName,
|
|
parsedOptions,
|
|
areRestArgumentsInputs,
|
|
);
|
|
} on CommandLineProblem catch (e) {
|
|
options = new ProcessedOptions();
|
|
problem = e;
|
|
}
|
|
|
|
return CompilerContext.runWithOptions<T>(options, (CompilerContext c) {
|
|
if (problem != null) {
|
|
print(computeUsage(programName, options.verbose).problemMessage);
|
|
PlainAndColorizedString formatted = c.format(
|
|
problem.message.withoutLocation(),
|
|
CfeSeverity.error,
|
|
);
|
|
String formattedText;
|
|
if (enableColors) {
|
|
formattedText = formatted.colorized;
|
|
} else {
|
|
formattedText = formatted.plain;
|
|
}
|
|
print(formattedText);
|
|
exit(1);
|
|
}
|
|
|
|
return f(c, parsedOptions!.arguments);
|
|
}, errorOnMissingInput: problem == null);
|
|
}
|
|
|
|
Message computeUsage(String programName, bool verbose) {
|
|
String basicUsage = "Usage: $programName [options] dartfile\n";
|
|
String? summary;
|
|
String options =
|
|
(verbose
|
|
? diag.fastaUsageLong.problemMessage
|
|
: diag.fastaUsageShort.problemMessage)
|
|
.trim();
|
|
switch (programName) {
|
|
case "outline":
|
|
summary =
|
|
"Creates an outline of a Dart program in the Dill/Kernel IR format.";
|
|
break;
|
|
|
|
case "compile":
|
|
summary = "Compiles a Dart program to the Dill/Kernel IR format.";
|
|
break;
|
|
|
|
case "run":
|
|
summary = "Runs a Dart program.";
|
|
break;
|
|
|
|
case "compile_platform":
|
|
summary = "Compiles Dart SDK platform to the Dill/Kernel IR format.";
|
|
basicUsage =
|
|
"Usage: $programName [options]"
|
|
" dart-library-uri libraries.json vm_outline.dill"
|
|
" platform.dill outline.dill\n";
|
|
}
|
|
StringBuffer sb = new StringBuffer(basicUsage);
|
|
if (summary != null) {
|
|
sb.writeln();
|
|
sb.writeln(summary);
|
|
sb.writeln();
|
|
}
|
|
sb.write(options);
|
|
// TODO(ahe): Don't use [codeUnspecified].
|
|
return diag.unspecified.withArguments(message: "$sb");
|
|
}
|
|
|
|
Future<T> runProtectedFromAbort<T>(
|
|
Future<T> Function() action, [
|
|
T? failingValue,
|
|
]) async {
|
|
try {
|
|
return await action();
|
|
} on DebugAbort catch (e) {
|
|
print(e.message.problemMessage);
|
|
|
|
// DebugAbort should never happen in production code, so we want test.py to
|
|
// treat this as a crash which is signalled by exiting with 255.
|
|
exit(255);
|
|
}
|
|
}
|