add --dart-defines option (#44083)
diff --git a/packages/flutter_tools/lib/src/aot.dart b/packages/flutter_tools/lib/src/aot.dart
index 71e1558..50be745 100644
--- a/packages/flutter_tools/lib/src/aot.dart
+++ b/packages/flutter_tools/lib/src/aot.dart
@@ -34,6 +34,7 @@
Iterable<DarwinArch> iosBuildArchs = defaultIOSArchs,
List<String> extraFrontEndOptions,
List<String> extraGenSnapshotOptions,
+ @required List<String> dartDefines,
}) async {
if (platform == null) {
throwToolExit('No AOT build platform specified');
@@ -78,6 +79,7 @@
trackWidgetCreation: false,
outputPath: outputPath,
extraFrontEndOptions: extraFrontEndOptions,
+ dartDefines: dartDefines,
);
if (kernelOut == null) {
throwToolExit('Compiler terminated unexpectedly.');
diff --git a/packages/flutter_tools/lib/src/base/build.dart b/packages/flutter_tools/lib/src/base/build.dart
index d0f1642..9a70a94 100644
--- a/packages/flutter_tools/lib/src/base/build.dart
+++ b/packages/flutter_tools/lib/src/base/build.dart
@@ -285,6 +285,7 @@
@required String packagesPath,
@required String outputPath,
@required bool trackWidgetCreation,
+ @required List<String> dartDefines,
List<String> extraFrontEndOptions = const <String>[],
}) async {
final FlutterProject flutterProject = FlutterProject.current();
@@ -315,6 +316,7 @@
aot: true,
buildMode: buildMode,
trackWidgetCreation: trackWidgetCreation,
+ dartDefines: dartDefines,
));
// Write path to frontend_server, since things need to be re-generated when that changes.
diff --git a/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart b/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart
index 36537c3..3613dad 100644
--- a/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart
+++ b/packages/flutter_tools/lib/src/build_runner/resident_web_runner.dart
@@ -46,6 +46,7 @@
@required FlutterProject flutterProject,
@required bool ipv6,
@required DebuggingOptions debuggingOptions,
+ @required List<String> dartDefines,
}) {
if (featureFlags.isWebIncrementalCompilerEnabled) {
return _ExperimentalResidentWebRunner(
@@ -55,6 +56,7 @@
debuggingOptions: debuggingOptions,
ipv6: ipv6,
stayResident: stayResident,
+ dartDefines: dartDefines,
);
}
return _DwdsResidentWebRunner(
@@ -64,6 +66,7 @@
debuggingOptions: debuggingOptions,
ipv6: ipv6,
stayResident: stayResident,
+ dartDefines: dartDefines,
);
}
}
@@ -77,6 +80,7 @@
@required bool ipv6,
@required DebuggingOptions debuggingOptions,
bool stayResident = true,
+ @required this.dartDefines,
}) : super(
<FlutterDevice>[],
target: target ?? fs.path.join('lib', 'main.dart'),
@@ -87,6 +91,7 @@
final FlutterDevice device;
final FlutterProject flutterProject;
+ final List<String> dartDefines;
DateTime firstBuildTime;
// Only the debug builds of the web support the service protocol.
@@ -348,6 +353,7 @@
@required bool ipv6,
@required DebuggingOptions debuggingOptions,
bool stayResident = true,
+ @required List<String> dartDefines,
}) : super(
device,
flutterProject: flutterProject,
@@ -355,6 +361,7 @@
debuggingOptions: debuggingOptions,
ipv6: ipv6,
stayResident: stayResident,
+ dartDefines: dartDefines,
);
@override
@@ -540,6 +547,7 @@
@required bool ipv6,
@required DebuggingOptions debuggingOptions,
bool stayResident = true,
+ @required List<String> dartDefines,
}) : super(
device,
flutterProject: flutterProject,
@@ -547,6 +555,7 @@
debuggingOptions: debuggingOptions,
ipv6: ipv6,
stayResident: stayResident,
+ dartDefines: dartDefines,
);
@override
@@ -594,6 +603,7 @@
hostname: debuggingOptions.hostname,
port: debuggingOptions.port,
skipDwds: device is WebServerDevice || !debuggingOptions.buildInfo.isDebug,
+ dartDefines: dartDefines,
);
// When connecting to a browser, update the message with a seemsSlow notification
// to handle the case where we fail to connect.
diff --git a/packages/flutter_tools/lib/src/build_runner/web_fs.dart b/packages/flutter_tools/lib/src/build_runner/web_fs.dart
index da25e08..688d2d3 100644
--- a/packages/flutter_tools/lib/src/build_runner/web_fs.dart
+++ b/packages/flutter_tools/lib/src/build_runner/web_fs.dart
@@ -81,6 +81,7 @@
@required bool initializePlatform,
@required String hostname,
@required String port,
+ @required List<String> dartDefines,
});
/// The dev filesystem responsible for building and serving web applications.
@@ -97,6 +98,7 @@
this._target,
this._buildInfo,
this._initializePlatform,
+ this._dartDefines,
);
/// The server uri.
@@ -111,6 +113,7 @@
final String _target;
final BuildInfo _buildInfo;
final bool _initializePlatform;
+ final List<String> _dartDefines;
StreamSubscription<void> _connectedApps;
static const String _kHostName = 'localhost';
@@ -146,7 +149,7 @@
/// Recompile the web application and return whether this was successful.
Future<bool> recompile() async {
if (!_useBuildRunner) {
- await buildWeb(_flutterProject, _target, _buildInfo, _initializePlatform);
+ await buildWeb(_flutterProject, _target, _buildInfo, _initializePlatform, _dartDefines);
return true;
}
_client.startBuild();
@@ -173,6 +176,7 @@
@required bool initializePlatform,
@required String hostname,
@required String port,
+ @required List<String> dartDefines,
}) async {
// workaround for https://github.com/flutter/flutter/issues/38290
if (!flutterProject.dartTool.existsSync()) {
@@ -302,7 +306,7 @@
handler = pipeline.addHandler(proxyHandler('http://localhost:$daemonAssetPort/web/'));
}
} else {
- await buildWeb(flutterProject, target, buildInfo, initializePlatform);
+ await buildWeb(flutterProject, target, buildInfo, initializePlatform, dartDefines);
firstBuildCompleter.complete(true);
}
@@ -325,6 +329,7 @@
target,
buildInfo,
initializePlatform,
+ dartDefines,
);
if (!await firstBuildCompleter.future) {
throw const BuildException();
diff --git a/packages/flutter_tools/lib/src/build_system/targets/dart.dart b/packages/flutter_tools/lib/src/build_system/targets/dart.dart
index 8f00e82..392cc34 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/dart.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/dart.dart
@@ -7,6 +7,7 @@
import '../../base/file_system.dart';
import '../../build_info.dart';
import '../../compile.dart';
+import '../../convert.dart';
import '../../globals.dart';
import '../../project.dart';
import '../build_system.dart';
@@ -50,6 +51,9 @@
/// If provided, must be used along with [kFileSystemScheme].
const String kFileSystemRoots = 'FileSystemRoots';
+/// Defines specified via the `--dart-define` command-line option.
+const String kDartDefines = 'DartDefines';
+
/// The define to control what iOS architectures are built for.
///
/// This is expected to be a comma-separated list of architectures. If not
@@ -208,6 +212,7 @@
extraFrontEndOptions: extraFrontEndOptions,
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
+ dartDefines: parseDartDefines(environment),
);
if (output == null || output.errorCount != 0) {
throw Exception('Errors during snapshot creation: $output');
@@ -357,3 +362,22 @@
AotElfRelease(),
];
}
+
+/// Dart defines are encoded inside [Environment] as a JSON array.
+List<String> parseDartDefines(Environment environment) {
+ if (!environment.defines.containsKey(kDartDefines)) {
+ return const <String>[];
+ }
+
+ final String dartDefinesJson = environment.defines[kDartDefines];
+ try {
+ final List<Object> parsedDefines = jsonDecode(dartDefinesJson);
+ return parsedDefines.cast<String>();
+ } on FormatException catch (_) {
+ throw Exception(
+ 'The value of -D$kDartDefines is not formatted correctly.\n'
+ 'The value must be a JSON-encoded list of strings but was:\n'
+ '$dartDefinesJson'
+ );
+ }
+}
diff --git a/packages/flutter_tools/lib/src/build_system/targets/web.dart b/packages/flutter_tools/lib/src/build_system/targets/web.dart
index 4c4946f..11b01ec 100644
--- a/packages/flutter_tools/lib/src/build_system/targets/web.dart
+++ b/packages/flutter_tools/lib/src/build_system/targets/web.dart
@@ -130,6 +130,7 @@
? PackageMap.globalGeneratedPackagesPath
: PackageMap.globalPackagesPath;
final File outputFile = environment.buildDir.childFile('main.dart.js');
+
final ProcessResult result = await processManager.run(<String>[
artifacts.getArtifactPath(Artifact.engineDartBinary),
artifacts.getArtifactPath(Artifact.dart2jsSnapshot),
@@ -147,6 +148,8 @@
'-Ddart.vm.profile=true'
else
'-Ddart.vm.product=true',
+ for (String dartDefine in parseDartDefines(environment))
+ '-D$dartDefine',
environment.buildDir.childFile('main.dart').path,
]);
if (result.exitCode != 0) {
diff --git a/packages/flutter_tools/lib/src/codegen.dart b/packages/flutter_tools/lib/src/codegen.dart
index bd66869..a85bd86 100644
--- a/packages/flutter_tools/lib/src/codegen.dart
+++ b/packages/flutter_tools/lib/src/codegen.dart
@@ -109,6 +109,7 @@
TargetModel targetModel = TargetModel.flutter,
String initializeFromDill,
String platformDill,
+ List<String> dartDefines,
}) async {
if (fileSystemRoots != null || fileSystemScheme != null || depFilePath != null || targetModel != null || sdkRoot != null || packagesPath != null) {
printTrace('fileSystemRoots, fileSystemScheme, depFilePath, targetModel,'
@@ -147,6 +148,7 @@
depFilePath: depFilePath,
targetModel: targetModel,
initializeFromDill: initializeFromDill,
+ dartDefines: dartDefines,
);
}
}
@@ -172,6 +174,7 @@
String initializeFromDill,
bool runCold = false,
TargetPlatform targetPlatform,
+ @required List<String> dartDefines,
}) async {
codeGenerator.updatePackages(flutterProject);
final ResidentCompiler residentCompiler = ResidentCompiler(
@@ -191,6 +194,7 @@
targetModel: TargetModel.flutter,
unsafePackageSerialization: unsafePackageSerialization,
initializeFromDill: initializeFromDill,
+ dartDefines: dartDefines,
);
if (runCold) {
return residentCompiler;
diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart
index d6aec17..b9f35b5 100644
--- a/packages/flutter_tools/lib/src/commands/attach.dart
+++ b/packages/flutter_tools/lib/src/commands/attach.dart
@@ -61,6 +61,7 @@
usesIpv6Flag();
usesFilesystemOptions(hide: !verboseHelp);
usesFuchsiaOptions(hide: !verboseHelp);
+ usesDartDefines();
argParser
..addOption(
'debug-port',
@@ -274,6 +275,7 @@
target: argResults['target'],
targetModel: TargetModel(argResults['target-model']),
buildMode: getBuildMode(),
+ dartDefines: dartDefines,
);
flutterDevice.observatoryUris = <Uri>[ observatoryUri ];
final List<FlutterDevice> flutterDevices = <FlutterDevice>[flutterDevice];
diff --git a/packages/flutter_tools/lib/src/commands/build_aot.dart b/packages/flutter_tools/lib/src/commands/build_aot.dart
index b69b1bc..92a8f86 100644
--- a/packages/flutter_tools/lib/src/commands/build_aot.dart
+++ b/packages/flutter_tools/lib/src/commands/build_aot.dart
@@ -18,6 +18,7 @@
usesTargetOption();
addBuildModeFlags();
usesPubOption();
+ usesDartDefines();
argParser
..addOption('output-dir', defaultsTo: getAotBuildDirectory())
..addOption('target-platform',
@@ -86,6 +87,7 @@
iosBuildArchs: argResults['ios-arch'].map<DarwinArch>(getIOSArchForName),
extraFrontEndOptions: argResults[FlutterOptions.kExtraFrontEndOptions],
extraGenSnapshotOptions: argResults[FlutterOptions.kExtraGenSnapshotOptions],
+ dartDefines: dartDefines,
);
return null;
}
diff --git a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
index 12d9f36..07e8199 100644
--- a/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
+++ b/packages/flutter_tools/lib/src/commands/build_ios_framework.dart
@@ -35,6 +35,7 @@
usesTargetOption();
usesFlavorOption();
usesPubOption();
+ usesDartDefines();
argParser
..addFlag('debug',
negatable: true,
@@ -294,6 +295,7 @@
quiet: true,
reportTimings: false,
iosBuildArchs: <DarwinArch>[DarwinArch.armv7, DarwinArch.arm64],
+ dartDefines: dartDefines,
);
const String appFrameworkName = 'App.framework';
diff --git a/packages/flutter_tools/lib/src/commands/build_web.dart b/packages/flutter_tools/lib/src/commands/build_web.dart
index e731150..60b5863 100644
--- a/packages/flutter_tools/lib/src/commands/build_web.dart
+++ b/packages/flutter_tools/lib/src/commands/build_web.dart
@@ -18,6 +18,7 @@
usesTargetOption();
usesPubOption();
addBuildModeFlags(excludeDebug: true);
+ usesDartDefines();
argParser.addFlag('web-initialize-platform',
defaultsTo: true,
negatable: true,
@@ -53,7 +54,13 @@
if (buildInfo.isDebug) {
throwToolExit('debug builds cannot be built directly for the web. Try using "flutter run"');
}
- await buildWeb(flutterProject, target, buildInfo, argResults['web-initialize-platform']);
+ await buildWeb(
+ flutterProject,
+ target,
+ buildInfo,
+ argResults['web-initialize-platform'],
+ dartDefines,
+ );
return null;
}
}
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index d37bfe0..fed2bd0 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -424,6 +424,7 @@
viewFilter: isolateFilter,
target: target,
buildMode: options.buildInfo.mode,
+ dartDefines: command?.dartDefines,
);
ResidentRunner runner;
@@ -436,6 +437,7 @@
debuggingOptions: options,
ipv6: ipv6,
stayResident: true,
+ dartDefines: command?.dartDefines,
);
} else if (enableHotReload) {
runner = HotRunner(
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index b410da2..6f10357 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -31,6 +31,7 @@
// Used by run and drive commands.
RunCommandBase({ bool verboseHelp = false }) {
addBuildModeFlags(defaultToRelease: false, verboseHelp: verboseHelp);
+ usesDartDefines();
usesFlavorOption();
argParser
..addFlag('trace-startup',
@@ -426,6 +427,7 @@
experimentalFlags: expFlags,
target: argResults['target'],
buildMode: getBuildMode(),
+ dartDefines: dartDefines,
),
];
// Only support "web mode" with a single web device due to resident runner
@@ -459,6 +461,7 @@
ipv6: ipv6,
debuggingOptions: _createDebuggingOptions(),
stayResident: stayResident,
+ dartDefines: dartDefines,
);
} else {
runner = ColdRunner(
diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart
index 4dfeba8..d31d1d0 100644
--- a/packages/flutter_tools/lib/src/compile.dart
+++ b/packages/flutter_tools/lib/src/compile.dart
@@ -288,6 +288,7 @@
String fileSystemScheme,
String initializeFromDill,
String platformDill,
+ @required List<String> dartDefines,
}) async {
final String frontendServer = artifacts.getArtifactPath(
Artifact.frontendServerSnapshotForEngineDartSdk
@@ -316,6 +317,8 @@
sdkRoot,
'--target=$targetModel',
'-Ddart.developer.causal_async_stacks=$causalAsyncStacks',
+ for (Object dartDefine in dartDefines)
+ '-D$dartDefine',
..._buildModeOptions(buildMode),
if (trackWidgetCreation) '--track-widget-creation',
if (!linkPlatformKernelIn) '--no-link-platform',
@@ -464,6 +467,7 @@
bool unsafePackageSerialization,
List<String> experimentalFlags,
String platformDill,
+ List<String> dartDefines,
}) = DefaultResidentCompiler;
@@ -524,8 +528,10 @@
this.unsafePackageSerialization,
this.experimentalFlags,
this.platformDill,
+ List<String> dartDefines,
}) : assert(sdkRoot != null),
_stdoutHandler = StdoutHandler(consumer: compilerMessageConsumer),
+ dartDefines = dartDefines ?? const <String>[],
// This is a URI, not a file path, so the forward slash is correct even on Windows.
sdkRoot = sdkRoot.endsWith('/') ? sdkRoot : '$sdkRoot/';
@@ -539,6 +545,7 @@
final String initializeFromDill;
final bool unsafePackageSerialization;
final List<String> experimentalFlags;
+ final List<String> dartDefines;
/// The path to the root of the Dart SDK used to compile.
///
@@ -594,9 +601,9 @@
if (_server == null) {
return _compile(
- _mapFilename(request.mainPath, packageUriMapper),
- request.outputPath,
- _mapFilename(request.packagesFilePath ?? packagesPath, /* packageUriMapper= */ null),
+ _mapFilename(request.mainPath, packageUriMapper),
+ request.outputPath,
+ _mapFilename(request.packagesFilePath ?? packagesPath, /* packageUriMapper= */ null),
);
}
@@ -648,6 +655,8 @@
'--incremental',
'--target=$targetModel',
'-Ddart.developer.causal_async_stacks=$causalAsyncStacks',
+ for (Object dartDefine in dartDefines)
+ '-D$dartDefine',
if (outputPath != null) ...<String>[
'--output-dill',
outputPath,
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart
index 0e465b7..9b3ebb6 100644
--- a/packages/flutter_tools/lib/src/resident_runner.dart
+++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -41,6 +41,7 @@
List<String> experimentalFlags,
ResidentCompiler generator,
@required BuildMode buildMode,
+ List<String> dartDefines,
}) : assert(trackWidgetCreation != null),
generator = generator ?? ResidentCompiler(
artifacts.getArtifactPath(
@@ -54,6 +55,7 @@
fileSystemScheme: fileSystemScheme,
targetModel: targetModel,
experimentalFlags: experimentalFlags,
+ dartDefines: dartDefines,
);
/// Create a [FlutterDevice] with optional code generation enabled.
@@ -69,6 +71,7 @@
TargetModel targetModel = TargetModel.flutter,
List<String> experimentalFlags,
ResidentCompiler generator,
+ List<String> dartDefines,
}) async {
ResidentCompiler generator;
final TargetPlatform targetPlatform = await device.targetPlatform;
@@ -86,12 +89,14 @@
targetModel: TargetModel.dartdevc,
experimentalFlags: experimentalFlags,
platformDill: artifacts.getArtifactPath(Artifact.webPlatformKernelDill, mode: buildMode),
+ dartDefines: dartDefines,
);
} else if (flutterProject.hasBuilders) {
generator = await CodeGeneratingResidentCompiler.create(
targetPlatform: targetPlatform,
buildMode: buildMode,
flutterProject: flutterProject,
+ dartDefines: dartDefines,
);
} else {
generator = ResidentCompiler(
@@ -106,6 +111,7 @@
fileSystemScheme: fileSystemScheme,
targetModel: targetModel,
experimentalFlags: experimentalFlags,
+ dartDefines: dartDefines,
);
}
return FlutterDevice(
@@ -119,6 +125,7 @@
targetPlatform: targetPlatform,
generator: generator,
buildMode: buildMode,
+ dartDefines: dartDefines,
);
}
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index cdbad2d..81ec070 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -269,6 +269,20 @@
valueHelp: 'x.y.z');
}
+ void usesDartDefines() {
+ argParser.addMultiOption(
+ 'dart-define',
+ help: 'Passed to the Dart compiler building this application as a -D flag.\n'
+ 'Values supported by this option are compiler implementation specific.\n'
+ 'Multiple defines can be passed by repeating --dart-define multiple times.',
+ valueHelp: 'FOO=bar',
+ hide: true,
+ );
+ }
+
+ /// The values passed via the `--dart-define` option.
+ List<String> get dartDefines => argResults['dart-define'];
+
void usesIsolateFilterOption({ @required bool hide }) {
argParser.addOption('isolate-filter',
defaultsTo: null,
diff --git a/packages/flutter_tools/lib/src/test/test_compiler.dart b/packages/flutter_tools/lib/src/test/test_compiler.dart
index 8bb3a65..dd37a5f 100644
--- a/packages/flutter_tools/lib/src/test/test_compiler.dart
+++ b/packages/flutter_tools/lib/src/test/test_compiler.dart
@@ -103,6 +103,7 @@
// We already ran codegen once at the start, we only need to
// configure builders.
runCold: true,
+ dartDefines: const <String>[],
);
}
return ResidentCompiler(
@@ -113,6 +114,7 @@
compilerMessageConsumer: _reportCompilerMessage,
initializeFromDill: testFilePath,
unsafePackageSerialization: false,
+ dartDefines: const <String>[],
);
}
diff --git a/packages/flutter_tools/lib/src/web/compile.dart b/packages/flutter_tools/lib/src/web/compile.dart
index 51413ad..f0d9524 100644
--- a/packages/flutter_tools/lib/src/web/compile.dart
+++ b/packages/flutter_tools/lib/src/web/compile.dart
@@ -12,6 +12,7 @@
import '../build_system/build_system.dart';
import '../build_system/targets/dart.dart';
import '../build_system/targets/web.dart';
+import '../convert.dart';
import '../globals.dart';
import '../platform_plugins.dart';
import '../plugins.dart';
@@ -21,7 +22,13 @@
/// The [WebCompilationProxy] instance.
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
-Future<void> buildWeb(FlutterProject flutterProject, String target, BuildInfo buildInfo, bool initializePlatform) async {
+Future<void> buildWeb(
+ FlutterProject flutterProject,
+ String target,
+ BuildInfo buildInfo,
+ bool initializePlatform,
+ List<String> dartDefines,
+) async {
if (!flutterProject.web.existsSync()) {
throwToolExit('Missing index.html.');
}
@@ -42,6 +49,7 @@
kTargetFile: target,
kInitializePlatform: initializePlatform.toString(),
kHasWebPlugins: hasWebPlugins.toString(),
+ kDartDefines: jsonEncode(dartDefines),
},
));
if (!result.success) {
diff --git a/packages/flutter_tools/lib/src/web/web_runner.dart b/packages/flutter_tools/lib/src/web/web_runner.dart
index 09402a3..ad41c5e 100644
--- a/packages/flutter_tools/lib/src/web/web_runner.dart
+++ b/packages/flutter_tools/lib/src/web/web_runner.dart
@@ -23,5 +23,6 @@
@required FlutterProject flutterProject,
@required bool ipv6,
@required DebuggingOptions debuggingOptions,
+ @required List<String> dartDefines,
});
}