mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:00:09 +00:00
[dart2js] Support running modular analysis alongside building a dill.
Change-Id: If10385445c5f6267e2de20b090b37e1741b7ace7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/237925 Reviewed-by: Johnni Winther <johnniwinther@google.com> Reviewed-by: Sigmund Cherem <sigmund@google.com> Commit-Queue: Joshua Litt <joshualitt@google.com>
This commit is contained in:
parent
818f886f1d
commit
b1fbe0c01d
|
@ -112,6 +112,7 @@ class Flags {
|
|||
static const String reportAllMetrics = '--report-all-metrics';
|
||||
|
||||
static const String dillDependencies = '--dill-dependencies';
|
||||
static const String sources = '--sources';
|
||||
static const String readData = '--read-data';
|
||||
static const String writeData = '--write-data';
|
||||
static const String noClosedWorldInData = '--no-closed-world-in-data';
|
||||
|
|
|
@ -133,6 +133,7 @@ Future<api.CompilationResult> compile(List<String> argv,
|
|||
bool showWarnings;
|
||||
bool showHints;
|
||||
bool enableColors;
|
||||
List<Uri> sources;
|
||||
int optimizationLevel = null;
|
||||
Uri platformBinaries;
|
||||
Map<String, String> environment = Map<String, String>();
|
||||
|
@ -289,11 +290,12 @@ Future<api.CompilationResult> compile(List<String> argv,
|
|||
Uri.base.resolve(extractPath(argument, isDirectory: true));
|
||||
}
|
||||
|
||||
void setUriList(String flag, String argument) {
|
||||
List<Uri> setUriList(String flag, String argument) {
|
||||
String list = extractParameter(argument);
|
||||
String uriList = list.splitMapJoin(',',
|
||||
onMatch: (_) => ',', onNonMatch: (p) => '${fe.nativeToUri(p)}');
|
||||
List<Uri> uris = list.split(',').map(fe.nativeToUri).toList();
|
||||
String uriList = uris.map((uri) => '$uri').join(',');
|
||||
options.add('${flag}=${uriList}');
|
||||
return uris;
|
||||
}
|
||||
|
||||
void setModularAnalysisInputs(String argument) {
|
||||
|
@ -361,6 +363,10 @@ Future<api.CompilationResult> compile(List<String> argv,
|
|||
setUriList(Flags.dillDependencies, argument);
|
||||
}
|
||||
|
||||
void setSources(String argument) {
|
||||
sources = setUriList(Flags.sources, argument);
|
||||
}
|
||||
|
||||
void setCfeOnly(String argument) {
|
||||
if (writeStrategy == WriteStrategy.toModularAnalysis) {
|
||||
fail("Cannot use ${Flags.cfeOnly} "
|
||||
|
@ -547,6 +553,7 @@ Future<api.CompilationResult> compile(List<String> argv,
|
|||
OptionHandler('--library-root=.+', ignoreOption),
|
||||
OptionHandler('--libraries-spec=.+', setLibrarySpecificationUri),
|
||||
OptionHandler('${Flags.dillDependencies}=.+', setDillDependencies),
|
||||
OptionHandler('${Flags.sources}=.+', setSources),
|
||||
OptionHandler('${Flags.readModularAnalysis}=.+', setModularAnalysisInputs),
|
||||
OptionHandler(
|
||||
'${Flags.writeModularAnalysis}|${Flags.writeModularAnalysis}=.+',
|
||||
|
@ -761,7 +768,10 @@ Future<api.CompilationResult> compile(List<String> argv,
|
|||
helpAndExit(wantHelp, wantVersion, diagnosticHandler.verbose);
|
||||
}
|
||||
|
||||
if (arguments.isEmpty && entryUri == null && inputDillUri == null) {
|
||||
if (arguments.isEmpty &&
|
||||
entryUri == null &&
|
||||
inputDillUri == null &&
|
||||
sources == null) {
|
||||
helpAndFail('No Dart file specified.');
|
||||
}
|
||||
|
||||
|
@ -787,8 +797,11 @@ Future<api.CompilationResult> compile(List<String> argv,
|
|||
}
|
||||
|
||||
// Make [scriptName] a relative path..
|
||||
String scriptName =
|
||||
fe.relativizeUri(Uri.base, inputDillUri ?? entryUri, Platform.isWindows);
|
||||
String scriptName = sources == null
|
||||
? fe.relativizeUri(Uri.base, inputDillUri ?? entryUri, Platform.isWindows)
|
||||
: sources
|
||||
.map((uri) => fe.relativizeUri(Uri.base, uri, Platform.isWindows))
|
||||
.join(',');
|
||||
|
||||
switch (writeStrategy) {
|
||||
case WriteStrategy.toJs:
|
||||
|
|
|
@ -171,6 +171,7 @@ class CompilerOptions implements DiagnosticOptions {
|
|||
Uri? get compilationTarget => inputDillUri ?? entryUri;
|
||||
|
||||
bool get fromDill {
|
||||
if (sources != null) return false;
|
||||
var targetPath = compilationTarget!.path;
|
||||
return targetPath.endsWith('.dill');
|
||||
}
|
||||
|
@ -191,6 +192,9 @@ class CompilerOptions implements DiagnosticOptions {
|
|||
/// files for linking.
|
||||
List<Uri>? dillDependencies;
|
||||
|
||||
/// A list of sources to compile, only used for modular analysis.
|
||||
List<Uri>? sources;
|
||||
|
||||
Uri? writeModularAnalysisUri;
|
||||
|
||||
/// Helper to determine if compiler is being run just for modular analysis.
|
||||
|
@ -676,6 +680,7 @@ class CompilerOptions implements DiagnosticOptions {
|
|||
..showInternalProgress = _hasOption(options, Flags.progress)
|
||||
..dillDependencies =
|
||||
_extractUriListOption(options, '${Flags.dillDependencies}')
|
||||
..sources = _extractUriListOption(options, '${Flags.sources}')
|
||||
..readProgramSplit =
|
||||
_extractUriOption(options, '${Flags.readProgramSplit}=')
|
||||
..writeModularAnalysisUri =
|
||||
|
|
|
@ -195,8 +195,10 @@ Future<_LoadFromKernelResult> _loadFromKernel(CompilerOptions options,
|
|||
class _LoadFromSourceResult {
|
||||
final ir.Component component;
|
||||
final fe.InitializedCompilerState initializedCompilerState;
|
||||
final List<Uri> moduleLibraries;
|
||||
|
||||
_LoadFromSourceResult(this.component, this.initializedCompilerState);
|
||||
_LoadFromSourceResult(
|
||||
this.component, this.initializedCompilerState, this.moduleLibraries);
|
||||
}
|
||||
|
||||
Future<_LoadFromSourceResult> _loadFromSource(
|
||||
|
@ -215,21 +217,36 @@ Future<_LoadFromSourceResult> _loadFromSource(
|
|||
reportFrontEndMessage(reporter, message);
|
||||
}
|
||||
};
|
||||
fe.CompilerOptions feOptions = fe.CompilerOptions()
|
||||
..target = target
|
||||
..librariesSpecificationUri = options.librariesSpecificationUri
|
||||
..packagesFileUri = options.packageConfig
|
||||
..explicitExperimentalFlags = options.explicitExperimentalFlags
|
||||
..verbose = verbose
|
||||
..fileSystem = fileSystem
|
||||
..onDiagnostic = onDiagnostic
|
||||
..verbosity = verbosity;
|
||||
Uri resolvedUri = options.compilationTarget;
|
||||
bool isLegacy = await fe.uriUsesLegacyLanguageVersion(resolvedUri, feOptions);
|
||||
_inferNullSafetyMode(options, !isLegacy);
|
||||
|
||||
// If we are passed a list of sources, then we are performing a modular
|
||||
// compile. In this case, we cannot infer null safety from the source files
|
||||
// and must instead rely on the options passed in on the command line.
|
||||
bool isModularCompile = false;
|
||||
List<Uri> sources = [];
|
||||
if (options.sources != null) {
|
||||
isModularCompile = true;
|
||||
sources.addAll(options.sources);
|
||||
} else {
|
||||
fe.CompilerOptions feOptions = fe.CompilerOptions()
|
||||
..target = target
|
||||
..librariesSpecificationUri = options.librariesSpecificationUri
|
||||
..packagesFileUri = options.packageConfig
|
||||
..explicitExperimentalFlags = options.explicitExperimentalFlags
|
||||
..verbose = verbose
|
||||
..fileSystem = fileSystem
|
||||
..onDiagnostic = onDiagnostic
|
||||
..verbosity = verbosity;
|
||||
Uri resolvedUri = options.compilationTarget;
|
||||
bool isLegacy =
|
||||
await fe.uriUsesLegacyLanguageVersion(resolvedUri, feOptions);
|
||||
_inferNullSafetyMode(options, !isLegacy);
|
||||
sources.add(options.compilationTarget);
|
||||
}
|
||||
|
||||
// If we are performing a modular compile, we expect the platform binary to be
|
||||
// supplied along with other dill dependencies.
|
||||
List<Uri> dependencies = [];
|
||||
if (options.platformBinaries != null) {
|
||||
if (options.platformBinaries != null && !isModularCompile) {
|
||||
dependencies.add(options.platformBinaries
|
||||
.resolve(_getPlatformFilename(options, targetName)));
|
||||
}
|
||||
|
@ -248,10 +265,17 @@ Future<_LoadFromSourceResult> _loadFromSource(
|
|||
options.useLegacySubtyping ? fe.NnbdMode.Weak : fe.NnbdMode.Strong,
|
||||
invocationModes: options.cfeInvocationModes,
|
||||
verbosity: verbosity);
|
||||
ir.Component component = await fe.compile(
|
||||
initializedCompilerState, verbose, fileSystem, onDiagnostic, resolvedUri);
|
||||
ir.Component component = await fe.compile(initializedCompilerState, verbose,
|
||||
fileSystem, onDiagnostic, sources, isModularCompile);
|
||||
_validateNullSafetyMode(options);
|
||||
return _LoadFromSourceResult(component, initializedCompilerState);
|
||||
|
||||
// We have to compute canonical names on the component here to avoid missing
|
||||
// canonical names downstream.
|
||||
if (isModularCompile) {
|
||||
component.computeCanonicalNames();
|
||||
}
|
||||
return _LoadFromSourceResult(
|
||||
component, initializedCompilerState, isModularCompile ? sources : []);
|
||||
}
|
||||
|
||||
Output _createOutput(
|
||||
|
@ -336,6 +360,7 @@ Future<Output> run(Input input) async {
|
|||
reporter, input.initializedCompilerState, targetName);
|
||||
component = result.component;
|
||||
initializedCompilerState = result.initializedCompilerState;
|
||||
moduleLibraries = result.moduleLibraries;
|
||||
}
|
||||
if (component == null) return null;
|
||||
if (input.forceSerialization) {
|
||||
|
|
|
@ -30,7 +30,8 @@ main() {
|
|||
(fe.DiagnosticMessage message) {
|
||||
message.plainTextFormatted.forEach(print);
|
||||
Expect.notEquals(fe.Severity.error, message.severity);
|
||||
}, Uri.base.resolve('pkg/compiler/test/end_to_end/data/hello_world.dart'));
|
||||
}, [Uri.base.resolve('pkg/compiler/test/end_to_end/data/hello_world.dart')],
|
||||
false);
|
||||
Expect.isNotNull(new ir.CoreTypes(component).futureClass);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@ main(List<String> args) async {
|
|||
options,
|
||||
IOPipeline([
|
||||
OutlineDillCompilationStep(),
|
||||
FullDillCompilationStep(),
|
||||
FullDillCompilationStep(onlyOnSdk: true),
|
||||
ModularAnalysisStep(onlyOnSdk: true),
|
||||
ModularAnalysisStep(),
|
||||
ConcatenateDillsStep(useModularAnalysis: true),
|
||||
ComputeClosedWorldStep(useModularAnalysis: true),
|
||||
|
|
|
@ -51,10 +51,95 @@ String _packageConfigEntry(String name, Uri root,
|
|||
return '{${fields.join(',')}}';
|
||||
}
|
||||
|
||||
abstract class CFEStep implements IOModularStep {
|
||||
String getRootScheme(Module module) {
|
||||
// We use non file-URI schemes for representeing source locations in a
|
||||
// root-agnostic way. This allows us to refer to file across modules and
|
||||
// across steps without exposing the underlying temporary folders that are
|
||||
// created by the framework. In build systems like bazel this is especially
|
||||
// important because each step may be run on a different machine.
|
||||
//
|
||||
// Files in packages are defined in terms of `package:` URIs, while
|
||||
// non-package URIs are defined using the `dart-dev-app` scheme.
|
||||
return module.isSdk ? 'dart-dev-sdk' : 'dev-dart-app';
|
||||
}
|
||||
|
||||
String sourceToImportUri(Module module, Uri relativeUri) {
|
||||
if (module.isPackage) {
|
||||
var basePath = module.packageBase.path;
|
||||
var packageRelativePath = basePath == "./"
|
||||
? relativeUri.path
|
||||
: relativeUri.path.substring(basePath.length);
|
||||
return 'package:${module.name}/$packageRelativePath';
|
||||
} else {
|
||||
return '${getRootScheme(module)}:/$relativeUri';
|
||||
}
|
||||
}
|
||||
|
||||
List<String> getSources(Module module) {
|
||||
return module.sources.map((uri) => sourceToImportUri(module, uri)).toList();
|
||||
}
|
||||
|
||||
void writePackageConfig(
|
||||
Module module, Set<Module> transitiveDependencies, Uri root) async {
|
||||
// TODO(joshualitt): Figure out a way to support package configs in
|
||||
// tests/modular.
|
||||
var packageConfig = await loadPackageConfigUri(packageConfigUri);
|
||||
|
||||
// We create both a .packages and package_config.json file which defines
|
||||
// the location of this module if it is a package. The CFE requires that
|
||||
// if a `package:` URI of a dependency is used in an import, then we need
|
||||
// that package entry in the associated file. However, after it checks that
|
||||
// the definition exists, the CFE will not actually use the resolved URI if
|
||||
// a library for the import URI is already found in one of the provide
|
||||
// .dill files of the dependencies. For that reason, and to ensure that
|
||||
// a step only has access to the files provided in a module, we generate a
|
||||
// config file with invalid folders for other packages.
|
||||
// TODO(sigmund): follow up with the CFE to see if we can remove the need
|
||||
// for these dummy entries..
|
||||
// TODO(joshualitt): Generate just the json file.
|
||||
var packagesJson = [];
|
||||
var packagesContents = StringBuffer();
|
||||
if (module.isPackage) {
|
||||
packagesContents.write('${module.name}:${module.packageBase}\n');
|
||||
packagesJson.add(_packageConfigEntry(
|
||||
module.name, Uri.parse('../${module.packageBase}')));
|
||||
}
|
||||
|
||||
int unusedNum = 0;
|
||||
for (Module dependency in transitiveDependencies) {
|
||||
if (dependency.isPackage) {
|
||||
// rootUri should be ignored for dependent modules, so we pass in a
|
||||
// bogus value.
|
||||
var rootUri = Uri.parse('unused$unusedNum');
|
||||
unusedNum++;
|
||||
|
||||
var dependentPackage = packageConfig[dependency.name];
|
||||
var packageJson = dependentPackage == null
|
||||
? _packageConfigEntry(dependency.name, rootUri)
|
||||
: _packageConfigEntry(dependentPackage.name, rootUri,
|
||||
version: dependentPackage.languageVersion);
|
||||
packagesJson.add(packageJson);
|
||||
packagesContents.write('${dependency.name}:$rootUri\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (module.isPackage) {
|
||||
await File.fromUri(root.resolve(packageConfigJsonPath))
|
||||
.create(recursive: true);
|
||||
await File.fromUri(root.resolve(packageConfigJsonPath)).writeAsString('{'
|
||||
' "configVersion": ${packageConfig.version},'
|
||||
' "packages": [ ${packagesJson.join(',')} ]'
|
||||
'}');
|
||||
}
|
||||
|
||||
await File.fromUri(root.resolve('.packages'))
|
||||
.writeAsString('$packagesContents');
|
||||
}
|
||||
|
||||
abstract class CFEStep extends IOModularStep {
|
||||
final String stepName;
|
||||
|
||||
CFEStep(this.stepName);
|
||||
CFEStep(this.stepName, this.onlyOnSdk);
|
||||
|
||||
@override
|
||||
bool get needsSources => true;
|
||||
|
@ -62,87 +147,18 @@ abstract class CFEStep implements IOModularStep {
|
|||
@override
|
||||
bool get onlyOnMain => false;
|
||||
|
||||
@override
|
||||
final bool onlyOnSdk;
|
||||
|
||||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
if (_options.verbose) print("\nstep: $stepName on $module");
|
||||
|
||||
// TODO(joshualitt): Figure out a way to support package configs in
|
||||
// tests/modular.
|
||||
var packageConfig = await loadPackageConfigUri(packageConfigUri);
|
||||
|
||||
// We use non file-URI schemes for representeing source locations in a
|
||||
// root-agnostic way. This allows us to refer to file across modules and
|
||||
// across steps without exposing the underlying temporary folders that are
|
||||
// created by the framework. In build systems like bazel this is especially
|
||||
// important because each step may be run on a different machine.
|
||||
//
|
||||
// Files in packages are defined in terms of `package:` URIs, while
|
||||
// non-package URIs are defined using the `dart-dev-app` scheme.
|
||||
String rootScheme = module.isSdk ? 'dart-dev-sdk' : 'dev-dart-app';
|
||||
String sourceToImportUri(Uri relativeUri) {
|
||||
if (module.isPackage) {
|
||||
var basePath = module.packageBase.path;
|
||||
var packageRelativePath = basePath == "./"
|
||||
? relativeUri.path
|
||||
: relativeUri.path.substring(basePath.length);
|
||||
return 'package:${module.name}/$packageRelativePath';
|
||||
} else {
|
||||
return '$rootScheme:/$relativeUri';
|
||||
}
|
||||
}
|
||||
|
||||
// We create both a .packages and package_config.json file which defines
|
||||
// the location of this module if it is a package. The CFE requires that
|
||||
// if a `package:` URI of a dependency is used in an import, then we need
|
||||
// that package entry in the associated file. However, after it checks that
|
||||
// the definition exists, the CFE will not actually use the resolved URI if
|
||||
// a library for the import URI is already found in one of the provide
|
||||
// .dill files of the dependencies. For that reason, and to ensure that
|
||||
// a step only has access to the files provided in a module, we generate a
|
||||
// config file with invalid folders for other packages.
|
||||
// TODO(sigmund): follow up with the CFE to see if we can remove the need
|
||||
// for these dummy entries..
|
||||
// TODO(joshualitt): Generate just the json file.
|
||||
var packagesJson = [];
|
||||
var packagesContents = StringBuffer();
|
||||
if (module.isPackage) {
|
||||
packagesContents.write('${module.name}:${module.packageBase}\n');
|
||||
packagesJson.add(_packageConfigEntry(
|
||||
module.name, Uri.parse('../${module.packageBase}')));
|
||||
}
|
||||
|
||||
Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
|
||||
int unusedNum = 0;
|
||||
for (Module dependency in transitiveDependencies) {
|
||||
if (dependency.isPackage) {
|
||||
// rootUri should be ignored for dependent modules, so we pass in a
|
||||
// bogus value.
|
||||
var rootUri = Uri.parse('unused$unusedNum');
|
||||
unusedNum++;
|
||||
|
||||
var dependentPackage = packageConfig[dependency.name];
|
||||
var packageJson = dependentPackage == null
|
||||
? _packageConfigEntry(dependency.name, rootUri)
|
||||
: _packageConfigEntry(dependentPackage.name, rootUri,
|
||||
version: dependentPackage.languageVersion);
|
||||
packagesJson.add(packageJson);
|
||||
packagesContents.write('${dependency.name}:$rootUri\n');
|
||||
}
|
||||
}
|
||||
|
||||
if (module.isPackage) {
|
||||
await File.fromUri(root.resolve(packageConfigJsonPath))
|
||||
.create(recursive: true);
|
||||
await File.fromUri(root.resolve(packageConfigJsonPath)).writeAsString('{'
|
||||
' "configVersion": ${packageConfig.version},'
|
||||
' "packages": [ ${packagesJson.join(',')} ]'
|
||||
'}');
|
||||
}
|
||||
|
||||
await File.fromUri(root.resolve('.packages'))
|
||||
.writeAsString('$packagesContents');
|
||||
writePackageConfig(module, transitiveDependencies, root);
|
||||
|
||||
String rootScheme = getRootScheme(module);
|
||||
List<String> sources;
|
||||
List<String> extraArgs = ['--packages-file', '$rootScheme:/.packages'];
|
||||
if (module.isSdk) {
|
||||
|
@ -165,7 +181,7 @@ abstract class CFEStep implements IOModularStep {
|
|||
];
|
||||
assert(transitiveDependencies.isEmpty);
|
||||
} else {
|
||||
sources = module.sources.map(sourceToImportUri).toList();
|
||||
sources = getSources(module);
|
||||
}
|
||||
|
||||
// TODO(joshualitt): Ensure the kernel worker has some way to specify
|
||||
|
@ -228,7 +244,7 @@ class OutlineDillCompilationStep extends CFEStep {
|
|||
@override
|
||||
DataId get outputData => dillSummaryId;
|
||||
|
||||
OutlineDillCompilationStep() : super('outline-dill-compilation');
|
||||
OutlineDillCompilationStep() : super('outline-dill-compilation', false);
|
||||
}
|
||||
|
||||
// Step that compiles sources in a module to a .dill file.
|
||||
|
@ -255,42 +271,81 @@ class FullDillCompilationStep extends CFEStep {
|
|||
@override
|
||||
DataId get outputData => dillId;
|
||||
|
||||
FullDillCompilationStep() : super('full-dill-compilation');
|
||||
FullDillCompilationStep({bool onlyOnSdk = false})
|
||||
: super('full-dill-compilation', onlyOnSdk);
|
||||
}
|
||||
|
||||
class ModularAnalysisStep implements IOModularStep {
|
||||
class ModularAnalysisStep extends IOModularStep {
|
||||
@override
|
||||
List<DataId> get resultData => const [modularDataId, modularUpdatedDillId];
|
||||
List<DataId> get resultData => [modularDataId, modularUpdatedDillId];
|
||||
|
||||
@override
|
||||
bool get needsSources => false;
|
||||
bool get needsSources => !onlyOnSdk;
|
||||
|
||||
/// The SDK has no dependencies, and for all other modules we only need
|
||||
/// summaries.
|
||||
@override
|
||||
List<DataId> get dependencyDataNeeded => const [dillId];
|
||||
List<DataId> get dependencyDataNeeded => [dillSummaryId];
|
||||
|
||||
/// All non SDK modules only need sources for module data.
|
||||
@override
|
||||
List<DataId> get moduleDataNeeded => const [dillId];
|
||||
List<DataId> get moduleDataNeeded => onlyOnSdk ? [dillId] : const [];
|
||||
|
||||
@override
|
||||
bool get onlyOnMain => false;
|
||||
|
||||
@override
|
||||
final bool onlyOnSdk;
|
||||
|
||||
@override
|
||||
bool get notOnSdk => !onlyOnSdk;
|
||||
|
||||
// TODO(joshualitt): We currently special case the SDK both because it is not
|
||||
// trivial to build it in the same fashion as other modules, and because it is
|
||||
// a special case in other build environments. Eventually, we should
|
||||
// standardize this a bit more and always build the SDK modularly, if we have
|
||||
// to build it.
|
||||
ModularAnalysisStep({this.onlyOnSdk = false});
|
||||
|
||||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
if (_options.verbose) print("\nstep: modular analysis on $module");
|
||||
Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
|
||||
Iterable<String> dillDependencies =
|
||||
transitiveDependencies.map((m) => '${toUri(m, dillId)}');
|
||||
List<String> dillDependencies = [];
|
||||
List<String> sources = [];
|
||||
List<String> extraArgs = [];
|
||||
if (!module.isSdk) {
|
||||
writePackageConfig(module, transitiveDependencies, root);
|
||||
String rootScheme = getRootScheme(module);
|
||||
sources = getSources(module);
|
||||
dillDependencies = transitiveDependencies
|
||||
.map((m) => '${toUri(m, dillSummaryId)}')
|
||||
.toList();
|
||||
extraArgs = [
|
||||
'--packages=${root.resolve('.packages')}',
|
||||
'--multi-root=$root',
|
||||
'--multi-root-scheme=$rootScheme',
|
||||
];
|
||||
}
|
||||
|
||||
List<String> args = [
|
||||
'--packages=${sdkRoot.toFilePath()}/.packages',
|
||||
_dart2jsScript,
|
||||
'--no-sound-null-safety',
|
||||
if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
|
||||
'${Flags.inputDill}=${toUri(module, dillId)}',
|
||||
// If we have sources, then we aren't building the SDK, otherwise we
|
||||
// assume we are building the sdk and pass in a full dill.
|
||||
if (sources.isNotEmpty)
|
||||
'${Flags.sources}=${sources.join(',')}'
|
||||
else
|
||||
'${Flags.inputDill}=${toUri(module, dillId)}',
|
||||
if (dillDependencies.isNotEmpty)
|
||||
'--dill-dependencies=${dillDependencies.join(',')}',
|
||||
'--out=${toUri(module, modularUpdatedDillId)}',
|
||||
'${Flags.writeModularAnalysis}=${toUri(module, modularDataId)}',
|
||||
for (String flag in flags) '--enable-experiment=$flag',
|
||||
...extraArgs
|
||||
];
|
||||
var result =
|
||||
await _runProcess(Platform.resolvedExecutable, args, root.toFilePath());
|
||||
|
@ -306,7 +361,7 @@ class ModularAnalysisStep implements IOModularStep {
|
|||
}
|
||||
}
|
||||
|
||||
class ConcatenateDillsStep implements IOModularStep {
|
||||
class ConcatenateDillsStep extends IOModularStep {
|
||||
final bool useModularAnalysis;
|
||||
|
||||
DataId get idForDill => useModularAnalysis ? modularUpdatedDillId : dillId;
|
||||
|
@ -368,7 +423,7 @@ class ConcatenateDillsStep implements IOModularStep {
|
|||
}
|
||||
|
||||
// Step that invokes the dart2js closed world computation.
|
||||
class ComputeClosedWorldStep implements IOModularStep {
|
||||
class ComputeClosedWorldStep extends IOModularStep {
|
||||
final bool useModularAnalysis;
|
||||
|
||||
ComputeClosedWorldStep({this.useModularAnalysis});
|
||||
|
@ -429,7 +484,7 @@ class ComputeClosedWorldStep implements IOModularStep {
|
|||
}
|
||||
|
||||
// Step that runs the dart2js modular analysis.
|
||||
class GlobalAnalysisStep implements IOModularStep {
|
||||
class GlobalAnalysisStep extends IOModularStep {
|
||||
@override
|
||||
List<DataId> get resultData => const [globalDataId];
|
||||
|
||||
|
@ -479,7 +534,7 @@ class GlobalAnalysisStep implements IOModularStep {
|
|||
// Step that invokes the dart2js code generation on the main module given the
|
||||
// results of the global analysis step and produces one shard of the codegen
|
||||
// output.
|
||||
class Dart2jsCodegenStep implements IOModularStep {
|
||||
class Dart2jsCodegenStep extends IOModularStep {
|
||||
final ShardDataId codeId;
|
||||
|
||||
Dart2jsCodegenStep(this.codeId);
|
||||
|
@ -531,7 +586,7 @@ class Dart2jsCodegenStep implements IOModularStep {
|
|||
|
||||
// Step that invokes the dart2js codegen enqueuer and emitter on the main module
|
||||
// given the results of the global analysis step and codegen shards.
|
||||
class Dart2jsEmissionStep implements IOModularStep {
|
||||
class Dart2jsEmissionStep extends IOModularStep {
|
||||
@override
|
||||
List<DataId> get resultData => const [jsId];
|
||||
|
||||
|
@ -583,7 +638,7 @@ class Dart2jsEmissionStep implements IOModularStep {
|
|||
}
|
||||
|
||||
/// Step that runs the output of dart2js in d8 and saves the output.
|
||||
class RunD8 implements IOModularStep {
|
||||
class RunD8 extends IOModularStep {
|
||||
@override
|
||||
List<DataId> get resultData => const [txtId];
|
||||
|
||||
|
|
|
@ -72,6 +72,12 @@ class SourceToSummaryDillStep implements IOModularStep {
|
|||
@override
|
||||
bool get onlyOnMain => false;
|
||||
|
||||
@override
|
||||
bool get onlyOnSdk => false;
|
||||
|
||||
@override
|
||||
bool get notOnSdk => false;
|
||||
|
||||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
|
@ -162,6 +168,12 @@ class DDCStep implements IOModularStep {
|
|||
@override
|
||||
bool get onlyOnMain => false;
|
||||
|
||||
@override
|
||||
bool get onlyOnSdk => false;
|
||||
|
||||
@override
|
||||
bool get notOnSdk => false;
|
||||
|
||||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
|
@ -244,6 +256,12 @@ class RunD8 implements IOModularStep {
|
|||
@override
|
||||
bool get onlyOnMain => true;
|
||||
|
||||
@override
|
||||
bool get onlyOnSdk => false;
|
||||
|
||||
@override
|
||||
bool get notOnSdk => false;
|
||||
|
||||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
|
|
|
@ -72,6 +72,12 @@ class SourceToSummaryDillStep implements IOModularStep {
|
|||
@override
|
||||
bool get onlyOnMain => false;
|
||||
|
||||
@override
|
||||
bool get onlyOnSdk => false;
|
||||
|
||||
@override
|
||||
bool get notOnSdk => false;
|
||||
|
||||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
|
@ -164,6 +170,12 @@ class DDCStep implements IOModularStep {
|
|||
@override
|
||||
bool get onlyOnMain => false;
|
||||
|
||||
@override
|
||||
bool get onlyOnSdk => false;
|
||||
|
||||
@override
|
||||
bool get notOnSdk => false;
|
||||
|
||||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
|
@ -248,6 +260,12 @@ class RunD8 implements IOModularStep {
|
|||
@override
|
||||
bool get onlyOnMain => true;
|
||||
|
||||
@override
|
||||
bool get onlyOnSdk => false;
|
||||
|
||||
@override
|
||||
bool get notOnSdk => false;
|
||||
|
||||
@override
|
||||
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
|
||||
List<String> flags) async {
|
||||
|
|
|
@ -172,7 +172,9 @@ Future<Component?> compile(
|
|||
bool verbose,
|
||||
FileSystem fileSystem,
|
||||
DiagnosticMessageHandler onDiagnostic,
|
||||
Uri input) async {
|
||||
List<Uri> inputs,
|
||||
bool isModularCompile) async {
|
||||
assert(inputs.length == 1 || isModularCompile);
|
||||
CompilerOptions options = state.options;
|
||||
options
|
||||
..onDiagnostic = onDiagnostic
|
||||
|
@ -181,7 +183,7 @@ Future<Component?> compile(
|
|||
|
||||
ProcessedOptions processedOpts = state.processedOpts;
|
||||
processedOpts.inputs.clear();
|
||||
processedOpts.inputs.add(input);
|
||||
processedOpts.inputs.addAll(inputs);
|
||||
processedOpts.clearFileSystemCache();
|
||||
|
||||
CompilerResult? compilerResult = await CompilerContext.runWithOptions(
|
||||
|
@ -189,9 +191,10 @@ Future<Component?> compile(
|
|||
CompilerResult compilerResult = await generateKernelInternal();
|
||||
Component? component = compilerResult.component;
|
||||
if (component == null) return null;
|
||||
if (component.mainMethod == null) {
|
||||
if (component.mainMethod == null && !isModularCompile) {
|
||||
context.options.report(
|
||||
messageMissingMain.withLocation(input, -1, 0), Severity.error);
|
||||
messageMissingMain.withLocation(inputs.single, -1, 0),
|
||||
Severity.error);
|
||||
return null;
|
||||
}
|
||||
return compilerResult;
|
||||
|
|
|
@ -42,12 +42,20 @@ class ModularStep {
|
|||
/// Whether this step is only executed on the main module.
|
||||
final bool onlyOnMain;
|
||||
|
||||
/// Whether this step is only exceuted on the SDK.
|
||||
final bool onlyOnSdk;
|
||||
|
||||
/// Whether this step is not executed on the SDK.
|
||||
final bool notOnSdk;
|
||||
|
||||
ModularStep(
|
||||
{this.needsSources: true,
|
||||
this.dependencyDataNeeded: const [],
|
||||
this.moduleDataNeeded: const [],
|
||||
this.resultData,
|
||||
this.onlyOnMain: false});
|
||||
this.onlyOnMain: false,
|
||||
this.onlyOnSdk: false,
|
||||
this.notOnSdk: false});
|
||||
|
||||
/// Notifies that the step was not executed, but cached instead.
|
||||
void notifyCached(Module module) {}
|
||||
|
@ -77,6 +85,11 @@ abstract class Pipeline<S extends ModularStep> {
|
|||
}
|
||||
|
||||
void _validate() {
|
||||
// Whether or not two steps run on mutually exclusive input data.
|
||||
bool areMutuallyExclusive(S a, S b) {
|
||||
return (a.onlyOnSdk && b.notOnSdk) || (b.onlyOnSdk && a.notOnSdk);
|
||||
}
|
||||
|
||||
// Ensure that steps consume only data that was produced by previous steps
|
||||
// or by the same step on a dependency.
|
||||
Map<DataId, S> previousKinds = {};
|
||||
|
@ -86,7 +99,8 @@ abstract class Pipeline<S extends ModularStep> {
|
|||
"'${step.runtimeType}' needs to declare what data it produces.");
|
||||
}
|
||||
for (var resultKind in step.resultData) {
|
||||
if (previousKinds.containsKey(resultKind)) {
|
||||
if (previousKinds.containsKey(resultKind) &&
|
||||
!areMutuallyExclusive(step, previousKinds[resultKind])) {
|
||||
_validationError("Cannot produce the same data on two modular steps."
|
||||
" '$resultKind' was previously produced by "
|
||||
"'${previousKinds[resultKind].runtimeType}' but "
|
||||
|
@ -140,7 +154,9 @@ abstract class Pipeline<S extends ModularStep> {
|
|||
deps.addAll(transitiveDependencies[dependency]);
|
||||
}
|
||||
|
||||
if (step.onlyOnMain && !module.isMain) return;
|
||||
if ((step.onlyOnMain && !module.isMain) ||
|
||||
(step.onlyOnSdk && !module.isSdk) ||
|
||||
(step.notOnSdk && module.isSdk)) return;
|
||||
// Include only requested data from transitive dependencies.
|
||||
Map<Module, Set<DataId>> visibleData = {};
|
||||
|
||||
|
|
|
@ -107,6 +107,8 @@ class SourceOnlyStep implements IOModularStep {
|
|||
List<DataId> get moduleDataNeeded => const [];
|
||||
List<DataId> get resultData => [resultId];
|
||||
bool get onlyOnMain => false;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
SourceOnlyStep(this.action, this.resultId, this.needsSources);
|
||||
|
||||
|
@ -137,6 +139,8 @@ class ModuleDataStep implements IOModularStep {
|
|||
final DataId resultId;
|
||||
final DataId inputId;
|
||||
bool get onlyOnMain => false;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
ModuleDataStep(this.action, this.inputId, this.resultId, bool requestInput)
|
||||
: moduleDataNeeded = requestInput ? [inputId] : [];
|
||||
|
@ -166,6 +170,8 @@ class TwoOutputStep implements IOModularStep {
|
|||
final DataId result2Id;
|
||||
final DataId inputId;
|
||||
bool get onlyOnMain => false;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
TwoOutputStep(
|
||||
this.action1, this.action2, this.inputId, this.result1Id, this.result2Id);
|
||||
|
@ -198,6 +204,8 @@ class LinkStep implements IOModularStep {
|
|||
final DataId depId;
|
||||
final DataId resultId;
|
||||
bool get onlyOnMain => false;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
LinkStep(this.action, this.inputId, this.depId, this.resultId,
|
||||
bool requestDependencies)
|
||||
|
@ -230,6 +238,8 @@ class MainOnlyStep implements IOModularStep {
|
|||
final DataId depId;
|
||||
final DataId resultId;
|
||||
bool get onlyOnMain => true;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
MainOnlyStep(this.action, this.inputId, this.depId, this.resultId,
|
||||
bool requestDependencies)
|
||||
|
|
|
@ -86,6 +86,8 @@ class SourceOnlyStep implements MemoryModularStep {
|
|||
List<DataId> get moduleDataNeeded => const [];
|
||||
List<DataId> get resultData => [resultId];
|
||||
bool get onlyOnMain => false;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
SourceOnlyStep(this.action, this.resultId, this.needsSources);
|
||||
|
||||
|
@ -114,6 +116,8 @@ class ModuleDataStep implements MemoryModularStep {
|
|||
final DataId resultId;
|
||||
final DataId inputId;
|
||||
bool get onlyOnMain => false;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
ModuleDataStep(this.action, this.inputId, this.resultId, bool requestInput)
|
||||
: moduleDataNeeded = requestInput ? [inputId] : [];
|
||||
|
@ -144,6 +148,8 @@ class TwoOutputStep implements MemoryModularStep {
|
|||
final DataId result2Id;
|
||||
final DataId inputId;
|
||||
bool get onlyOnMain => false;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
TwoOutputStep(
|
||||
this.action1, this.action2, this.inputId, this.result1Id, this.result2Id);
|
||||
|
@ -177,6 +183,8 @@ class LinkStep implements MemoryModularStep {
|
|||
final DataId resultId;
|
||||
List<DataId> get resultData => [resultId];
|
||||
bool get onlyOnMain => false;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
LinkStep(this.action, this.inputId, this.depId, this.resultId,
|
||||
bool requestDependencies)
|
||||
|
@ -208,6 +216,8 @@ class MainOnlyStep implements MemoryModularStep {
|
|||
final DataId resultId;
|
||||
List<DataId> get resultData => [resultId];
|
||||
bool get onlyOnMain => true;
|
||||
bool get onlyOnSdk => false;
|
||||
bool get notOnSdk => false;
|
||||
|
||||
MainOnlyStep(this.action, this.inputId, this.depId, this.resultId,
|
||||
bool requestDependencies)
|
||||
|
|
Loading…
Reference in a new issue