1// Copyright (c) 2017, 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#include "bin/main_options.h"
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include "bin/dartdev_isolate.h"
12#include "bin/error_exit.h"
13#include "bin/file_system_watcher.h"
14#include "bin/options.h"
15#include "bin/platform.h"
16#include "bin/utils.h"
17#include "platform/syslog.h"
18#if !defined(DART_IO_SECURE_SOCKET_DISABLED)
19#include "bin/security_context.h"
20#endif // !defined(DART_IO_SECURE_SOCKET_DISABLED)
21#include "bin/socket.h"
22#include "include/dart_api.h"
23#include "platform/assert.h"
24#include "platform/globals.h"
25#include "platform/hashmap.h"
26
27namespace dart {
28namespace bin {
29
30// These strings must match the enum SnapshotKind in main_options.h.
31static const char* const kSnapshotKindNames[] = {
32 "none",
33 "kernel",
34 "app-jit",
35 nullptr,
36};
37
38// These strings must match the enum VerbosityLevel in main_options.h.
39static const char* const kVerbosityLevelNames[] = {
40 "error", "warning", "info", "all", nullptr,
41};
42
43SnapshotKind Options::gen_snapshot_kind_ = kNone;
44VerbosityLevel Options::verbosity_ = kAll;
45bool Options::enable_vm_service_ = false;
46
47#define OPTION_FIELD(variable) Options::variable##_
48
49#define STRING_OPTION_DEFINITION(name, variable) \
50 const char* OPTION_FIELD(variable) = nullptr; \
51 DEFINE_STRING_OPTION(name, OPTION_FIELD(variable))
52STRING_OPTIONS_LIST(STRING_OPTION_DEFINITION)
53#undef STRING_OPTION_DEFINITION
54
55#define BOOL_OPTION_DEFINITION(name, variable) \
56 bool OPTION_FIELD(variable) = false; \
57 DEFINE_BOOL_OPTION(name, OPTION_FIELD(variable))
58BOOL_OPTIONS_LIST(BOOL_OPTION_DEFINITION)
59#if defined(DEBUG)
60DEBUG_BOOL_OPTIONS_LIST(BOOL_OPTION_DEFINITION)
61#endif
62#undef BOOL_OPTION_DEFINITION
63
64#define SHORT_BOOL_OPTION_DEFINITION(short_name, long_name, variable) \
65 bool OPTION_FIELD(variable) = false; \
66 DEFINE_BOOL_OPTION_SHORT(short_name, long_name, OPTION_FIELD(variable))
67SHORT_BOOL_OPTIONS_LIST(SHORT_BOOL_OPTION_DEFINITION)
68#undef SHORT_BOOL_OPTION_DEFINITION
69
70#define ENUM_OPTION_DEFINITION(name, type, variable) \
71 DEFINE_ENUM_OPTION(name, type, OPTION_FIELD(variable))
72ENUM_OPTIONS_LIST(ENUM_OPTION_DEFINITION)
73#undef ENUM_OPTION_DEFINITION
74
75#define CB_OPTION_DEFINITION(callback) \
76 static bool callback##Helper(const char* arg, CommandLineOptions* o) { \
77 return Options::callback(arg, o); \
78 } \
79 DEFINE_CB_OPTION(callback##Helper)
80CB_OPTIONS_LIST(CB_OPTION_DEFINITION)
81#undef CB_OPTION_DEFINITION
82
83#if !defined(DART_PRECOMPILED_RUNTIME)
84DFE* Options::dfe_ = nullptr;
85
86DEFINE_STRING_OPTION_CB(dfe, { Options::dfe()->set_frontend_filename(value); });
87#endif // !defined(DART_PRECOMPILED_RUNTIME)
88
89static void hot_reload_test_mode_callback(CommandLineOptions* vm_options) {
90 // Identity reload.
91 vm_options->AddArgument(argument: "--identity_reload");
92 // Start reloading quickly.
93 vm_options->AddArgument(argument: "--reload_every=4");
94 // Reload from optimized and unoptimized code.
95 vm_options->AddArgument(argument: "--reload_every_optimized=false");
96 // Reload less frequently as time goes on.
97 vm_options->AddArgument(argument: "--reload_every_back_off");
98 // Ensure that every isolate has reloaded once before exiting.
99 vm_options->AddArgument(argument: "--check_reloaded");
100#if !defined(DART_PRECOMPILED_RUNTIME)
101 Options::dfe()->set_use_incremental_compiler(true);
102#endif // !defined(DART_PRECOMPILED_RUNTIME)
103}
104
105DEFINE_BOOL_OPTION_CB(hot_reload_test_mode, hot_reload_test_mode_callback);
106
107static void hot_reload_rollback_test_mode_callback(
108 CommandLineOptions* vm_options) {
109 // Identity reload.
110 vm_options->AddArgument(argument: "--identity_reload");
111 // Start reloading quickly.
112 vm_options->AddArgument(argument: "--reload_every=4");
113 // Reload from optimized and unoptimized code.
114 vm_options->AddArgument(argument: "--reload_every_optimized=false");
115 // Reload less frequently as time goes on.
116 vm_options->AddArgument(argument: "--reload_every_back_off");
117 // Ensure that every isolate has reloaded once before exiting.
118 vm_options->AddArgument(argument: "--check_reloaded");
119 // Force all reloads to fail and execute the rollback code.
120 vm_options->AddArgument(argument: "--reload_force_rollback");
121#if !defined(DART_PRECOMPILED_RUNTIME)
122 Options::dfe()->set_use_incremental_compiler(true);
123#endif // !defined(DART_PRECOMPILED_RUNTIME)
124}
125
126DEFINE_BOOL_OPTION_CB(hot_reload_rollback_test_mode,
127 hot_reload_rollback_test_mode_callback);
128
129void Options::PrintVersion() {
130 Syslog::Print(format: "Dart SDK version: %s\n", Dart_VersionString());
131}
132
133// clang-format off
134void Options::PrintUsage() {
135 Syslog::Print(
136 format: "Usage: dart [<vm-flags>] <dart-script-file> [<script-arguments>]\n"
137 "\n"
138 "Executes the Dart script <dart-script-file> with "
139 "the given list of <script-arguments>.\n"
140 "\n");
141 if (!Options::verbose_option()) {
142 Syslog::Print(
143format: "Common VM flags:\n"
144#if !defined(PRODUCT)
145"--enable-asserts\n"
146" Enable assert statements.\n"
147#endif // !defined(PRODUCT)
148"--help or -h\n"
149" Display this message (add -v or --verbose for information about\n"
150" all VM options).\n"
151"--packages=<path>\n"
152" Where to find a package spec file.\n"
153"--define=<key>=<value> or -D<key>=<value>\n"
154" Define an environment declaration. To specify multiple declarations,\n"
155" use multiple instances of this option.\n"
156#if !defined(PRODUCT)
157"--observe[=<port>[/<bind-address>]]\n"
158" The observe flag is a convenience flag used to run a program with a\n"
159" set of options which are often useful for debugging under Observatory.\n"
160" These options are currently:\n"
161" --enable-vm-service[=<port>[/<bind-address>]]\n"
162" --serve-devtools\n"
163" --pause-isolates-on-exit\n"
164" --pause-isolates-on-unhandled-exceptions\n"
165" --warn-on-pause-with-no-debugger\n"
166" --timeline-streams=\"Compiler, Dart, GC\"\n"
167" This set is subject to change.\n"
168" Please see these options (--help --verbose) for further documentation.\n"
169"--write-service-info=<file_uri>\n"
170" Outputs information necessary to connect to the VM service to the\n"
171" specified file in JSON format. Useful for clients which are unable to\n"
172" listen to stdout for the Dart VM service listening message.\n"
173#endif // !defined(PRODUCT)
174"--snapshot-kind=<snapshot_kind>\n"
175"--snapshot=<file_name>\n"
176" These snapshot options are used to generate a snapshot of the loaded\n"
177" Dart script:\n"
178" <snapshot-kind> controls the kind of snapshot, it could be\n"
179" kernel(default) or app-jit\n"
180" <file_name> specifies the file into which the snapshot is written\n"
181"--version\n"
182" Print the SDK version.\n");
183 } else {
184 Syslog::Print(
185format: "Supported options:\n"
186#if !defined(PRODUCT)
187"--enable-asserts\n"
188" Enable assert statements.\n"
189#endif // !defined(PRODUCT)
190"--help or -h\n"
191" Display this message (add -v or --verbose for information about\n"
192" all VM options).\n"
193"--packages=<path>\n"
194" Where to find a package spec file.\n"
195"--define=<key>=<value> or -D<key>=<value>\n"
196" Define an environment declaration. To specify multiple declarations,\n"
197" use multiple instances of this option.\n"
198#if !defined(PRODUCT)
199"--observe[=<port>[/<bind-address>]]\n"
200" The observe flag is a convenience flag used to run a program with a\n"
201" set of options which are often useful for debugging under Observatory.\n"
202" These options are currently:\n"
203" --enable-vm-service[=<port>[/<bind-address>]]\n"
204" --serve-devtools\n"
205" --pause-isolates-on-exit\n"
206" --pause-isolates-on-unhandled-exceptions\n"
207" --warn-on-pause-with-no-debugger\n"
208" --timeline-streams=\"Compiler, Dart, GC\"\n"
209" This set is subject to change.\n"
210" Please see these options for further documentation.\n"
211#endif // !defined(PRODUCT)
212"--version\n"
213" Print the VM version.\n"
214"\n"
215"--trace-loading\n"
216" enables tracing of library and script loading\n"
217"\n"
218#if !defined(PRODUCT)
219"--enable-vm-service[=<port>[/<bind-address>]]\n"
220" Enables the VM service and listens on specified port for connections\n"
221" (default port number is 8181, default bind address is localhost).\n"
222"\n"
223"--disable-service-auth-codes\n"
224" Disables the requirement for an authentication code to communicate with\n"
225" the VM service. Authentication codes help protect against CSRF attacks,\n"
226" so it is not recommended to disable them unless behind a firewall on a\n"
227" secure device.\n"
228"\n"
229"--enable-service-port-fallback\n"
230" When the VM service is told to bind to a particular port, fallback to 0 if\n"
231" it fails to bind instead of failing to start.\n"
232"\n"
233#endif // !defined(PRODUCT)
234"--root-certs-file=<path>\n"
235" The path to a file containing the trusted root certificates to use for\n"
236" secure socket connections.\n"
237"--root-certs-cache=<path>\n"
238" The path to a cache directory containing the trusted root certificates to\n"
239" use for secure socket connections.\n"
240#if defined(DART_HOST_OS_LINUX) || \
241 defined(DART_HOST_OS_ANDROID) || \
242 defined(DART_HOST_OS_FUCHSIA)
243"--namespace=<path>\n"
244" The path to a directory that dart:io calls will treat as the root of the\n"
245" filesystem.\n"
246#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
247"\n"
248"The following options are only used for VM development and may\n"
249"be changed in any future version:\n");
250 const char* print_flags = "--print_flags";
251 char* error = Dart_SetVMFlags(argc: 1, argv: &print_flags);
252 ASSERT(error == nullptr);
253 }
254}
255// clang-format on
256
257dart::SimpleHashMap* Options::environment_ = nullptr;
258bool Options::ProcessEnvironmentOption(const char* arg,
259 CommandLineOptions* vm_options) {
260 return OptionProcessor::ProcessEnvironmentOption(arg, vm_options,
261 environment: &Options::environment_);
262}
263
264void Options::DestroyEnvironment() {
265 if (environment_ != nullptr) {
266 for (SimpleHashMap::Entry* p = environment_->Start(); p != nullptr;
267 p = environment_->Next(p)) {
268 free(ptr: p->key);
269 free(ptr: p->value);
270 }
271 delete environment_;
272 environment_ = nullptr;
273 }
274}
275
276bool Options::ExtractPortAndAddress(const char* option_value,
277 int* out_port,
278 const char** out_ip,
279 int default_port,
280 const char* default_ip) {
281 // [option_value] has to be one of the following formats:
282 // - ""
283 // - ":8181"
284 // - "=8181"
285 // - ":8181/192.168.0.1"
286 // - "=8181/192.168.0.1"
287 // - "=8181/::1"
288
289 if (*option_value == '\0') {
290 *out_ip = default_ip;
291 *out_port = default_port;
292 return true;
293 }
294
295 if ((*option_value != '=') && (*option_value != ':')) {
296 return false;
297 }
298
299 int port = atoi(nptr: option_value + 1);
300 const char* slash = strstr(s1: option_value, s2: "/");
301 if (slash == nullptr) {
302 *out_ip = default_ip;
303 *out_port = port;
304 return true;
305 }
306
307 *out_ip = slash + 1;
308 *out_port = port;
309 return true;
310}
311
312// Returns true if arg starts with the characters "--" followed by option, but
313// all '_' in the option name are treated as '-'.
314static bool IsOption(const char* arg, const char* option) {
315 if (arg[0] != '-' || arg[1] != '-') {
316 // Special case first two characters to avoid recognizing __flag.
317 return false;
318 }
319 for (int i = 0; option[i] != '\0'; i++) {
320 auto c = arg[i + 2];
321 if (c == '\0') {
322 // Not long enough.
323 return false;
324 }
325 if ((c == '_' ? '-' : c) != option[i]) {
326 return false;
327 }
328 }
329 return true;
330}
331
332const char* Options::vm_service_server_ip_ = DEFAULT_VM_SERVICE_SERVER_IP;
333int Options::vm_service_server_port_ = INVALID_VM_SERVICE_SERVER_PORT;
334bool Options::ProcessEnableVmServiceOption(const char* arg,
335 CommandLineOptions* vm_options) {
336#if !defined(PRODUCT)
337 const char* value =
338 OptionProcessor::ProcessOption(option: arg, name: "--enable-vm-service");
339 if (value == nullptr) {
340 return false;
341 }
342 if (!ExtractPortAndAddress(
343 option_value: value, out_port: &vm_service_server_port_, out_ip: &vm_service_server_ip_,
344 default_port: DEFAULT_VM_SERVICE_SERVER_PORT, default_ip: DEFAULT_VM_SERVICE_SERVER_IP)) {
345 Syslog::PrintErr(
346 format: "unrecognized --enable-vm-service option syntax. "
347 "Use --enable-vm-service[=<port number>[/<bind address>]]\n");
348 return false;
349 }
350#if !defined(DART_PRECOMPILED_RUNTIME)
351 dfe()->set_use_incremental_compiler(true);
352#endif // !defined(DART_PRECOMPILED_RUNTIME)
353 enable_vm_service_ = true;
354 return true;
355#else
356 // VM service not available in product mode.
357 return false;
358#endif // !defined(PRODUCT)
359}
360
361bool Options::ProcessObserveOption(const char* arg,
362 CommandLineOptions* vm_options) {
363#if !defined(PRODUCT)
364 const char* value = OptionProcessor::ProcessOption(option: arg, name: "--observe");
365 if (value == nullptr) {
366 return false;
367 }
368 if (!ExtractPortAndAddress(
369 option_value: value, out_port: &vm_service_server_port_, out_ip: &vm_service_server_ip_,
370 default_port: DEFAULT_VM_SERVICE_SERVER_PORT, default_ip: DEFAULT_VM_SERVICE_SERVER_IP)) {
371 Syslog::PrintErr(
372 format: "unrecognized --observe option syntax. "
373 "Use --observe[=<port number>[/<bind address>]]\n");
374 return false;
375 }
376
377 // These options should also be documented in the help message.
378 vm_options->AddArgument(argument: "--pause-isolates-on-exit");
379 vm_options->AddArgument(argument: "--pause-isolates-on-unhandled-exceptions");
380 vm_options->AddArgument(argument: "--profiler");
381 vm_options->AddArgument(argument: "--warn-on-pause-with-no-debugger");
382 vm_options->AddArgument(argument: "--timeline-streams=\"Compiler,Dart,GC\"");
383#if !defined(DART_PRECOMPILED_RUNTIME)
384 dfe()->set_use_incremental_compiler(true);
385#endif // !defined(DART_PRECOMPILED_RUNTIME)
386 enable_vm_service_ = true;
387 return true;
388#else
389 // VM service not available in product mode.
390 return false;
391#endif // !defined(PRODUCT)
392}
393
394// Explicitly handle VM flags that can be parsed by DartDev's run command.
395bool Options::ProcessVMDebuggingOptions(const char* arg,
396 CommandLineOptions* vm_options) {
397#define IS_DEBUG_OPTION(name, arg) \
398 if (strncmp(name, arg, strlen(name)) == 0) { \
399 vm_options->AddArgument(arg); \
400 return true; \
401 }
402
403// This is an exhaustive set of VM flags that are accepted by 'dart run'. Flags
404// defined in main_options.h do not need to be handled here as they already
405// have handlers generated.
406//
407// NOTE: When updating this list of VM flags, be sure to make the corresponding
408// changes in pkg/dartdev/lib/src/commands/run.dart.
409#define HANDLE_DARTDEV_VM_DEBUG_OPTIONS(V, arg) \
410 V("--enable-asserts", arg) \
411 V("--pause-isolates-on-exit", arg) \
412 V("--no-pause-isolates-on-exit", arg) \
413 V("--pause-isolates-on-start", arg) \
414 V("--no-pause-isolates-on-start", arg) \
415 V("--pause-isolates-on-unhandled-exception", arg) \
416 V("--no-pause-isolates-on-unhandled-exception", arg) \
417 V("--warn-on-pause-with-no-debugger", arg) \
418 V("--no-warn-on-pause-with-no-debugger", arg) \
419 V("--timeline-streams", arg) \
420 V("--timeline-recorder", arg) \
421 V("--enable-experiment", arg)
422 HANDLE_DARTDEV_VM_DEBUG_OPTIONS(IS_DEBUG_OPTION, arg);
423
424#undef IS_DEBUG_OPTION
425#undef HANDLE_DARTDEV_VM_DEBUG_OPTIONS
426
427 return false;
428}
429
430bool Options::ParseArguments(int argc,
431 char** argv,
432 bool vm_run_app_snapshot,
433 CommandLineOptions* vm_options,
434 char** script_name,
435 CommandLineOptions* dart_options,
436 bool* print_flags_seen,
437 bool* verbose_debug_seen) {
438 // Store the executable name.
439 Platform::SetExecutableName(argv[0]);
440
441 // Start the rest after the executable name.
442 int i = 1;
443
444 CommandLineOptions temp_vm_options(vm_options->max_count());
445
446 bool enable_dartdev_analytics = false;
447 bool disable_dartdev_analytics = false;
448 bool serve_devtools = true;
449 char* packages_argument = nullptr;
450
451 // Parse out the vm options.
452 while (i < argc) {
453 bool skipVmOption = false;
454 if (!OptionProcessor::TryProcess(option: argv[i], options: &temp_vm_options)) {
455 // Check if this flag is a potentially valid VM flag.
456 if (!OptionProcessor::IsValidFlag(name: argv[i])) {
457 break;
458 }
459 // The following flags are processed as DartDev flags and are not to
460 // be treated as if they are VM flags.
461 if (IsOption(arg: argv[i], option: "print-flags")) {
462 *print_flags_seen = true;
463 } else if (IsOption(arg: argv[i], option: "verbose-debug")) {
464 *verbose_debug_seen = true;
465 } else if (IsOption(arg: argv[i], option: "enable-analytics")) {
466 enable_dartdev_analytics = true;
467 skipVmOption = true;
468 } else if (IsOption(arg: argv[i], option: "disable-analytics")) {
469 disable_dartdev_analytics = true;
470 skipVmOption = true;
471 } else if (IsOption(arg: argv[i], option: "disable-telemetry")) {
472 disable_dartdev_analytics = true;
473 skipVmOption = true;
474 } else if (IsOption(arg: argv[i], option: "no-analytics")) {
475 // Just add this option even if we don't go to dartdev.
476 // It is irrelevant for the vm.
477 dart_options->AddArgument(argument: "--no-analytics");
478 skipVmOption = true;
479 } else if (IsOption(arg: argv[i], option: "serve-devtools")) {
480 serve_devtools = true;
481 skipVmOption = true;
482 } else if (IsOption(arg: argv[i], option: "no-serve-devtools")) {
483 serve_devtools = false;
484 skipVmOption = true;
485 } else if (IsOption(arg: argv[i], option: "dds")) {
486 // This flag is set by default in dartdev, so we ignore it. --no-dds is
487 // a VM flag as disabling DDS changes how we configure the VM service,
488 // so we don't need to handle that case here.
489 skipVmOption = true;
490 } else if (IsOption(arg: argv[i], option: "serve-observatory")) {
491 // This flag is currently set by default in vmservice_io.dart, so we
492 // ignore it. --no-serve-observatory is a VM flag so we don't need to
493 // handle that case here.
494 skipVmOption = true;
495 }
496 if (!skipVmOption) {
497 temp_vm_options.AddArgument(argument: argv[i]);
498 }
499 }
500 if (IsOption(arg: argv[i], option: "packages")) {
501 packages_argument = argv[i];
502 }
503 i++;
504 }
505
506#if !defined(DART_PRECOMPILED_RUNTIME)
507 Options::dfe()->set_use_dfe();
508#else
509 // DartDev is not supported in AOT.
510 Options::disable_dart_dev_ = true;
511#endif // !defined(DART_PRECOMPILED_RUNTIME)
512 if (Options::deterministic()) {
513 // Both an embedder and VM flag.
514 temp_vm_options.AddArgument(argument: "--deterministic");
515 }
516
517 Socket::set_short_socket_read(Options::short_socket_read());
518 Socket::set_short_socket_write(Options::short_socket_write());
519#if !defined(DART_IO_SECURE_SOCKET_DISABLED)
520 SSLCertContext::set_root_certs_file(Options::root_certs_file());
521 SSLCertContext::set_root_certs_cache(Options::root_certs_cache());
522 SSLCertContext::set_long_ssl_cert_evaluation(
523 Options::long_ssl_cert_evaluation());
524 SSLCertContext::set_bypass_trusting_system_roots(
525 Options::bypass_trusting_system_roots());
526#endif // !defined(DART_IO_SECURE_SOCKET_DISABLED)
527
528 FileSystemWatcher::set_delayed_filewatch_callback(
529 Options::delayed_filewatch_callback());
530
531 // The arguments to the VM are at positions 1 through i-1 in argv.
532 Platform::SetExecutableArguments(script_index: i, argv);
533
534 bool implicitly_use_dart_dev = false;
535 bool run_script = false;
536 // Get the script name.
537 if (i < argc) {
538#if !defined(DART_PRECOMPILED_RUNTIME)
539 // If the script name is a valid file or a URL, we'll run the script
540 // directly. Otherwise, this might be a DartDev command and we need to try
541 // to find the DartDev snapshot so we can forward the command and its
542 // arguments.
543 bool is_potential_file_path = !DartDevIsolate::ShouldParseCommand(argv[i]);
544#else
545 bool is_potential_file_path = true;
546#endif // !defined(DART_PRECOMPILED_RUNTIME)
547 if (Options::disable_dart_dev() ||
548 (Options::snapshot_filename() != nullptr) ||
549 (is_potential_file_path && !enable_vm_service_)) {
550 *script_name = Utils::StrDup(s: argv[i]);
551 run_script = true;
552 i++;
553 }
554#if !defined(DART_PRECOMPILED_RUNTIME)
555 else { // NOLINT
556 DartDevIsolate::set_should_run_dart_dev(true);
557 }
558 if (!Options::disable_dart_dev() && enable_vm_service_) {
559 // Handle the special case where the user is running a Dart program
560 // without using a DartDev command and wants to use the VM service. Here
561 // we'll run the program using DartDev as it's used to spawn a DDS
562 // instance.
563 if (is_potential_file_path) {
564 implicitly_use_dart_dev = true;
565 }
566 }
567#endif // !defined(DART_PRECOMPILED_RUNTIME)
568 }
569#if !defined(DART_PRECOMPILED_RUNTIME)
570 else if (!Options::disable_dart_dev()) { // NOLINT
571 // Handles following invocation arguments:
572 // - dart help
573 // - dart --help
574 // - dart
575 if (((Options::help_option() && !Options::verbose_option()) ||
576 (argc == 1))) {
577 DartDevIsolate::set_should_run_dart_dev(true);
578 // Let DartDev handle the default help message.
579 dart_options->AddArgument("help");
580 return true;
581 }
582 // Handles cases where only analytics flags are provided. We need to start
583 // the DartDev isolate to set this state.
584 else if (enable_dartdev_analytics || disable_dartdev_analytics) { // NOLINT
585 // The analytics flags are a special case as we don't have a target script
586 // or DartDev command but we still want to launch DartDev.
587 DartDevIsolate::set_should_run_dart_dev(true);
588 dart_options->AddArgument(enable_dartdev_analytics
589 ? "--enable-analytics"
590 : "--disable-analytics");
591 return true;
592 }
593 // Let the VM handle '--version' and '--help --disable-dart-dev'.
594 // Otherwise, we'll launch the DartDev isolate to print its help message
595 // and set an error exit code.
596 else if (!Options::help_option() && !Options::version_option()) { // NOLINT
597 DartDevIsolate::PrintUsageErrorOnRun();
598 return true;
599 }
600 return false;
601 }
602#endif // !defined(DART_PRECOMPILED_RUNTIME)
603 // Handle argument parsing errors.
604 else { // NOLINT
605 return false;
606 }
607 USE(enable_dartdev_analytics);
608 USE(disable_dartdev_analytics);
609 USE(packages_argument);
610
611 const char** vm_argv = temp_vm_options.arguments();
612 int vm_argc = temp_vm_options.count();
613
614 vm_options->AddArguments(argv: vm_argv, argc: vm_argc);
615
616 // If running with dartdev, attempt to parse VM flags which are part of the
617 // dartdev command (e.g., --enable-vm-service, --observe, etc).
618 if (!run_script) {
619 int tmp_i = i;
620 // We only run the CLI implicitly if the service is enabled and the user
621 // didn't run with the 'run' command. If they did provide a command, we need
622 // to skip it here to continue parsing VM flags.
623 if (!implicitly_use_dart_dev) {
624 tmp_i++;
625 }
626 while (tmp_i < argc) {
627 // Check if this flag is a potentially valid VM flag. If not, we've likely
628 // hit a script name and are done parsing VM flags.
629 if (!OptionProcessor::IsValidFlag(name: argv[tmp_i]) &&
630 !OptionProcessor::IsValidShortFlag(name: argv[tmp_i])) {
631 break;
632 }
633 OptionProcessor::TryProcess(option: argv[tmp_i], options: vm_options);
634 tmp_i++;
635 }
636 }
637 bool first_option = true;
638 // Parse out options to be passed to dart main.
639 while (i < argc) {
640 if (implicitly_use_dart_dev && first_option) {
641 // Special case where user enables VM service without using a dartdev
642 // run command. If 'run' is provided, it will be the first argument
643 // processed in this loop.
644 dart_options->AddArgument(argument: "run");
645
646 // Ensure we can enable / disable DevTools when invoking 'dart run'
647 // implicitly.
648 if (enable_vm_service_) {
649 if (serve_devtools) {
650 dart_options->AddArgument(argument: "--serve-devtools");
651 } else {
652 dart_options->AddArgument(argument: "--no-serve-devtools");
653 }
654 }
655 } else {
656 dart_options->AddArgument(argument: argv[i]);
657 i++;
658 }
659 // Add DDS specific flags immediately after the dartdev command.
660 if (first_option) {
661 // DDS is only enabled for the run command. Make sure we don't pass DDS
662 // specific flags along with other commands, otherwise argument parsing
663 // will fail unexpectedly.
664 bool run_command = implicitly_use_dart_dev;
665 if (!run_command && strcmp(s1: argv[i - 1], s2: "run") == 0) {
666 run_command = true;
667 }
668 if (!Options::disable_dart_dev() && !Options::disable_dds() &&
669 enable_vm_service_ && run_command) {
670 const char* dds_format_str = "--launch-dds=%s\\:%d";
671 size_t size =
672 snprintf(s: nullptr, maxlen: 0, format: dds_format_str, vm_service_server_ip(),
673 vm_service_server_port());
674 // Make room for '\0'.
675 ++size;
676 char* dds_uri = new char[size];
677 snprintf(s: dds_uri, maxlen: size, format: dds_format_str, vm_service_server_ip(),
678 vm_service_server_port());
679 dart_options->AddArgument(argument: dds_uri);
680
681 // Only add --disable-service-auth-codes if dartdev is being run
682 // implicitly. Otherwise it will already be forwarded.
683 if (implicitly_use_dart_dev && Options::vm_service_auth_disabled()) {
684 dart_options->AddArgument(argument: "--disable-service-auth-codes");
685 }
686 if (implicitly_use_dart_dev &&
687 Options::enable_service_port_fallback()) {
688 dart_options->AddArgument(argument: "--enable-service-port-fallback");
689 }
690 }
691#if !defined(DART_PRECOMPILED_RUNTIME)
692 // Bring any --packages option into the dartdev command
693 if (DartDevIsolate::should_run_dart_dev() &&
694 packages_argument != nullptr) {
695 dart_options->AddArgument(packages_argument);
696 }
697#endif // !defined(DART_PRECOMPILED_RUNTIME)
698 first_option = false;
699 }
700 }
701
702 // Verify consistency of arguments.
703
704 // snapshot_depfile is an alias for depfile. Passing them both is an error.
705 if ((snapshot_deps_filename_ != nullptr) && (depfile_ != nullptr)) {
706 Syslog::PrintErr(format: "Specify only one of --depfile and --snapshot_depfile\n");
707 return false;
708 }
709 if (snapshot_deps_filename_ != nullptr) {
710 depfile_ = snapshot_deps_filename_;
711 snapshot_deps_filename_ = nullptr;
712 }
713
714 if ((packages_file_ != nullptr) && (strlen(s: packages_file_) == 0)) {
715 Syslog::PrintErr(format: "Empty package file name specified.\n");
716 return false;
717 }
718 if ((gen_snapshot_kind_ != kNone) && (snapshot_filename_ == nullptr)) {
719 Syslog::PrintErr(
720 format: "Generating a snapshot requires a filename (--snapshot).\n");
721 return false;
722 }
723 if ((gen_snapshot_kind_ == kNone) && (depfile_ != nullptr) &&
724 (snapshot_filename_ == nullptr) &&
725 (depfile_output_filename_ == nullptr)) {
726 Syslog::PrintErr(
727 format: "Generating a depfile requires an output filename"
728 " (--depfile-output-filename or --snapshot).\n");
729 return false;
730 }
731 if ((gen_snapshot_kind_ != kNone) && vm_run_app_snapshot) {
732 Syslog::PrintErr(
733 format: "Specifying an option to generate a snapshot and"
734 " run using a snapshot is invalid.\n");
735 return false;
736 }
737
738 // If --snapshot is given without --snapshot-kind, default to script snapshot.
739 if ((snapshot_filename_ != nullptr) && (gen_snapshot_kind_ == kNone)) {
740 gen_snapshot_kind_ = kKernel;
741 }
742
743 return true;
744}
745
746} // namespace bin
747} // namespace dart
748

source code of flutter_engine/third_party/dart/runtime/bin/main_options.cc