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