mirror of
https://github.com/dart-lang/sdk
synced 2024-10-02 23:59:16 +00:00
[dartdevc] add module-name option to kernel backend
This name is not used by most module formats, but we do use it with the legacy format. Change-Id: I8d2f36b12a60b37d0460b57d5a360ba21b4e0476 Reviewed-on: https://dart-review.googlesource.com/c/78923 Reviewed-by: Jake Macdonald <jakemac@google.com> Commit-Queue: Jenny Messerly <jmesserly@google.com>
This commit is contained in:
parent
b8760fed67
commit
f320477ff9
|
@ -48,7 +48,7 @@ import 'error_helpers.dart';
|
|||
import 'extension_types.dart' show ExtensionTypeSet;
|
||||
import 'js_interop.dart';
|
||||
import 'js_typerep.dart';
|
||||
import 'module_compiler.dart' show BuildUnit, CompilerOptions, JSModuleFile;
|
||||
import 'module_compiler.dart' show CompilerOptions, JSModuleFile;
|
||||
import 'nullable_type_inference.dart' show NullableTypeInference;
|
||||
import 'property_model.dart';
|
||||
import 'reify_coercions.dart' show CoercionReifier;
|
||||
|
@ -179,8 +179,6 @@ class CodeGenerator extends Object
|
|||
|
||||
final _deferredProperties = HashMap<PropertyAccessorElement, JS.Method>();
|
||||
|
||||
BuildUnit _buildUnit;
|
||||
|
||||
String _libraryRoot;
|
||||
|
||||
bool _superAllowed = true;
|
||||
|
@ -250,29 +248,29 @@ class CodeGenerator extends Object
|
|||
///
|
||||
/// Takes the metadata for the build unit, as well as resolved trees and
|
||||
/// errors, and computes the output module code and optionally the source map.
|
||||
JSModuleFile compile(BuildUnit unit, List<CompilationUnit> compilationUnits) {
|
||||
_buildUnit = unit;
|
||||
_libraryRoot = _buildUnit.libraryRoot;
|
||||
JSModuleFile compile(List<CompilationUnit> compilationUnits) {
|
||||
_libraryRoot = options.libraryRoot;
|
||||
if (!_libraryRoot.endsWith(path.separator)) {
|
||||
_libraryRoot += path.separator;
|
||||
}
|
||||
|
||||
var name = options.moduleName;
|
||||
invalidModule() =>
|
||||
JSModuleFile.invalid(unit.name, formatErrors(context, errors), options);
|
||||
JSModuleFile.invalid(name, formatErrors(context, errors), options);
|
||||
|
||||
if (!options.unsafeForceCompile && errors.any(_isFatalError)) {
|
||||
return invalidModule();
|
||||
}
|
||||
|
||||
try {
|
||||
var module = _emitModule(compilationUnits, unit.name);
|
||||
var module = _emitModule(compilationUnits, name);
|
||||
if (!options.unsafeForceCompile && errors.any(_isFatalError)) {
|
||||
return invalidModule();
|
||||
}
|
||||
|
||||
var dartApiSummary = _summarizeModule(compilationUnits);
|
||||
return JSModuleFile(unit.name, formatErrors(context, errors), options,
|
||||
module, dartApiSummary);
|
||||
return JSModuleFile(
|
||||
name, formatErrors(context, errors), options, module, dartApiSummary);
|
||||
} catch (e) {
|
||||
if (errors.any(_isFatalError)) {
|
||||
// Force compilation failed. Suppress the exception and report
|
||||
|
@ -443,7 +441,7 @@ class CodeGenerator extends Object
|
|||
_copyAndFlattenBlocks(items, moduleItems);
|
||||
|
||||
// Build the module.
|
||||
return JS.Program(items, name: _buildUnit.name);
|
||||
return JS.Program(items, name: options.moduleName);
|
||||
}
|
||||
|
||||
void _emitDebuggerExtensionInfo(String name) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import 'package:args/command_runner.dart' show UsageException;
|
|||
import 'package:path/path.dart' as path;
|
||||
|
||||
import 'context.dart' show AnalyzerOptions;
|
||||
import 'module_compiler.dart' show BuildUnit, CompilerOptions, ModuleCompiler;
|
||||
import 'module_compiler.dart' show CompilerOptions, ModuleCompiler;
|
||||
|
||||
const _binaryName = 'dartdevc';
|
||||
|
||||
|
@ -103,12 +103,7 @@ ArgParser ddcArgParser({bool hide = true}) {
|
|||
help: 'Ignore unrecognized command line flags.',
|
||||
defaultsTo: false,
|
||||
hide: hide)
|
||||
..addMultiOption('out', abbr: 'o', help: 'Output file (required).')
|
||||
..addOption('module-name',
|
||||
help: 'The output module name, used in some JS module formats.\n'
|
||||
'Defaults to the output file name (without .js).')
|
||||
..addOption('library-root',
|
||||
help: 'Root of source files. Library names are relative to this root.');
|
||||
..addMultiOption('out', abbr: 'o', help: 'Output file (required).');
|
||||
CompilerOptions.addArguments(argParser, hide: hide);
|
||||
defineAnalysisArguments(argParser, hide: hide, ddc: true);
|
||||
AnalyzerOptions.addArguments(argParser, hide: hide);
|
||||
|
@ -143,32 +138,7 @@ void _compile(ArgResults argResults, AnalyzerOptions analyzerOptions,
|
|||
'');
|
||||
}
|
||||
|
||||
// TODO(jmesserly): for now the first one is special. This will go away once
|
||||
// we've removed the "root" and "module name" variables.
|
||||
var firstOutPath = outPaths[0];
|
||||
|
||||
var libraryRoot = argResults['library-root'] as String;
|
||||
if (libraryRoot != null) {
|
||||
libraryRoot = path.absolute(libraryRoot);
|
||||
} else {
|
||||
libraryRoot = Directory.current.path;
|
||||
}
|
||||
var moduleName = argResults['module-name'] as String;
|
||||
if (moduleName == null) {
|
||||
var moduleRoot = compilerOpts.moduleRoot;
|
||||
if (moduleRoot != null) {
|
||||
// TODO(jmesserly): remove this legacy support after a deprecation period.
|
||||
// (Mainly this is to give time for migrating build rules.)
|
||||
moduleName =
|
||||
path.withoutExtension(path.relative(firstOutPath, from: moduleRoot));
|
||||
} else {
|
||||
moduleName = path.basenameWithoutExtension(firstOutPath);
|
||||
}
|
||||
}
|
||||
|
||||
var unit = BuildUnit(moduleName, libraryRoot, argResults.rest);
|
||||
|
||||
var module = compiler.compile(unit, compilerOpts);
|
||||
var module = compiler.compile(argResults.rest, compilerOpts);
|
||||
module.errors.forEach(printFn);
|
||||
|
||||
if (!module.isValid) {
|
||||
|
|
|
@ -133,14 +133,14 @@ class ModuleCompiler {
|
|||
/// *Warning* - this may require resolving the entire world.
|
||||
/// If that is not desired, the analysis context must be pre-configured using
|
||||
/// summaries before calling this method.
|
||||
JSModuleFile compile(BuildUnit unit, CompilerOptions options) {
|
||||
JSModuleFile compile(List<String> sourcePaths, CompilerOptions options) {
|
||||
var trees = <CompilationUnit>[];
|
||||
var errors = <AnalysisError>[];
|
||||
|
||||
var librariesToCompile = Queue<LibraryElement>();
|
||||
|
||||
var compilingSdk = false;
|
||||
for (var sourcePath in unit.sources) {
|
||||
for (var sourcePath in sourcePaths) {
|
||||
var sourceUri = sourcePathToUri(sourcePath);
|
||||
if (sourceUri.scheme == "dart") {
|
||||
compilingSdk = true;
|
||||
|
@ -201,9 +201,9 @@ class ModuleCompiler {
|
|||
}
|
||||
}
|
||||
|
||||
var codeGenerator =
|
||||
var compiler =
|
||||
CodeGenerator(context, summaryData, options, _extensionTypes, errors);
|
||||
return codeGenerator.compile(unit, trees);
|
||||
return compiler.compile(trees);
|
||||
}
|
||||
|
||||
Iterable<AnalysisError> _filterJsErrors(
|
||||
|
@ -256,6 +256,10 @@ class CompilerOptions extends SharedCompilerOptions {
|
|||
/// [summaryModules].
|
||||
final String moduleRoot;
|
||||
|
||||
/// *deprecated* If specified, `dartdevc` will synthesize library names that
|
||||
/// are relative to this path for all libraries in the JS module.
|
||||
final String libraryRoot;
|
||||
|
||||
CompilerOptions(
|
||||
{bool sourceMap = true,
|
||||
this.sourceMapComment = true,
|
||||
|
@ -269,7 +273,8 @@ class CompilerOptions extends SharedCompilerOptions {
|
|||
Map<String, String> bazelMapping = const {},
|
||||
this.summaryOutPath,
|
||||
Map<String, String> summaryModules = const {},
|
||||
this.moduleRoot})
|
||||
this.moduleRoot,
|
||||
this.libraryRoot})
|
||||
: super(
|
||||
sourceMap: sourceMap,
|
||||
summarizeApi: summarizeApi,
|
||||
|
@ -286,6 +291,7 @@ class CompilerOptions extends SharedCompilerOptions {
|
|||
unsafeForceCompile = args['unsafe-force-compile'] as bool,
|
||||
summaryOutPath = args['summary-out'] as String,
|
||||
moduleRoot = args['module-root'] as String,
|
||||
libraryRoot = _getLibraryRoot(args),
|
||||
super.fromArguments(args, args['module-root'] as String,
|
||||
args['summary-extension'] as String);
|
||||
|
||||
|
@ -312,27 +318,15 @@ class CompilerOptions extends SharedCompilerOptions {
|
|||
..addOption('module-root',
|
||||
help: '(deprecated) used to determine the default module name and\n'
|
||||
'summary import name if those are not provided.',
|
||||
hide: hide);
|
||||
hide: hide)
|
||||
..addOption('library-root',
|
||||
help: '(deprecated) used to name libraries inside the module.');
|
||||
}
|
||||
}
|
||||
|
||||
/// A unit of Dart code that can be built into a single JavaScript module.
|
||||
class BuildUnit {
|
||||
/// The name of this module.
|
||||
final String name;
|
||||
|
||||
/// All library names are relative to this path/prefix.
|
||||
final String libraryRoot;
|
||||
|
||||
/// The list of sources in this module.
|
||||
///
|
||||
/// The set of Dart files can be arbitrarily large, but it must contain
|
||||
/// complete libraries including all of their parts, as well as all libraries
|
||||
/// that are part of a library cycle.
|
||||
final List<String> sources;
|
||||
|
||||
BuildUnit(String modulePath, this.libraryRoot, this.sources)
|
||||
: name = '${path.toUri(modulePath)}';
|
||||
static String _getLibraryRoot(ArgResults args) {
|
||||
var root = args['library-root'] as String;
|
||||
return root != null ? path.absolute(root) : path.current;
|
||||
}
|
||||
}
|
||||
|
||||
/// The output of Dart->JS compilation.
|
||||
|
|
|
@ -41,14 +41,11 @@ ModuleFormat parseModuleFormat(String s) => {
|
|||
}[s];
|
||||
|
||||
/// Parse the module format option added by [addModuleFormatOptions].
|
||||
List<ModuleFormat> parseModuleFormatOption(ArgResults argResults) {
|
||||
var format = argResults['modules'];
|
||||
if (format is String) {
|
||||
return [parseModuleFormat(format)];
|
||||
}
|
||||
var formats = (format as List<String>).map(parseModuleFormat).toList();
|
||||
List<ModuleFormat> parseModuleFormatOption(ArgResults args) {
|
||||
var formats =
|
||||
(args['modules'] as List<String>).map(parseModuleFormat).toList();
|
||||
|
||||
if (argResults['single-out-file'] as bool) {
|
||||
if (args['single-out-file'] as bool) {
|
||||
for (int i = 0; i < formats.length; i++) {
|
||||
var format = formats[i];
|
||||
switch (formats[i]) {
|
||||
|
@ -72,8 +69,7 @@ List<ModuleFormat> parseModuleFormatOption(ArgResults argResults) {
|
|||
/// Adds an option to the [argParser] for choosing the module format, optionally
|
||||
/// [allowMultiple] formats to be specified, with each emitted into a separate
|
||||
/// file.
|
||||
void addModuleFormatOptions(ArgParser argParser,
|
||||
{bool allowMultiple = false, bool hide = true}) {
|
||||
void addModuleFormatOptions(ArgParser argParser, {bool hide = true}) {
|
||||
argParser.addMultiOption('modules', help: 'module pattern to emit', allowed: [
|
||||
'es6',
|
||||
'common',
|
||||
|
|
|
@ -83,6 +83,13 @@ class SharedCompilerOptions {
|
|||
|
||||
final List<ModuleFormat> moduleFormats;
|
||||
|
||||
/// The name of the module.
|
||||
///
|
||||
/// This used when to support file concatenation. The JS module will contain
|
||||
/// its module name inside itself, allowing it to declare the module name
|
||||
/// independently of the file.
|
||||
String moduleName;
|
||||
|
||||
SharedCompilerOptions(
|
||||
{this.sourceMap = true,
|
||||
this.summarizeApi = true,
|
||||
|
@ -91,7 +98,8 @@ class SharedCompilerOptions {
|
|||
this.replCompile = false,
|
||||
this.bazelMapping = const {},
|
||||
this.summaryModules = const {},
|
||||
this.moduleFormats = const []});
|
||||
this.moduleFormats = const [],
|
||||
this.moduleName});
|
||||
|
||||
SharedCompilerOptions.fromArguments(ArgResults args,
|
||||
[String moduleRoot, String summaryExtension])
|
||||
|
@ -104,10 +112,11 @@ class SharedCompilerOptions {
|
|||
_parseBazelMappings(args['bazel-mapping'] as List<String>),
|
||||
summaryModules: _parseCustomSummaryModules(
|
||||
args['summary'] as List<String>, moduleRoot, summaryExtension),
|
||||
moduleFormats: parseModuleFormatOption(args));
|
||||
moduleFormats: parseModuleFormatOption(args),
|
||||
moduleName: _getModuleName(args, moduleRoot));
|
||||
|
||||
static void addArguments(ArgParser parser, {bool hide = true}) {
|
||||
addModuleFormatOptions(parser, allowMultiple: true, hide: hide);
|
||||
addModuleFormatOptions(parser, hide: hide);
|
||||
|
||||
parser
|
||||
..addMultiOption('summary',
|
||||
|
@ -122,6 +131,9 @@ class SharedCompilerOptions {
|
|||
help: 'emit metadata annotations queriable via mirrors', hide: hide)
|
||||
..addFlag('enable-asserts',
|
||||
help: 'enable assertions', defaultsTo: true, hide: hide)
|
||||
..addOption('module-name',
|
||||
help: 'The output module name, used in some JS module formats.\n'
|
||||
'Defaults to the output file name (without .js).')
|
||||
// TODO(jmesserly): rename this, it has nothing to do with bazel.
|
||||
..addMultiOption('bazel-mapping',
|
||||
help: '--bazel-mapping=gen/to/library.dart,to/library.dart\n'
|
||||
|
@ -129,6 +141,32 @@ class SharedCompilerOptions {
|
|||
splitCommas: false,
|
||||
hide: hide);
|
||||
}
|
||||
|
||||
static String _getModuleName(ArgResults args, String moduleRoot) {
|
||||
var moduleName = args['module-name'] as String;
|
||||
if (moduleName == null) {
|
||||
var outPaths = args['out'];
|
||||
var outPath = outPaths is String
|
||||
? outPaths
|
||||
: (outPaths as List<String>)
|
||||
.firstWhere((_) => true, orElse: () => null);
|
||||
|
||||
if (moduleRoot != null) {
|
||||
// TODO(jmesserly): remove this legacy support after a deprecation period.
|
||||
// (Mainly this is to give time for migrating build rules.)
|
||||
moduleName =
|
||||
path.withoutExtension(path.relative(outPath, from: moduleRoot));
|
||||
} else {
|
||||
moduleName = path.basenameWithoutExtension(outPath);
|
||||
}
|
||||
}
|
||||
// TODO(jmesserly): this should probably use sourcePathToUri.
|
||||
//
|
||||
// Also we should not need this logic if the user passed in the module name
|
||||
// explicitly. It is here for backwards compatibility until we can confirm
|
||||
// that build systems do not depend on passing windows-style paths here.
|
||||
return path.toUri(moduleName).toString();
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds explicit module names of the form `path=name` in [summaryPaths],
|
||||
|
|
|
@ -221,6 +221,11 @@ Future<CompilerResult> _compile(List<String> args,
|
|||
var jsModule =
|
||||
compiler.emitModule(component, result.inputSummaries, summaryModules);
|
||||
|
||||
// TODO(jmesserly): support for multiple output formats?
|
||||
//
|
||||
// Also the old Analyzer backend had some code to make debugging better when
|
||||
// --single-out-file is used, but that option does not appear to be used by
|
||||
// any of our build systems.
|
||||
var jsCode = jsProgramToCode(jsModule, options.moduleFormats.first,
|
||||
buildSourceMap: argResults['source-map'] as bool,
|
||||
jsUrl: path.toUri(output).toString(),
|
||||
|
|
|
@ -234,12 +234,12 @@ class ProgramCompiler extends Object
|
|||
|
||||
bool get emitMetadata => options.emitMetadata;
|
||||
|
||||
JS.Program emitModule(Component buildUnit, List<Component> summaries,
|
||||
JS.Program emitModule(Component component, List<Component> summaries,
|
||||
Map<Uri, String> summaryModules) {
|
||||
if (moduleItems.isNotEmpty) {
|
||||
throw StateError('Can only call emitModule once.');
|
||||
}
|
||||
_component = buildUnit;
|
||||
_component = component;
|
||||
|
||||
var moduleImports = summaryModules.values.toList();
|
||||
for (var i = 0; i < summaries.length; i++) {
|
||||
|
@ -252,7 +252,7 @@ class ProgramCompiler extends Object
|
|||
}
|
||||
}
|
||||
|
||||
var libraries = buildUnit.libraries.where((l) => !l.isExternal);
|
||||
var libraries = component.libraries.where((l) => !l.isExternal);
|
||||
var ddcRuntime =
|
||||
libraries.firstWhere(isSdkInternalRuntime, orElse: () => null);
|
||||
if (ddcRuntime != null) {
|
||||
|
@ -335,7 +335,7 @@ class ProgramCompiler extends Object
|
|||
_copyAndFlattenBlocks(items, moduleItems);
|
||||
|
||||
// Build the module.
|
||||
return JS.Program(items, name: buildUnit.root.name);
|
||||
return JS.Program(items, name: options.moduleName);
|
||||
}
|
||||
|
||||
/// Flattens blocks in [items] to a single list.
|
||||
|
|
|
@ -52,9 +52,11 @@ Future main(List<String> args) async {
|
|||
await Directory(outputDir).create(recursive: true);
|
||||
await writeComponentToBinary(component, outputPath);
|
||||
|
||||
var jsModule =
|
||||
ProgramCompiler(component, target.hierarchy, SharedCompilerOptions(), {})
|
||||
.emitModule(component, [], {});
|
||||
var jsModule = ProgramCompiler(
|
||||
component,
|
||||
target.hierarchy,
|
||||
SharedCompilerOptions(moduleName: 'dart_sdk'),
|
||||
{}).emitModule(component, [], {});
|
||||
var moduleFormats = {
|
||||
'amd': ModuleFormat.amd,
|
||||
'common': ModuleFormat.common,
|
||||
|
|
|
@ -293,15 +293,14 @@ class WebCompileCommand extends Command {
|
|||
}
|
||||
resources.newFile(fileName, sourceCode);
|
||||
|
||||
var unit = BuildUnit(libraryName, "", [fileName]);
|
||||
|
||||
JSModuleFile module = compiler.compile(unit, compilerOptions);
|
||||
compilerOptions.moduleName = path.toUri(libraryName).toString();
|
||||
JSModuleFile module = compiler.compile([fileName], compilerOptions);
|
||||
|
||||
var moduleCode = '';
|
||||
if (module.isValid) {
|
||||
moduleCode = module
|
||||
.getCode(ModuleFormat.legacyConcat, unit.name, unit.name + '.map')
|
||||
.code;
|
||||
var name = compilerOptions.moduleName;
|
||||
moduleCode =
|
||||
module.getCode(ModuleFormat.legacyConcat, name, name + '.map').code;
|
||||
}
|
||||
|
||||
return CompileResult(
|
||||
|
|
Loading…
Reference in a new issue