Skip to content

Commit 807660f

Browse files
nshahanCommit Queue
authored andcommitted
[ddc] Create new options.dart library
This is a step towards organizing the code from shared_command.dart and eventually deleting it. - Move `SharedCompilerOptions` and rename to `Options` from shared_command.dart along with helpers. Change-Id: Ic9edfb47fc2425a28b1e948d94fad96a2f594108 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/388048 Reviewed-by: Johnni Winther <[email protected]> Reviewed-by: Mark Zhou <[email protected]> Reviewed-by: Sigmund Cherem <[email protected]> Reviewed-by: Nate Biggs <[email protected]> Commit-Queue: Nicholas Shahan <[email protected]>
1 parent 164777e commit 807660f

File tree

13 files changed

+390
-389
lines changed

13 files changed

+390
-389
lines changed

pkg/dev_compiler/lib/dev_compiler.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
// The dev_compiler does not have a publishable public API, instead this is
66
// intended for other consumers within the Dart SDK.
7+
export 'src/command/options.dart' show Options;
78
export 'src/compiler/module_builder.dart'
89
show ModuleFormat, parseModuleFormat, libraryUriToJsIdentifier;
9-
export 'src/compiler/shared_command.dart' show SharedCompilerOptions;
1010
export 'src/kernel/command.dart' show jsProgramToCode;
1111
export 'src/kernel/compiler.dart' show Compiler, ProgramCompiler;
1212
export 'src/kernel/compiler_new.dart' show LibraryBundleCompiler;
Lines changed: 363 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,363 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:args/args.dart';
6+
7+
import 'package:front_end/src/api_unstable/ddc.dart'
8+
show parseExperimentalArguments;
9+
import 'package:path/path.dart' as p;
10+
11+
import '../compiler/module_builder.dart';
12+
13+
/// Compiler options for the `dartdevc` backend.
14+
class Options {
15+
/// Whether to emit the source mapping file.
16+
///
17+
/// This supports debugging the original source code instead of the generated
18+
/// code.
19+
final bool sourceMap;
20+
21+
/// Whether to emit the source mapping file in the program text, so the
22+
/// runtime can enable synchronous stack trace deobfuscation.
23+
final bool inlineSourceMap;
24+
25+
/// Whether to emit the full compiled kernel.
26+
///
27+
/// This is used by expression compiler worker, launched from the debugger
28+
/// in webdev and google3 scenarios, for expression evaluation features.
29+
/// Full kernel for compiled files is needed to be able to compile
30+
/// expressions on demand in the current scope of a breakpoint.
31+
final bool emitFullCompiledKernel;
32+
33+
/// Whether to emit a summary file containing API signatures.
34+
///
35+
/// This is required for a modular build process.
36+
final bool summarizeApi;
37+
38+
// Whether to enable assertions.
39+
final bool enableAsserts;
40+
41+
/// Whether to compile code in a more permissive REPL mode allowing access
42+
/// to private members across library boundaries.
43+
///
44+
/// This should only set `true` by our REPL compiler.
45+
bool replCompile;
46+
47+
/// Whether to emit the debug metadata
48+
///
49+
/// Debugger uses this information about to construct mapping between
50+
/// modules and libraries that otherwise requires expensive communication with
51+
/// the browser.
52+
final bool emitDebugMetadata;
53+
54+
/// Whether to emit the debug symbols
55+
///
56+
/// Debugger uses this information about to construct mapping between
57+
/// dart and js objects that otherwise requires expensive communication with
58+
/// the browser.
59+
final bool emitDebugSymbols;
60+
61+
final Map<String, String> summaryModules;
62+
63+
final List<ModuleFormat> moduleFormats;
64+
65+
/// The name of the module.
66+
///
67+
/// This is used to support file concatenation. The JS module will contain its
68+
/// module name inside itself, allowing it to declare the module name
69+
/// independently of the file.
70+
final String moduleName;
71+
72+
/// Custom scheme to indicate a multi-root uri.
73+
final String multiRootScheme;
74+
75+
/// Path to set multi-root files relative to when generating source-maps.
76+
final String? multiRootOutputPath;
77+
78+
/// Experimental language features that are enabled/disabled, see
79+
/// [the spec](https://github.com/dart-lang/sdk/blob/master/docs/process/experimental-flags.md)
80+
/// for more details.
81+
final Map<String, bool> experiments;
82+
83+
final bool soundNullSafety;
84+
85+
/// Whether or not the `--canary` flag was specified during compilation.
86+
final bool canaryFeatures;
87+
88+
/// When `true` the [Component] will be compiled into a format compatible with
89+
/// hot reload.
90+
///
91+
/// The output will still be a single file containing each library in an
92+
/// isolated namespace.
93+
final bool emitLibraryBundle;
94+
95+
/// Whether the compiler is generating a dynamic module.
96+
final bool dynamicModule;
97+
98+
/// When `true` stars "*" will appear to represent legacy types when printing
99+
/// runtime types in the compiled application.
100+
final bool printLegacyStars = false;
101+
102+
/// Raw precompiled macro options, each of the format
103+
/// `<program-uri>;<macro-library-uri>`.
104+
///
105+
/// Multiple library URIs may be provided separated by additional semicolons.
106+
final List<String> precompiledMacros;
107+
108+
/// The serialization mode to use for macro communication.
109+
final String? macroSerializationMode;
110+
111+
Options(
112+
{this.sourceMap = true,
113+
this.inlineSourceMap = false,
114+
this.summarizeApi = true,
115+
this.enableAsserts = true,
116+
this.replCompile = false,
117+
this.emitDebugMetadata = false,
118+
this.emitDebugSymbols = false,
119+
this.emitFullCompiledKernel = false,
120+
this.summaryModules = const {},
121+
this.moduleFormats = const [],
122+
required this.moduleName,
123+
this.multiRootScheme = 'org-dartlang-app',
124+
this.multiRootOutputPath,
125+
this.experiments = const {},
126+
this.soundNullSafety = true,
127+
this.canaryFeatures = false,
128+
this.dynamicModule = false,
129+
this.precompiledMacros = const [],
130+
this.macroSerializationMode})
131+
: emitLibraryBundle = canaryFeatures &&
132+
moduleFormats.length == 1 &&
133+
moduleFormats.single == ModuleFormat.ddc;
134+
135+
Options.fromArguments(ArgResults args)
136+
: this(
137+
sourceMap: args['source-map'] as bool,
138+
inlineSourceMap: args['inline-source-map'] as bool,
139+
summarizeApi: args['summarize'] as bool,
140+
enableAsserts: args['enable-asserts'] as bool,
141+
replCompile: args['repl-compile'] as bool,
142+
emitDebugMetadata: args['experimental-emit-debug-metadata'] as bool,
143+
emitDebugSymbols: args['emit-debug-symbols'] as bool,
144+
emitFullCompiledKernel:
145+
args['experimental-output-compiled-kernel'] as bool,
146+
summaryModules:
147+
_parseCustomSummaryModules(args['summary'] as List<String>),
148+
moduleFormats: parseModuleFormatOption(args),
149+
moduleName: _getModuleName(args),
150+
multiRootScheme: args['multi-root-scheme'] as String,
151+
multiRootOutputPath: args['multi-root-output-path'] as String?,
152+
experiments: parseExperimentalArguments(
153+
args['enable-experiment'] as List<String>),
154+
soundNullSafety: args['sound-null-safety'] as bool,
155+
canaryFeatures: args['canary'] as bool,
156+
dynamicModule: args['dynamic-module'] as bool,
157+
precompiledMacros: args['precompiled-macro'] as List<String>,
158+
macroSerializationMode:
159+
args['macro-serialization-mode'] as String?);
160+
161+
Options.fromSdkRequiredArguments(ArgResults args)
162+
: this(
163+
summarizeApi: false,
164+
moduleFormats: parseModuleFormatOption(args),
165+
// When compiling the SDK use dart_sdk as the default. This is the
166+
// assumed name in various places around the build systems.
167+
moduleName:
168+
args['module-name'] != null ? _getModuleName(args) : 'dart_sdk',
169+
multiRootScheme: args['multi-root-scheme'] as String,
170+
multiRootOutputPath: args['multi-root-output-path'] as String?,
171+
experiments: parseExperimentalArguments(
172+
args['enable-experiment'] as List<String>),
173+
soundNullSafety: args['sound-null-safety'] as bool,
174+
canaryFeatures: args['canary'] as bool);
175+
176+
static void addArguments(ArgParser parser, {bool hide = true}) {
177+
addSdkRequiredArguments(parser, hide: hide);
178+
179+
parser
180+
..addMultiOption('summary',
181+
abbr: 's',
182+
help: 'API summary file(s) of imported libraries, optionally\n'
183+
'with module import path: -s path.dill=js/import/path')
184+
..addFlag('summarize',
185+
help: 'Emit an API summary file.', defaultsTo: true, hide: hide)
186+
..addFlag('source-map',
187+
help: 'Emit source mapping.', defaultsTo: true, hide: hide)
188+
..addFlag('inline-source-map',
189+
help: 'Emit source mapping inline.', defaultsTo: false, hide: hide)
190+
..addFlag('enable-asserts',
191+
help: 'Enable assertions.', defaultsTo: true, hide: hide)
192+
..addFlag('repl-compile',
193+
help: 'Compile in a more permissive REPL mode, allowing access'
194+
' to private members across library boundaries. This should'
195+
' only be used by debugging tools.',
196+
defaultsTo: false,
197+
hide: hide)
198+
// TODO(41852) Define a process for breaking changes before graduating from
199+
// experimental.
200+
..addFlag('experimental-emit-debug-metadata',
201+
help: 'Experimental option for compiler development.\n'
202+
'Output a metadata file for debug tools next to the .js output.',
203+
defaultsTo: false,
204+
hide: true)
205+
..addFlag('emit-debug-symbols',
206+
help: 'Experimental option for compiler development.\n'
207+
'Output a symbols file for debug tools next to the .js output.',
208+
defaultsTo: false,
209+
hide: true)
210+
..addFlag('experimental-output-compiled-kernel',
211+
help: 'Experimental option for compiler development.\n'
212+
'Output a full kernel file for currently compiled module next to '
213+
'the .js output.',
214+
defaultsTo: false,
215+
hide: true)
216+
..addMultiOption('precompiled-macro',
217+
help:
218+
'Configuration for precompiled macro binaries or kernel files.\n'
219+
'The expected format of this option is as follows: '
220+
'<absolute-path-to-binary>;<macro-library-uri>\nFor example: '
221+
'--precompiled-macro="/path/to/compiled/macro;'
222+
'package:some_macro/some_macro.dart". Multiple library uris may be '
223+
'passed as well (separated by semicolons).',
224+
hide: true)
225+
..addOption('macro-serialization-mode',
226+
help: 'The serialization mode for communicating with macros.',
227+
allowed: ['bytedata', 'json'],
228+
defaultsTo: 'bytedata')
229+
..addFlag('dynamic-module',
230+
help: 'Compile to generate a dynamic module',
231+
negatable: false,
232+
defaultsTo: false);
233+
}
234+
235+
/// Adds only the arguments used to compile the SDK from a full dill file.
236+
///
237+
/// NOTE: The 'module-name' option will have a special default value of
238+
/// 'dart_sdk' when compiling the SDK.
239+
/// See [SharedOptions.fromSdkRequiredArguments].
240+
static void addSdkRequiredArguments(ArgParser parser, {bool hide = true}) {
241+
addModuleFormatOptions(parser, hide: hide);
242+
parser
243+
..addMultiOption('out', abbr: 'o', help: 'Output file (required).')
244+
..addOption('module-name',
245+
help: 'The output module name, used in some JS module formats.\n'
246+
'Defaults to the output file name (without .js).')
247+
..addOption('multi-root-scheme',
248+
help: 'The custom scheme to indicate a multi-root uri.',
249+
defaultsTo: 'org-dartlang-app')
250+
..addOption('multi-root-output-path',
251+
help: 'Path to set multi-root files relative to when generating'
252+
' source-maps.',
253+
hide: true)
254+
..addMultiOption('enable-experiment',
255+
help: 'Enable/disable experimental language features.', hide: hide)
256+
..addFlag('sound-null-safety',
257+
help: 'Compile for sound null safety at runtime.',
258+
negatable: true,
259+
defaultsTo: true)
260+
..addFlag('canary',
261+
help: 'Enable all compiler features under active development. '
262+
'This option is intended for compiler development only. '
263+
'Canary features are likely to be unstable and can be removed '
264+
'without warning.',
265+
defaultsTo: false,
266+
hide: true);
267+
}
268+
269+
static String _getModuleName(ArgResults args) {
270+
var moduleName = args['module-name'] as String?;
271+
if (moduleName == null) {
272+
var outPaths = args['out'] as List<String>;
273+
if (outPaths.isEmpty) {
274+
throw UnsupportedError(
275+
'No module name provided and unable to synthesize one without any '
276+
'output paths.');
277+
}
278+
var outPath = outPaths.first;
279+
moduleName = p.basenameWithoutExtension(outPath);
280+
}
281+
// TODO(jmesserly): this should probably use sourcePathToUri.
282+
//
283+
// Also we should not need this logic if the user passed in the module name
284+
// explicitly. It is here for backwards compatibility until we can confirm
285+
// that build systems do not depend on passing windows-style paths here.
286+
return p.toUri(moduleName).toString();
287+
}
288+
}
289+
290+
/// Finds explicit module names of the form `path=name` in [summaryPaths],
291+
/// and returns the path to mapping in an ordered map from `path` to `name`.
292+
///
293+
/// A summary path can contain "=" followed by an explicit module name to
294+
/// allow working with summaries whose physical location is outside of the
295+
/// module root directory.
296+
Map<String, String> _parseCustomSummaryModules(List<String> summaryPaths,
297+
[String? moduleRoot, String? summaryExt]) {
298+
var pathToModule = <String, String>{};
299+
for (var summaryPath in summaryPaths) {
300+
var equalSign = summaryPath.indexOf('=');
301+
String modulePath;
302+
var summaryPathWithoutExt = summaryExt != null
303+
? summaryPath.substring(
304+
0,
305+
// Strip off the extension, including the last `.`.
306+
summaryPath.length - (summaryExt.length + 1))
307+
: p.withoutExtension(summaryPath);
308+
if (equalSign != -1) {
309+
modulePath = summaryPath.substring(equalSign + 1);
310+
summaryPath = summaryPath.substring(0, equalSign);
311+
} else if (moduleRoot != null && p.isWithin(moduleRoot, summaryPath)) {
312+
// TODO: Determine if this logic is still needed.
313+
modulePath = p.url.joinAll(
314+
p.split(p.relative(summaryPathWithoutExt, from: moduleRoot)));
315+
} else {
316+
modulePath = p.basename(summaryPathWithoutExt);
317+
}
318+
pathToModule[summaryPath] = modulePath;
319+
}
320+
return pathToModule;
321+
}
322+
323+
/// Taken from analyzer to implement `--ignore-unrecognized-flags`
324+
List<String> filterUnknownArguments(List<String> args, ArgParser parser) {
325+
if (!args.contains('--ignore-unrecognized-flags')) return args;
326+
327+
var knownOptions = <String>{};
328+
var knownAbbreviations = <String>{};
329+
parser.options.forEach((String name, Option option) {
330+
knownOptions.add(name);
331+
var abbreviation = option.abbr;
332+
if (abbreviation != null) {
333+
knownAbbreviations.add(abbreviation);
334+
}
335+
if (option.negatable != null && option.negatable!) {
336+
knownOptions.add('no-$name');
337+
}
338+
});
339+
340+
String optionName(int prefixLength, String arg) {
341+
var equalsOffset = arg.lastIndexOf('=');
342+
if (equalsOffset < 0) {
343+
return arg.substring(prefixLength);
344+
}
345+
return arg.substring(prefixLength, equalsOffset);
346+
}
347+
348+
var filtered = <String>[];
349+
for (var arg in args) {
350+
if (arg.startsWith('--') && arg.length > 2) {
351+
if (knownOptions.contains(optionName(2, arg))) {
352+
filtered.add(arg);
353+
}
354+
} else if (arg.startsWith('-') && arg.length > 1) {
355+
if (knownAbbreviations.contains(optionName(1, arg))) {
356+
filtered.add(arg);
357+
}
358+
} else {
359+
filtered.add(arg);
360+
}
361+
}
362+
return filtered;
363+
}

0 commit comments

Comments
 (0)