vxx2 / vlib / v / pref / pref.v
1596 lines · 1540 sloc · 52.66 KB · e8810a671233f1d2072d70ab8e17c3b1dad5e1e5
Raw
1// Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module pref
5
6// import v.ast // TODO: this results in a compiler bug
7import os.cmdline
8import os
9import v.vcache
10import rand
11
12pub enum BuildMode {
13 // `v program.v'
14 // Build user code only, and add pre-compiled vlib (`cc program.o builtin.o os.o...`)
15 default_mode // `v -lib ~/v/os`
16 // build any module (generate os.o + os.vh)
17 build_module
18}
19
20pub enum AssertFailureMode {
21 default
22 aborts
23 backtraces
24 continues
25}
26
27pub enum GarbageCollectionMode {
28 unknown
29 no_gc
30 boehm_full // full garbage collection mode
31 boehm_incr // incremental garbage collection mode
32 boehm_full_opt // full garbage collection mode
33 boehm_incr_opt // incremental garbage collection mode
34 boehm_leak // leak detection mode (makes `gc_check_leaks()` work)
35 vgc // V GC: concurrent tri-color mark-and-sweep (translated from Go's runtime GC)
36}
37
38pub enum OutputMode {
39 stdout
40 silent
41}
42
43pub enum ColorOutput {
44 auto
45 always
46 never
47}
48
49// Subsystem is needed for modeling passing an explicit `/subsystem:windows` or `/subsystem:console` on Windows.
50// By default it is `auto`. It has no effect on platforms != windows.
51pub enum Subsystem {
52 auto
53 console
54 windows
55}
56
57pub enum Backend {
58 c // The (default) C backend
59 interpret // Removed V1 interpreter backend; kept for compatibility diagnostics.
60 js_node // The JavaScript NodeJS backend
61 js_browser // The JavaScript browser backend
62 js_freestanding // The JavaScript freestanding backend
63 wasm // The WebAssembly backend
64}
65
66pub fn (b Backend) is_js() bool {
67 return b in [
68 .js_node,
69 .js_browser,
70 .js_freestanding,
71 ]
72}
73
74pub enum CompilerType {
75 gcc
76 tinyc
77 clang
78 emcc
79 mingw
80 msvc
81 cplusplus
82}
83
84pub const supported_test_runners = ['normal', 'simple', 'tap', 'dump', 'teamcity']
85
86@[heap; minify]
87pub struct Preferences {
88pub mut:
89 os OS // the OS to compile for
90 backend Backend
91 backend_set_by_flag bool // true when the compiler receives `-b`/`-backend`
92 build_mode BuildMode
93 arch Arch
94 output_mode OutputMode = .stdout
95 // verbosity VerboseLevel
96 is_verbose bool
97 use_v2 bool
98 // nofmt bool // disable vfmt
99 is_glibc bool // if GLIBC will be linked
100 is_musl bool // if MUSL will be linked
101 is_test bool // `v test string_test.v`
102 is_script bool // single file mode (`v program.v`), main function can be skipped
103 is_vsh bool // v script (`file.vsh`) file, the `os` module should be made global
104 raw_vsh_tmp_prefix string // The prefix used for executables, when a script lacks the .vsh extension
105 is_livemain bool // main program that contains live/hot code
106 is_liveshared bool // a shared library, that will be used in a -live main program
107 is_shared bool // an ordinary shared library, -shared, no matter if it is live or not
108 is_o bool // building an .o file
109 is_prof bool // benchmark every function
110 is_prod bool // use "-O3"
111 no_prod_options bool // `-no-prod-options`, means do not pass any optimization flags to the C compilation, while still allowing the user to use for example `-cflags -Os` to pass custom ones
112 is_repl bool
113 is_eval_argument bool // true for `v -e 'println(2+2)'`. `println(2+2)` will be in pref.eval_argument .
114 is_run bool // compile and run a v program, passing arguments to it, and deleting the executable afterwards
115 is_crun bool // similar to run, but does not recompile the executable, if there were no changes to the sources
116 is_debug bool // turned on by -g/-debug or -cg/-cdebug, it tells v to pass -g to the C backend compiler.
117 is_vlines bool // turned on by -g (it slows down .tmp.c generation slightly).
118 is_stats bool // `v -stats file.v` will produce more detailed statistics for the file that is compiled
119 show_asserts bool // `VTEST_SHOW_ASSERTS=1 v file_test.v` will show details about the asserts done by a test file. Also activated for `-stats` and `-show-asserts`.
120 show_timings bool // show how much time each compiler stage took
121 is_fmt bool
122 is_vdoc bool
123 is_vet bool
124 is_template bool // skip _ var warning in templates
125 is_ios_simulator bool
126 is_apk bool // build as Android .apk format
127 is_help bool // -h, -help or --help was passed
128 is_quiet bool // do not show the repetitive explanatory messages like the one for `v -prod run file.v` .
129 is_cstrict bool // turn on more C warnings; slightly slower
130 is_callstack bool // turn on callstack registers on each call when v.debug is imported
131 is_trace bool // turn on possibility to trace fn call where v.debug is imported
132 is_coverage bool // turn on code coverage stats
133 is_check_return bool // -check-return, will make V produce notices about *all* call expressions with unused results. NOTE: experimental!
134 is_check_overflow bool // -check-overflow, will panic on integer overflow
135 eval_argument string // `println(2+2)` on `v -e "println(2+2)"`. Note that this source code, will be evaluated in vsh mode, so 'v -e 'println(ls(".")!)' is valid.
136 test_runner string // can be 'simple' (fastest, but much less detailed), 'tap', 'normal'
137 profile_file string // the profile results will be stored inside profile_file
138 coverage_dir string // the coverage files will be stored inside coverage_dir
139 profile_no_inline bool // when true, @[inline] functions would not be profiled
140 profile_fns []string // when set, profiling will be off by default, but inside these functions (and what they call) it will be on.
141 translated bool // `v translate doom.v` are we running V code translated from C? allow globals, ++ expressions, etc
142 translated_go bool = true // Are we running V code translated from Go? Allow err shadowing
143 obfuscate_removed bool // `v -obf program.v`, renames functions to "f_XXX". REMOVED. Use `strip` instead
144 hide_auto_str bool // `v -hide-auto-str program.v`, doesn't generate str() with struct data
145 // Note: passing -cg instead of -g will set is_vlines to false and is_debug to true, thus making v generate cleaner C files,
146 // which are sometimes easier to debug / inspect manually than the .tmp.c files by plain -g (when/if v line number generation breaks).
147 sanitize bool // use Clang's new "-fsanitize" option
148 sourcemap bool // JS Backend: -sourcemap will create a source map - default false
149 sourcemap_inline bool = true // JS Backend: -sourcemap-inline will embed the source map in the generated JaaScript file - currently default true only implemented
150 sourcemap_src_included bool // JS Backend: -sourcemap-src-included includes V source code in source map - default false
151 show_cc bool // -showcc, print cc command
152 show_c_output bool // -show-c-output, print all cc output even if the code was compiled correctly
153 show_callgraph bool // -show-callgraph, print the program callgraph, in a Graphviz DOT format to stdout
154 show_depgraph bool // -show-depgraph, print the program module dependency graph, in a Graphviz DOT format to stdout
155 show_unused_params bool = true // regular function params should report as unused by default.
156 c_error_bug_report_url string // `-bug-report-url url` - override the automatic C compiler bug report endpoint.
157 dump_c_flags string // `-dump-c-flags file.txt` - let V store all C flags, passed to the backend C compiler in `file.txt`, one C flag/value per line.
158 dump_modules string // `-dump-modules modules.txt` - let V store all V modules, that were used by the compiled program in `modules.txt`, one module per line.
159 dump_files string // `-dump-files files.txt` - let V store all V or .template file paths, that were used by the compiled program in `files.txt`, one path per line.
160 dump_defines string // `-dump-defines defines.txt` - let V store all the defines that affect the current program and their values, one define per line + `,` + its value.
161 generate_c_project string // `-generate-c-project path` - generate a portable C project folder with the generated C file and build scripts.
162 use_cache bool // when set, use cached modules to speed up subsequent compilations, at the cost of slower initial ones (while the modules are cached)
163 retry_compilation bool = true // retry the compilation with another C compiler, if tcc fails.
164 use_os_system_to_run bool // when set, use os.system() to run the produced executable, instead of os.new_process; works around segfaults on macos, that may happen when xcode is updated
165 macosx_version_min string = '0' // relevant only for macos and ios targets
166 // TODO: Convert this into a []string
167 cflags string // Additional options which will be passed to the C compiler *before* other options.
168 ldflags string // Additional options which will be passed to the C compiler *after* everything else.
169 // For example, passing -cflags -Os will cause the C compiler to optimize the generated binaries for size.
170 // You could pass several -cflags XXX arguments. They will be merged with each other.
171 // You can also quote several options at the same time: -cflags '-Os -fno-inline-small-functions'.
172 m64 bool // true = generate 64-bit code, defaults to x64
173 ccompiler string // the name of the C compiler used
174 ccompiler_set_by_flag bool // true when the compiler receives `-cc`
175 ccompiler_type CompilerType // the type of the C compiler used
176 cppcompiler string // the name of the CPP compiler used
177 third_party_option string
178 building_v bool
179 no_bounds_checking bool // `-no-bounds-checking` turns off *all* bounds checks for all functions at runtime, as if they all had been tagged with `@[direct_array_access]`
180 force_bounds_checking bool // `-force-bounds-checking` turns ON *all* bounds checks, even for functions that *were* tagged with `@[direct_array_access]`
181 autofree bool // `v -manualfree` => false, `v -autofree` => true; false by default for now.
182 print_autofree_vars bool // print vars that are not freed by autofree
183 print_autofree_vars_in_fn string // same as above, but only for a single fn
184 // Disabling `free()` insertion results in better performance in some applications (e.g. compilers)
185 trace_calls bool // -trace-calls true = the transformer stage will generate and inject print calls for tracing function calls
186 trace_fns []string // when set, tracing will be done only for functions, whose names match the listed patterns.
187 compress bool // when set, use `upx` to compress the generated executable
188 // generating_vh bool
189 no_builtin bool // Skip adding the `builtin` module implicitly. The generated C code may not compile.
190 enable_globals bool // allow __global for low level code
191 disable_explicit_mutability bool // allow ordinary variables to be mutated without explicit `mut` annotations
192 is_bare bool // set by -freestanding
193 bare_builtin_dir string // Set by -bare-builtin-dir xyz/ . The xyz/ module should contain implementations of malloc, memset, etc, that are used by the rest of V's `builtin` module. That option is only useful with -freestanding (i.e. when is_bare is true).
194 no_preludes bool // Prevents V from generating preludes in resulting .c files
195 custom_prelude string // Contents of custom V prelude that will be prepended before code in resulting .c files
196 no_closures bool // Produce a compile time error, if a closure was generated for any reason (an implicit receiver method was stored, or an explicit `fn [captured]()`).
197 cmain string // The name of the generated C main function. Useful with framework like code, that uses macros to re-define `main`, like SDL2 does. When set, V will always generate `int THE_NAME(int ___argc, char** ___argv){`, *no matter* the platform.
198 lookup_path []string
199 output_cross_c bool // true, when the user passed `-os cross` or `-cross`
200 output_es5 bool
201 prealloc bool
202 vroot string
203 vlib string // absolute path to the vlib/ folder
204 vmodules_paths []string // absolute paths to the vmodules folders, by default ['/home/user/.vmodules'], can be overridden by setting VMODULES
205 out_name_c string // full os.real_path to the generated .tmp.c file; set by builder.
206 out_name string
207 out_name_is_dir bool // true when `-o`/`-output` was passed with a trailing path separator
208 path string // Path to file/folder to compile
209 line_info string // `-line-info="file.v:28"`: for "mini VLS" (shows information about objects on provided line)
210 linfo LineInfo
211
212 run_only []string // VTEST_ONLY_FN and -run-only accept comma separated glob patterns.
213 exclude []string // glob patterns for excluding .v files from the list of .v files that otherwise would have been used for a compilation, example: `-exclude @vlib/math/*.c.v`
214 file_list []string // A list of .v files or directories. All .v files found recursively in directories will be included in the compilation.
215 // Only test_ functions that match these patterns will be run. -run-only is valid only for _test.v files.
216 // -d vfmt and -d another=0 for `$if vfmt { will execute }` and `$if another ? { will NOT get here }`
217 compile_defines []string // just ['vfmt']
218 compile_defines_all []string // contains both: ['vfmt','another']
219 compile_values map[string]string // the map will contain for `-d key=value`: compile_values['key'] = 'value', and for `-d ident`, it will be: compile_values['ident'] = 'true'
220
221 run_args []string // `v run x.v 1 2 3` => `1 2 3`
222 printfn_list []string // a list of generated function names, whose source should be shown, for debugging
223
224 print_v_files bool // when true, just print the list of all parsed .v files then stop.
225 print_watched_files bool // when true, just print the list of all parsed .v files + all the compiled $tmpl files, then stop. Used by `v watch run webserver.v`
226
227 skip_running bool // when true, do no try to run the produced file (set by b.cc(), when -o x.c or -o x.js)
228 skip_warnings bool // like C's "-w", forces warnings to be ignored.
229 skip_notes bool // force notices to be ignored/not shown.
230 warn_impure_v bool // -Wimpure-v, force a warning for JS.fn()/C.fn(), outside of .js.v/.c.v files. TODO: turn to an error by default
231 warns_are_errors bool // -W, like C's "-Werror", treat *every* warning is an error
232 notes_are_errors bool // -N, treat *every* notice as an error
233 fatal_errors bool // unconditionally exit after the first error with exit(1)
234 reuse_tmpc bool // do not use random names for .tmp.c and .tmp.c.rsp files, and do not remove them
235 no_rsp bool // when true, pass C backend options directly on the CLI (do not use `.rsp` files for them, some older C compilers do not support them)
236 no_std bool // when true, do not pass -std=c99 to the C backend
237
238 no_parallel bool // do not use threads when compiling; slower, but more portable and sometimes less buggy
239 parallel_cc bool // whether to split the resulting .c file into many .c files + a common .h file, that are then compiled in parallel, then linked together.
240 only_check_syntax bool // when true, just parse the files, then stop, before running checker
241 check_only bool // same as only_check_syntax, but also runs the checker
242 experimental bool // enable experimental features
243 skip_unused bool // skip generating C code for functions, that are not used
244
245 use_color ColorOutput // whether the warnings/errors should use ANSI color escapes.
246 cleanup_files []string // list of temporary *.tmp.c and *.tmp.c.rsp files. Cleaned up on successful builds.
247 build_options []string // list of options, that should be passed down to `build-module`, if needed for -usecache
248 cache_manager vcache.CacheManager
249 gc_mode GarbageCollectionMode = .unknown // .no_gc, .boehm, .boehm_leak, ...
250 gc_set_by_flag bool // true when the compiler receives `-gc`
251 assert_failure_mode AssertFailureMode // whether to call abort() or print_backtrace() after an assertion failure
252 message_limit int = 200 // the maximum amount of warnings/errors/notices that will be accumulated
253 nofloat bool // for low level code, like kernels: replaces f32 with u32 and f64 with u64
254 use_coroutines bool // experimental coroutines
255 fast_math bool // -fast-math will pass either -ffast-math or /fp:fast (for msvc) to the C backend
256 // checker settings:
257 checker_match_exhaustive_cutoff_limit int = 12
258 thread_stack_size int = 8388608 // Change with `-thread-stack-size 4194304`. The final default is adjusted in fill_with_defaults() based on the target architecture.
259 thread_stack_size_set_by_flag bool
260 // wasm settings:
261 wasm_stack_top int = 1024 + (16 * 1024) // stack size for webassembly backend
262 wasm_validate bool // validate webassembly code, by calling `wasm-validate`
263 warn_about_allocs bool // -warn-about-allocs warngs about every single allocation, e.g. 'hi ${name}'. Mostly for low level development where manual memory management is used.
264 // game prototyping flags:
265 div_by_zero_is_zero bool // -div-by-zero-is-zero makes so `x / 0 == 0`, i.e. eliminates the division by zero panics/segfaults
266 // forwards compatibility settings:
267 relaxed_gcc14 bool = true // turn on the generated pragmas, that make gcc versions > 14 a lot less pedantic. The default is to have those pragmas in the generated C output, so that gcc-14 can be used on Arch etc.
268 //
269 subsystem Subsystem // the type of the window app, that is going to be generated; has no effect on !windows
270 icon_path string // Windows executable icon file (.ico or .png)
271 is_vls bool
272 json_errors bool // -json-errors, for VLS and other tools
273 new_transform bool // temporary for the new transformer
274 new_generic_solver bool
275}
276
277// ensure_coroutines_runtime downloads and exposes the photon runtime used by `import coroutines`.
278pub fn ensure_coroutines_runtime() ! {
279 $if macos || linux {
280 arch := $if arm64 { 'arm64' } $else { 'amd64' }
281 vexe := vexe_path()
282 vroot := os.dir(vexe)
283 so_path := os.join_path(vroot, 'thirdparty', 'photon', 'photonwrapper.so')
284 so_url := 'https://raw.githubusercontent.com/vlang/photonbin/master/photonwrapper_${os.user_os()}_${arch}.so'
285 if !os.exists(so_path) {
286 println('coroutines .so not found, downloading...')
287 res := os.execute('${os.quoted_path(vexe)} download -o "${so_path}" "${so_url}"')
288 if res.exit_code != 0 || !os.exists(so_path) {
289 return error('coroutines .so could not be downloaded with `v download`. Download ${so_url}, place it in ${so_path} then try again.')
290 }
291 println('done!')
292 }
293 $if macos {
294 dyld_fallback_paths := os.getenv('DYLD_FALLBACK_LIBRARY_PATH')
295 so_dir := os.dir(so_path)
296 if !dyld_fallback_paths.contains(so_dir) {
297 env := [dyld_fallback_paths, so_dir].filter(it.len != 0).join(':')
298 os.setenv('DYLD_FALLBACK_LIBRARY_PATH', env, true)
299 }
300 }
301 } $else {
302 return error('coroutines only work on macOS & Linux for now')
303 }
304}
305
306pub fn parse_args(known_external_commands []string, args []string) (&Preferences, string) {
307 return parse_args_and_show_errors(known_external_commands, args, false)
308}
309
310@[if linux]
311fn detect_musl(mut res Preferences) {
312 res.is_glibc = true
313 res.is_musl = false
314 musl := os.execute('ldd --version').output.contains('musl')
315 if musl {
316 res.is_musl = true
317 res.is_glibc = false
318 }
319}
320
321@[noreturn]
322fn run_code_in_tmp_vfile_and_exit(args []string, mut res Preferences, option_name string, extension string,
323 content string) {
324 tmp_file_path := os.join_path(os.vtmp_dir(), rand.ulid())
325 mut tmp_exe_file_path := res.out_name
326 mut output_option := ''
327 if tmp_exe_file_path == '' {
328 tmp_exe_file_path = '${tmp_file_path}.exe'
329 output_option = '-o ${os.quoted_path(tmp_exe_file_path)} '
330 }
331 tmp_v_file_path := '${tmp_file_path}.${extension}'
332 os.write_file(tmp_v_file_path, content) or {
333 panic('Failed to create temporary file ${tmp_v_file_path}')
334 }
335 run_options := cmdline.options_before(args, [option_name]).join(' ')
336 command_options := cmdline.options_after(args, [option_name])#[1..].join(' ')
337 vexe := vexe_path()
338 tmp_cmd := '${os.quoted_path(vexe)} ${output_option} ${run_options} run ${os.quoted_path(tmp_v_file_path)} ${command_options}'
339
340 res.vrun_elog('tmp_cmd: ${tmp_cmd}')
341 tmp_result := os.system(tmp_cmd)
342 res.vrun_elog('exit code: ${tmp_result}')
343
344 if output_option != '' {
345 res.vrun_elog('remove tmp exe file: ${tmp_exe_file_path}')
346 os.rm(tmp_exe_file_path) or {}
347 }
348 res.vrun_elog('remove tmp v file: ${tmp_v_file_path}')
349 os.rm(tmp_v_file_path) or {}
350 exit(tmp_result)
351}
352
353fn inline_icon_option_value(arg string) ?string {
354 for prefix in ['-icon=', '--icon=', '-seticon=', '--seticon='] {
355 if arg.starts_with(prefix) {
356 return arg[prefix.len..]
357 }
358 }
359 return none
360}
361
362fn is_v2_passthrough_bool_flag(arg string) bool {
363 return arg in [
364 '--debug',
365 '--verbose',
366 '--skip-genv',
367 '--skip-builtin',
368 '--skip-imports',
369 '--skip-type-check',
370 '--no-parallel',
371 '--nocache',
372 '--nomarkused',
373 '-nomarkused',
374 '--showcc',
375 '--stats',
376 '-print-parsed-files',
377 '--print-parsed-files',
378 '--profile-alloc',
379 '-profile-alloc',
380 '--shared',
381 '-O0',
382 '--single-backend',
383 '-single-backend',
384 '--freestanding',
385 '-no-mos-tiny',
386 ]
387}
388
389fn v2_delegation_option_takes_value(arg string) bool {
390 return arg in [
391 '-arch',
392 '-assert',
393 '-b',
394 '-backend',
395 '-cc',
396 '-cflags',
397 '-d',
398 '-define',
399 '-fhooks',
400 '-gc',
401 '-hot-fn',
402 '-message-limit',
403 '-o',
404 '-output',
405 '-os',
406 '-printfn',
407 '-thread-stack-size',
408 ]
409}
410
411fn v2_compile_delegation_requested(args []string, known_external_commands []string) bool {
412 mut saw_v2 := false
413 for i := 0; i < args.len; i++ {
414 arg := args[i]
415 if arg == '' {
416 continue
417 }
418 if arg == '--' {
419 return false
420 }
421 if arg == '-v2' {
422 saw_v2 = true
423 continue
424 }
425 if arg.starts_with('-') {
426 if v2_delegation_option_takes_value(arg) {
427 i++
428 }
429 continue
430 }
431 if !saw_v2 {
432 return false
433 }
434 if arg in internal_v_commands || arg in known_external_commands {
435 return false
436 }
437 return is_source_file(arg) || os.exists(arg)
438 }
439 return false
440}
441
442fn set_icon_path(mut res Preferences, raw_path string, option_name string) {
443 if raw_path == '' {
444 eprintln_exit('missing value for `${option_name}`')
445 }
446 res.icon_path = os.real_path(raw_path)
447 res.build_options << '-icon "${res.icon_path}"'
448}
449
450const internal_v_commands = [
451 'run',
452 'crun',
453 'build',
454 'build-module',
455 'help',
456 'version',
457 'new',
458 'init',
459 'install',
460 'link',
461 'list',
462 'outdated',
463 'remove',
464 'search',
465 'show',
466 'unlink',
467 'update',
468 'upgrade',
469 'vlib-docs',
470 'translate',
471]
472
473fn has_following_positional_arg(args []string, start int) bool {
474 for idx := start; idx < args.len; idx++ {
475 if !args[idx].starts_with('-') {
476 return true
477 }
478 }
479 return false
480}
481
482fn optional_arg_value(args []string, idx int, command string, known_external_commands []string, def string) (string, bool) {
483 next := args[idx + 1] or { return def, false }
484 if next == '-' {
485 return next, true
486 }
487 if next.starts_with('-') {
488 return def, false
489 }
490 if command == ''
491 && (next in known_external_commands || next in internal_v_commands || next.ends_with('.v')
492 || next.ends_with('.vsh') || os.is_dir(next)
493 || !has_following_positional_arg(args, idx + 2)) {
494 return def, false
495 }
496 return next, true
497}
498
499pub fn parse_args_and_show_errors(known_external_commands []string, args []string, show_output bool) (&Preferences, string) {
500 mut res := &Preferences{}
501 v2_passthrough_allowed := v2_compile_delegation_requested(args, known_external_commands)
502 detect_musl(mut res)
503 $if x64 {
504 res.m64 = true // follow V model by default
505 }
506 res.run_only = os.getenv('VTEST_ONLY_FN').split_any(',')
507 if os.getenv('VQUIET') != '' {
508 res.is_quiet = true
509 }
510 if os.getenv('VNORUN') != '' {
511 res.skip_running = true
512 }
513 coverage_dir_from_env := os.getenv('VCOVDIR')
514 if coverage_dir_from_env != '' {
515 res.coverage_dir = coverage_dir_from_env
516 }
517
518 mut no_skip_unused := false
519 mut command, mut command_idx := '', 0
520 mut build_vsh_source := false
521 for i := 0; i < args.len; i++ {
522 arg := args[i]
523 if inline_icon_path := inline_icon_option_value(arg) {
524 set_icon_path(mut res, inline_icon_path, arg.all_before('='))
525 continue
526 }
527 if v2_passthrough_allowed && is_v2_passthrough_bool_flag(arg) {
528 continue
529 }
530 if v2_passthrough_allowed && arg == '-fhooks' {
531 value := cmdline.option(args[i..], arg, '')
532 res.build_options << '${arg} ${value}'
533 i++
534 continue
535 }
536 match arg {
537 '--' {
538 break
539 }
540 '-wasm-validate' {
541 res.wasm_validate = true
542 }
543 '-wasm-stack-top' {
544 res.wasm_stack_top = cmdline.option(args[i..], arg, res.wasm_stack_top.str()).int()
545 i++
546 }
547 '-apk' {
548 res.is_apk = true
549 res.build_options << arg
550 }
551 '-arch' {
552 target_arch := cmdline.option(args[i..], '-arch', '')
553 i++
554 target_arch_kind := arch_from_string(target_arch) or {
555 eprintln_exit('unknown architecture target `${target_arch}`')
556 }
557 res.arch = target_arch_kind
558 res.build_options << '${arg} ${target_arch}'
559 }
560 '-assert' {
561 assert_mode := cmdline.option(args[i..], '-assert', '')
562 match assert_mode {
563 'aborts' {
564 res.assert_failure_mode = .aborts
565 }
566 'backtraces' {
567 res.assert_failure_mode = .backtraces
568 }
569 'continues' {
570 res.assert_failure_mode = .continues
571 }
572 else {
573 eprintln('unknown assert mode `-gc ${assert_mode}`, supported modes are:`')
574 eprintln(' `-assert aborts` .... calls abort() after assertion failure')
575 eprintln(' `-assert backtraces` .... calls print_backtrace() after assertion failure')
576 eprintln(' `-assert continues` .... does not call anything, just continue after an assertion failure')
577 exit(1)
578 }
579 }
580
581 i++
582 }
583 '-show-timings' {
584 res.show_timings = true
585 }
586 '-show-asserts' {
587 res.show_asserts = true
588 }
589 '-check-syntax' {
590 res.only_check_syntax = true
591 }
592 '-check' {
593 res.check_only = true
594 }
595 '-vls-mode' {
596 res.is_vls = true
597 }
598 '-?', '-h', '-help', '--help' {
599 // Note: help is *very important*, just respond to all variations:
600 res.is_help = true
601 }
602 '-q' {
603 res.is_quiet = true
604 }
605 '-v', '-V', '--version', '-version' {
606 if command != '' {
607 // Version flags after a command are intended for the command, not for V itself.
608 continue
609 }
610 if args[i..].len > 1 && arg == '-v' {
611 // With additional args after the `-v` flag, it toggles verbosity, like Clang.
612 // E.g.: `v -v` VS `v -v run examples/hello_world.v`.
613 res.is_verbose = true
614 } else {
615 command = 'version'
616 }
617 }
618 '-v2' {
619 if command == '' {
620 res.use_v2 = true
621 }
622 }
623 '-eval', '--eval' {
624 if !v2_passthrough_allowed {
625 eprintln_exit('use v -v2 -eval file.v')
626 }
627 }
628 '-ownership' {
629 // Passed through to v2 compiler for ownership checking
630 }
631 '-progress' {
632 // processed by testing tools in cmd/tools/modules/testing/common.v
633 }
634 '-Wimpure-v' {
635 res.warn_impure_v = true
636 }
637 '-Wfatal-errors' {
638 res.fatal_errors = true
639 }
640 '-silent' {
641 res.output_mode = .silent
642 res.compile_defines_all << 'silent' // enable `$if silent? {`
643 res.compile_defines << 'silent'
644 }
645 '-skip-running' {
646 res.skip_running = true
647 }
648 '-cstrict' {
649 res.is_cstrict = true
650 }
651 '-nofloat' {
652 res.nofloat = true
653 res.compile_defines_all << 'nofloat' // so that `$if nofloat? {` works
654 res.compile_defines << 'nofloat'
655 }
656 '-fast-math' {
657 res.fast_math = true
658 }
659 '-e' {
660 res.is_eval_argument = true
661 res.eval_argument = cmdline.option(args[i..], '-e', '')
662 i++
663 }
664 '-subsystem' {
665 subsystem := cmdline.option(args[i..], '-subsystem', '')
666 res.subsystem = Subsystem.from_string(subsystem) or {
667 mut valid := []string{}
668 $for x in Subsystem.values {
669 valid << x.name
670 }
671 eprintln('invalid subsystem: ${subsystem}')
672 eprintln('valid values are: ${valid}')
673 exit(1)
674 }
675 i++
676 }
677 '-icon', '--icon', '-seticon', '--seticon' {
678 set_icon_path(mut res, cmdline.option(args[i..], arg, ''), arg)
679 i++
680 }
681 '-gc' {
682 gc_mode := cmdline.option(args[i..], '-gc', '')
683 res.gc_set_by_flag = true
684 match gc_mode {
685 'none' {
686 res.gc_mode = .no_gc
687 }
688 '', 'boehm' {
689 res.gc_mode = .boehm_full_opt // default mode
690 res.parse_define('gcboehm')
691 res.parse_define('gcboehm_full')
692 res.parse_define('gcboehm_opt')
693 }
694 'boehm_full' {
695 res.gc_mode = .boehm_full
696 res.parse_define('gcboehm')
697 res.parse_define('gcboehm_full')
698 }
699 'boehm_incr' {
700 res.gc_mode = .boehm_incr
701 res.parse_define('gcboehm')
702 res.parse_define('gcboehm_incr')
703 }
704 'boehm_full_opt' {
705 res.gc_mode = .boehm_full_opt
706 res.parse_define('gcboehm')
707 res.parse_define('gcboehm_full')
708 res.parse_define('gcboehm_opt')
709 }
710 'boehm_incr_opt' {
711 res.gc_mode = .boehm_incr_opt
712 res.parse_define('gcboehm')
713 res.parse_define('gcboehm_incr')
714 res.parse_define('gcboehm_opt')
715 }
716 'boehm_leak' {
717 res.gc_mode = .boehm_leak
718 res.parse_define('gcboehm')
719 res.parse_define('gcboehm_leak')
720 }
721 'vgc' {
722 res.gc_mode = .vgc
723 res.parse_define('vgc')
724 }
725 else {
726 eprintln('unknown garbage collection mode `-gc ${gc_mode}`, supported modes are:`')
727 eprintln(' `-gc boehm` ............ default GC-mode (currently `boehm_full_opt`)')
728 eprintln(' `-gc boehm_full` ....... classic full collection')
729 eprintln(' `-gc boehm_incr` ....... incremental collection')
730 eprintln(' `-gc boehm_full_opt` ... optimized classic full collection')
731 eprintln(' `-gc boehm_incr_opt` ... optimized incremental collection')
732 eprintln(' `-gc boehm_leak` ....... leak detection (for debugging)')
733 eprintln(' `-gc vgc` .............. V GC (concurrent tri-color mark-and-sweep)')
734 eprintln(' `-gc none` ............. no garbage collection')
735 exit(1)
736 }
737 }
738
739 effective_gc_mode := if gc_mode == '' { 'boehm' } else { gc_mode }
740 res.build_options << '${arg} ${effective_gc_mode}'
741 i++
742 }
743 '-g', '-debug' {
744 res.is_debug = true
745 res.is_vlines = true
746 res.build_options << arg
747 }
748 '-cg', '-cdebug' {
749 res.is_debug = true
750 res.is_vlines = false
751 res.build_options << arg
752 }
753 '-debug-tcc' {
754 res.ccompiler = 'tcc'
755 res.build_options << '${arg} "${res.ccompiler}"'
756 res.retry_compilation = false
757 res.show_cc = true
758 res.show_c_output = true
759 }
760 '-sourcemap' {
761 res.sourcemap = true
762 }
763 '-warn-about-allocs' {
764 res.warn_about_allocs = true
765 }
766 '-div-by-zero-is-zero' {
767 res.div_by_zero_is_zero = true
768 }
769 '-sourcemap-src-included' {
770 res.sourcemap_src_included = true
771 }
772 '-sourcemap-inline' {
773 res.sourcemap_inline = true
774 }
775 '-repl' {
776 res.is_repl = true
777 }
778 '-json-errors' {
779 res.json_errors = true
780 }
781 '-live' {
782 res.is_livemain = true
783 res.compile_defines << 'livemain'
784 res.compile_defines_all << 'livemain'
785 }
786 '-sharedlive' {
787 res.is_liveshared = true
788 res.is_shared = true
789 res.compile_defines << 'sharedlive'
790 res.compile_defines_all << 'sharedlive'
791 }
792 '-shared' {
793 res.is_shared = true
794 }
795 '--enable-globals' {
796 eprintln_cond(show_output && !res.is_quiet,
797 '`--enable-globals` flag is deprecated, please use `-enable-globals` instead')
798 res.enable_globals = true
799 }
800 '-enable-globals' {
801 res.enable_globals = true
802 }
803 '--disable-explicit-mutability', '-disable-explicit-mutability' {
804 res.disable_explicit_mutability = true
805 res.build_options << arg
806 }
807 '-autofree' {
808 res.autofree = true
809 res.gc_mode = .no_gc
810 res.build_options << arg
811 }
812 '-print_autofree_vars' {
813 res.print_autofree_vars = true
814 res.build_options << arg
815 }
816 '-print_autofree_vars_in_fn' {
817 res.print_autofree_vars = true
818 value := cmdline.option(args[i..], arg, '')
819 res.build_options << arg
820 res.build_options << value
821 res.print_autofree_vars_in_fn = value
822 i++
823 }
824 '-trace-calls' {
825 res.build_options << arg
826 res.trace_calls = true
827 }
828 '-trace-fns' {
829 value := cmdline.option(args[i..], arg, '')
830 res.build_options << arg
831 res.build_options << value
832 trace_fns := value.split(',')
833 if trace_fns.len > 0 {
834 res.trace_fns << trace_fns
835 }
836 i++
837 }
838 '-manualfree' {
839 res.autofree = false
840 res.build_options << arg
841 }
842 '-skip-unused' {
843 res.skip_unused = true
844 }
845 '-no-skip-unused' {
846 no_skip_unused = true
847 res.skip_unused = false
848 }
849 '-compress' {
850 res.compress = true
851 }
852 '-freestanding' {
853 res.is_bare = true
854 res.build_options << arg
855 }
856 '-no-retry-compilation' {
857 res.retry_compilation = false
858 res.build_options << arg
859 }
860 '-musl' {
861 res.is_musl = true
862 res.is_glibc = false
863 res.build_options << arg
864 }
865 '-glibc' {
866 res.is_musl = false
867 res.is_glibc = true
868 res.build_options << arg
869 }
870 '-no-bounds-checking' {
871 res.no_bounds_checking = true
872 res.compile_defines << 'no_bounds_checking'
873 res.compile_defines_all << 'no_bounds_checking'
874 res.build_options << arg
875 }
876 '-force-bounds-checking' {
877 res.force_bounds_checking = true
878 }
879 '-no-builtin' {
880 res.no_builtin = true
881 res.build_options << arg
882 }
883 '-no-preludes' {
884 res.no_preludes = true
885 res.build_options << arg
886 }
887 '-no-relaxed-gcc14' {
888 res.relaxed_gcc14 = false
889 }
890 '-prof', '-profile' {
891 profile_file, profile_file_consumed := optional_arg_value(args, i, command,
892 known_external_commands, '-')
893 res.profile_file = profile_file
894 res.is_prof = true
895 res.build_options << '${arg} ${res.profile_file}'
896 if profile_file_consumed {
897 i++
898 }
899 }
900 '-cov', '-coverage' {
901 res.coverage_dir = cmdline.option(args[i..], arg, '-')
902 i++
903 }
904 '-profile-fns' {
905 profile_fns := cmdline.option(args[i..], arg, '').split(',')
906 if profile_fns.len > 0 {
907 res.profile_fns << profile_fns
908 }
909 i++
910 }
911 '-profile-no-inline' {
912 res.profile_no_inline = true
913 }
914 '-prod' {
915 res.is_prod = true
916 res.build_options << arg
917 }
918 '-no-prod-options' {
919 res.no_prod_options = true
920 res.build_options << arg
921 }
922 '-sanitize' {
923 res.sanitize = true
924 res.build_options << arg
925 }
926 '-simulator' {
927 res.is_ios_simulator = true
928 }
929 '-stats' {
930 res.is_stats = true
931 }
932 '-obf', '-obfuscate' {
933 println('obfuscation has been removed; use `strip` on the resulting binary instead')
934 res.obfuscate_removed = true
935 }
936 '-hide-auto-str' {
937 res.hide_auto_str = true
938 }
939 '-translated' {
940 res.translated = true
941 res.gc_mode = .no_gc // no gc in c2v'ed code, at least for now
942 }
943 '-translated-go' {
944 println('got -translated-go')
945 res.translated_go = true
946 }
947 '-m32', '-m64' {
948 res.m64 = arg[2] == `6`
949 res.cflags += ' ${arg}'
950 res.build_options << arg
951 if arg == '-m32' && res.arch == ._auto {
952 res.arch = .i386
953 }
954 }
955 '-color' {
956 res.use_color = .always
957 }
958 '-nocolor' {
959 res.use_color = .never
960 }
961 '-showcc' {
962 res.show_cc = true
963 }
964 '-show-c-output' {
965 res.show_c_output = true
966 }
967 '-show-callgraph' {
968 res.show_callgraph = true
969 }
970 '-show-depgraph' {
971 res.show_depgraph = true
972 }
973 '-bug-report-url' {
974 res.c_error_bug_report_url = cmdline.option(args[i..], arg, '')
975 i++
976 }
977 '-run-only' {
978 res.run_only =
979 cmdline.option(args[i..], arg, os.getenv('VTEST_ONLY_FN')).split_any(',')
980 i++
981 }
982 '-exclude' {
983 patterns := cmdline.option(args[i..], arg, '').split_any(',')
984 res.exclude << patterns
985 i++
986 }
987 '-file-list' {
988 res.file_list = cmdline.option(args[i..], arg, '').split_any(',')
989 i++
990 }
991 '-test-runner' {
992 res.test_runner = cmdline.option(args[i..], arg, res.test_runner)
993 i++
994 }
995 '-dump-c-flags' {
996 res.dump_c_flags = cmdline.option(args[i..], arg, '-')
997 i++
998 }
999 '-dump-modules' {
1000 res.dump_modules = cmdline.option(args[i..], arg, '-')
1001 i++
1002 }
1003 '-dump-files' {
1004 res.dump_files = cmdline.option(args[i..], arg, '-')
1005 i++
1006 }
1007 '-dump-defines' {
1008 res.dump_defines = cmdline.option(args[i..], arg, '-')
1009 i++
1010 }
1011 '-generate-c-project' {
1012 res.generate_c_project = cmdline.option(args[i..], arg, '')
1013 if res.generate_c_project == '' {
1014 eprintln_exit('Missing output directory after `-generate-c-project`.')
1015 }
1016 i++
1017 }
1018 '-experimental' {
1019 res.experimental = true
1020 }
1021 '-new-transformer' {
1022 res.new_transform = true
1023 }
1024 '-usecache' {
1025 res.use_cache = true
1026 res.parallel_cc = false
1027 res.no_parallel = true
1028 }
1029 '-use-os-system-to-run' {
1030 res.use_os_system_to_run = true
1031 }
1032 '-macosx-version-min' {
1033 res.macosx_version_min = cmdline.option(args[i..], arg, res.macosx_version_min)
1034 res.build_options << '${arg} ${res.macosx_version_min}'
1035 i++
1036 }
1037 '-nocache' {
1038 res.use_cache = false
1039 }
1040 '-prealloc' {
1041 res.prealloc = true
1042 if !res.gc_set_by_flag {
1043 res.gc_mode = .no_gc
1044 }
1045 res.build_options << arg
1046 }
1047 '-no-parallel' {
1048 res.no_parallel = true
1049 res.build_options << arg
1050 }
1051 '-parallel-cc' {
1052 res.parallel_cc = true
1053 res.no_parallel = true // TODO: see how to make both work
1054 res.build_options << arg
1055 }
1056 '-native' {
1057 eprintln_exit('The native backend has been removed. Use `v -v2 -b arm64` or `v -v2 -b x64` instead.')
1058 }
1059 '-interpret' {
1060 eprintln_exit('use v -v2 -eval file.v')
1061 }
1062 '-W' {
1063 res.warns_are_errors = true
1064 }
1065 '-w' {
1066 res.skip_warnings = true
1067 res.warns_are_errors = false
1068 }
1069 '-N' {
1070 res.notes_are_errors = true
1071 }
1072 '-n' {
1073 res.skip_notes = true
1074 res.notes_are_errors = false
1075 }
1076 '-no-closures' {
1077 res.no_closures = true
1078 }
1079 '-no-rsp' {
1080 res.no_rsp = true
1081 }
1082 '-no-std' {
1083 res.no_std = true
1084 }
1085 '-keepc' {
1086 res.reuse_tmpc = true
1087 }
1088 '-watch' {
1089 eprintln_exit('The -watch option is deprecated. Please use the watch command `v watch file.v` instead.')
1090 }
1091 '-print-v-files' {
1092 res.print_v_files = true
1093 }
1094 '-print-watched-files' {
1095 res.print_watched_files = true
1096 }
1097 '-http' {
1098 run_http_argument := 'import net.http.file; file.serve()'
1099 mut new_args := args.filter(it != '-http')
1100 new_args << ['-e', run_http_argument]
1101 eprintln_cond(show_output && !res.is_quiet,
1102 "Note: use `v -e '${run_http_argument}'`, if you want to customise the http server options.")
1103 run_code_in_tmp_vfile_and_exit(new_args, mut res, '-e', 'vsh', run_http_argument)
1104 }
1105 '-cross' {
1106 res.output_cross_c = true
1107 res.build_options << '${arg}'
1108 }
1109 '-os' {
1110 target_os := cmdline.option(args[i..], '-os', '').to_lower_ascii()
1111 i++
1112 target_os_kind := os_from_string(target_os) or {
1113 if target_os == 'cross' {
1114 res.output_cross_c = true
1115 continue
1116 }
1117 if v2_passthrough_allowed && target_os == 'none' {
1118 res.build_options << '${arg} ${target_os}'
1119 continue
1120 }
1121 eprintln_exit('unknown operating system target `${target_os}`')
1122 }
1123 if target_os_kind == .wasm32 {
1124 res.is_bare = true
1125 }
1126 if target_os_kind in [.wasm32, .wasm32_emscripten, .wasm32_wasi] {
1127 res.arch = .wasm32
1128 }
1129 if target_os_kind == .wasm32_emscripten {
1130 res.gc_mode = .no_gc // TODO: enable gc (turn off threads etc, in builtin_d_gcboehm.c.v, once `$if wasm32_emscripten {` works)
1131 }
1132 res.os = target_os_kind
1133 res.build_options << '${arg} ${target_os}'
1134 }
1135 '-printfn' {
1136 res.printfn_list << cmdline.option(args[i..], '-printfn', '').split(',')
1137 i++
1138 }
1139 '-cflags' {
1140 res.cflags += ' ' + cmdline.option(args[i..], '-cflags', '')
1141 res.build_options << '${arg} "${res.cflags.trim_space()}"'
1142 i++
1143 }
1144 '-ldflags' {
1145 res.ldflags += ' ' + cmdline.option(args[i..], '-ldflags', '')
1146 res.build_options << '${arg} "${res.ldflags.trim_space()}"'
1147 i++
1148 }
1149 '-d', '-define' {
1150 if define := args[i..][1] {
1151 res.parse_define(define)
1152 }
1153 i++
1154 }
1155 '-message-limit' {
1156 res.message_limit = cmdline.option(args[i..], arg, '5').int()
1157 i++
1158 }
1159 '-thread-stack-size' {
1160 res.thread_stack_size =
1161 cmdline.option(args[i..], arg, res.thread_stack_size.str()).int()
1162 res.thread_stack_size_set_by_flag = true
1163 i++
1164 }
1165 '-cc' {
1166 res.ccompiler = cmdline.option(args[i..], '-cc', 'cc')
1167 res.ccompiler_set_by_flag = true
1168 res.build_options << '${arg} "${res.ccompiler}"'
1169 i++
1170 }
1171 '-c++' {
1172 res.cppcompiler = cmdline.option(args[i..], '-c++', 'c++')
1173 i++
1174 }
1175 '-checker-match-exhaustive-cutoff-limit' {
1176 res.checker_match_exhaustive_cutoff_limit =
1177 cmdline.option(args[i..], arg, '10').int()
1178 i++
1179 }
1180 '-o', '-output' {
1181 raw_out_name := cmdline.option(args[i..], arg, '')
1182 res.out_name_is_dir = raw_out_name.ends_with('/') || raw_out_name.ends_with('\\')
1183 res.out_name = raw_out_name
1184 if !os.is_abs_path(res.out_name) {
1185 res.out_name = os.join_path(os.getwd(), res.out_name)
1186 }
1187 i++
1188 }
1189 '-is_o' {
1190 res.is_o = true
1191 }
1192 '-b', '-backend' {
1193 sbackend := cmdline.option(args[i..], arg, 'c')
1194 res.build_options << '${arg} ${sbackend}'
1195 if v2_passthrough_allowed
1196 && sbackend in ['eval', 'cleanc', 'c', 'v', 'arm64', 'x64'] {
1197 res.backend_set_by_flag = true
1198 i++
1199 continue
1200 }
1201 b := backend_from_string(sbackend) or {
1202 eprintln_exit('Unknown V backend: ${sbackend}\nValid -backend choices are: c, js, js_node, js_browser, js_freestanding, wasm, arm64, x64')
1203 }
1204 if b == .wasm {
1205 res.compile_defines << 'wasm'
1206 res.compile_defines_all << 'wasm'
1207 res.arch = .wasm32
1208 } else if b.is_js() {
1209 res.output_cross_c = true
1210 }
1211 res.backend = b
1212 res.backend_set_by_flag = true
1213 i++
1214 }
1215 '-es5' {
1216 res.output_es5 = true
1217 }
1218 '-path' {
1219 path := cmdline.option(args[i..], '-path', '')
1220 res.build_options << '${arg} "${path}"'
1221 res.lookup_path = path.replace('|', os.path_delimiter).split(os.path_delimiter)
1222 i++
1223 }
1224 '-bare-builtin-dir' {
1225 bare_builtin_dir := cmdline.option(args[i..], arg, '')
1226 res.build_options << '${arg} "${bare_builtin_dir}"'
1227 res.bare_builtin_dir = bare_builtin_dir
1228 i++
1229 }
1230 '-custom-prelude' {
1231 path := cmdline.option(args[i..], '-custom-prelude', '')
1232 res.build_options << '${arg} ${path}'
1233 prelude := os.read_file(path) or {
1234 eprintln_exit('cannot open custom prelude file: ${err}')
1235 }
1236 res.custom_prelude = prelude
1237 i++
1238 }
1239 '-raw-vsh-tmp-prefix' {
1240 res.raw_vsh_tmp_prefix = cmdline.option(args[i..], arg, '')
1241 i++
1242 }
1243 '-cmain' {
1244 res.cmain = cmdline.option(args[i..], '-cmain', '')
1245 i++
1246 }
1247 '-line-info' {
1248 res.line_info = cmdline.option(args[i..], arg, '')
1249 res.parse_line_info(res.line_info)
1250 i++
1251 }
1252 '-check-unused-fn-args' {
1253 res.show_unused_params = true
1254 }
1255 '-check-return' {
1256 res.is_check_return = true
1257 }
1258 '-check-overflow' {
1259 res.is_check_overflow = true
1260 }
1261 '-use-coroutines' {
1262 res.use_coroutines = true
1263 ensure_coroutines_runtime() or { eprintln_exit(err.msg()) }
1264 res.compile_defines << 'is_coroutine'
1265 res.compile_defines_all << 'is_coroutine'
1266 }
1267 '-new-generic-solver' {
1268 res.new_generic_solver = true
1269 }
1270 else {
1271 if command == 'build' && is_source_file(arg) {
1272 if arg.ends_with('.vsh') {
1273 command, command_idx = arg, i
1274 build_vsh_source = true
1275 res.skip_running = true
1276 continue
1277 }
1278 eprintln_exit('Use `v ${arg}` instead.')
1279 }
1280 if is_source_file(arg) && arg.ends_with('.vsh') {
1281 // store for future iterations
1282 res.is_vsh = true
1283 }
1284 if !arg.starts_with('-') {
1285 if command == '' {
1286 command, command_idx = arg, i
1287 if res.is_eval_argument || command in ['run', 'crun', 'watch'] {
1288 break
1289 }
1290 } else if is_source_file(command) && is_source_file(arg) && !res.is_vsh
1291 && command !in known_external_commands && res.raw_vsh_tmp_prefix == '' {
1292 eprintln_exit('Too many targets. Specify just one target: <target.v|target_directory>.')
1293 }
1294 continue
1295 }
1296 if command !in ['', 'build-module'] && !is_source_file(command) {
1297 // arguments for e.g. fmt should be checked elsewhere
1298 continue
1299 }
1300 if command_idx < i && (res.is_vsh || (is_source_file(command)
1301 && command in known_external_commands)) {
1302 // When running programs, let them be responsible for the arguments passed to them.
1303 // E.g.: `script.vsh cmd -opt` or `v run hello_world.v -opt`.
1304 // But detect unknown arguments when building them. E.g.: `v hello_world.v -opt`.
1305 continue
1306 }
1307 err_detail := if command == '' { '' } else { ' for command `${command}`' }
1308 eprintln_exit('Unknown argument `${arg}`${err_detail}')
1309 }
1310 }
1311 }
1312 if res.force_bounds_checking {
1313 res.no_bounds_checking = false
1314 res.compile_defines = res.compile_defines.filter(it == 'no_bounds_checking')
1315 res.compile_defines_all = res.compile_defines_all.filter(it == 'no_bounds_checking')
1316 }
1317 if res.trace_calls {
1318 if res.trace_fns.len == 0 {
1319 res.trace_fns << '*'
1320 }
1321 for i, fpattern in res.trace_fns {
1322 if fpattern.contains('*') {
1323 continue
1324 }
1325 res.trace_fns[i] = '*${fpattern}*'
1326 }
1327 }
1328 if command == 'crun' {
1329 res.is_crun = true
1330 }
1331 if command == 'run' {
1332 res.is_run = true
1333 }
1334 res.show_asserts = res.show_asserts || res.is_stats || os.getenv('VTEST_SHOW_ASSERTS') != ''
1335
1336 if res.os != .wasm32_emscripten {
1337 if res.out_name.ends_with('.js') && !res.backend_set_by_flag {
1338 res.backend = .js_node
1339 res.output_cross_c = true
1340 }
1341 }
1342
1343 // Disable parallel checker on arm64 windows and linux for now
1344 $if linux || windows {
1345 $if arm64 {
1346 res.no_parallel = true
1347 }
1348 }
1349
1350 if res.out_name.ends_with('.o') {
1351 res.is_o = true
1352 }
1353
1354 if command == 'run' && res.is_prod && os.is_atty(1) > 0 {
1355 eprintln_cond(show_output && !res.is_quiet,
1356 "Note: building an optimized binary takes much longer. It shouldn't be used with `v run`.")
1357 eprintln_cond(show_output && !res.is_quiet,
1358 'Use `v run` without optimization, or build an optimized binary with -prod first, then run it separately.')
1359 }
1360 if res.os in [.browser, .wasi] && res.backend != .wasm {
1361 eprintln_exit('OS `${res.os}` forbidden for backends other than wasm')
1362 }
1363 if res.backend == .wasm && res.os !in [.browser, .wasi, ._auto] {
1364 eprintln_exit('Native WebAssembly backend OS must be `browser` or `wasi`')
1365 }
1366
1367 if command != 'doc' && res.out_name.ends_with('.v') {
1368 eprintln_exit('Cannot save output binary in a .v file.')
1369 }
1370 if res.fast_math {
1371 if res.ccompiler_type == .msvc {
1372 res.cflags += ' /fp:fast'
1373 } else {
1374 res.cflags += ' -ffast-math'
1375 }
1376 }
1377 if res.is_eval_argument {
1378 // `v -e "println(2+5)"`
1379 run_code_in_tmp_vfile_and_exit(args, mut res, '-e', 'vsh', res.eval_argument)
1380 }
1381
1382 command_args := args#[command_idx + 1..]
1383 if res.is_run || res.is_crun {
1384 res.path = command_args[0] or { eprintln_exit('v run: no v files listed') }
1385 res.run_args = command_args[1..]
1386 if res.path == '-' {
1387 // `echo "println(2+5)" | v -`
1388 contents := os.get_raw_lines_joined()
1389 run_code_in_tmp_vfile_and_exit(args, mut res, 'run', 'v', contents)
1390 }
1391 must_exist(res.path)
1392 if !res.path.ends_with('.v') && os.is_executable(res.path) && os.is_file(res.path)
1393 && os.is_file(res.path + '.v') {
1394 eprintln_cond(show_output && !res.is_quiet,
1395 'It looks like you wanted to run "${res.path}.v", so we went ahead and did that since "${res.path}" is an executable.')
1396 res.path += '.v'
1397 }
1398 } else if is_source_file(command) {
1399 res.path = command
1400 }
1401 if !res.is_bare && res.bare_builtin_dir != '' {
1402 eprintln_cond(show_output && !res.is_quiet,
1403 '`-bare-builtin-dir` must be used with `-freestanding`')
1404 }
1405 if !build_vsh_source
1406 && (command.ends_with('.vsh') || (res.raw_vsh_tmp_prefix != '' && !res.is_run)) {
1407 // `v build.vsh gcc` is the same as `v run build.vsh gcc`,
1408 // i.e. compiling, then running the script, passing the args
1409 // after it to the script:
1410 res.is_crun = true
1411 res.path = command
1412 res.run_args = command_args
1413 } else if command == 'interpret' {
1414 eprintln_exit('use v -v2 -eval file.v')
1415 }
1416 if command == 'build-module' {
1417 res.build_mode = .build_module
1418 res.no_parallel = true
1419 res.parallel_cc = false
1420 res.path = command_args[0] or { eprintln_exit('v build-module: no module specified') }
1421 }
1422 if res.ccompiler == 'musl-gcc' {
1423 res.is_musl = true
1424 res.is_glibc = false
1425 }
1426 if res.is_musl {
1427 // make `$if musl? {` work:
1428 res.compile_defines << 'musl'
1429 res.compile_defines_all << 'musl'
1430 }
1431 if res.is_bare {
1432 // make `$if freestanding? {` + file_freestanding.v + file_notd_freestanding.v work:
1433 res.compile_defines << 'freestanding'
1434 res.compile_defines_all << 'freestanding'
1435 }
1436 if 'callstack' in res.compile_defines_all {
1437 res.is_callstack = true
1438 }
1439 if 'trace' in res.compile_defines_all {
1440 res.is_trace = true
1441 }
1442 if res.coverage_dir != '' {
1443 res.is_coverage = true
1444 res.build_options << '-coverage ${res.coverage_dir}'
1445 }
1446 // keep only the unique res.build_options:
1447 mut m := map[string]string{}
1448 for x in res.build_options {
1449 m[x] = ''
1450 }
1451 res.build_options = m.keys()
1452 // eprintln('>> res.build_options: ${res.build_options}')
1453 res.fill_with_defaults()
1454 if res.generate_c_project != '' {
1455 // The generated C project should not depend on cached V module objects.
1456 res.use_cache = false
1457 }
1458 if res.backend == .c {
1459 res.skip_unused = res.build_mode != .build_module
1460 if no_skip_unused {
1461 res.skip_unused = false
1462 }
1463 }
1464
1465 return res, command
1466}
1467
1468@[noreturn]
1469pub fn eprintln_exit(s string) {
1470 eprintln(s)
1471 exit(1)
1472}
1473
1474pub fn eprintln_cond(condition bool, s string) {
1475 if !condition {
1476 return
1477 }
1478 eprintln(s)
1479}
1480
1481pub fn (pref &Preferences) vrun_elog(s string) {
1482 if pref.is_verbose {
1483 eprintln('> v run -, ${s}')
1484 }
1485}
1486
1487pub fn (pref &Preferences) should_output_to_stdout() bool {
1488 return pref.out_name.ends_with('/-') || pref.out_name.ends_with(r'\-')
1489}
1490
1491fn must_exist(path string) {
1492 if !os.exists(path) {
1493 eprintln_exit('v expects that `${path}` exists, but it does not')
1494 }
1495}
1496
1497@[inline]
1498fn is_source_file(path string) bool {
1499 return path.ends_with('.v') || os.exists(path)
1500}
1501
1502pub fn backend_from_string(s string) !Backend {
1503 // TODO: unify the "different js backend" options into a single `-b js`
1504 // + a separate option, to choose the wanted JS output.
1505 return match s {
1506 'c' { .c }
1507 'eval', 'interpret' { eprintln_exit('use v -v2 -eval file.v') }
1508 'js', 'js_node' { .js_node }
1509 'js_browser' { .js_browser }
1510 'js_freestanding' { .js_freestanding }
1511 'wasm' { .wasm }
1512 'native' { eprintln_exit('The native backend has been removed. Use `v -v2 -b arm64` or `v -v2 -b x64` instead.') }
1513 'go', 'golang' { eprintln_exit('The Go backend has been removed. Use `v -v2 -b golang` instead.') }
1514 else { error('Unknown backend type ${s}') }
1515 }
1516}
1517
1518// Helper function to convert string names to CC enum
1519pub fn cc_from_string(s string) CompilerType {
1520 if s == '' {
1521 return .gcc
1522 }
1523 cc := os.file_name(s).to_lower_ascii()
1524 return match true {
1525 cc.contains('tcc') || cc.contains('tinyc') || cc.contains('tinygcc')
1526 || cc.contains('tiny_gcc') || cc.contains('tiny-gcc') {
1527 .tinyc
1528 }
1529 cc.contains('gcc') {
1530 .gcc
1531 }
1532 cc.contains('clang') {
1533 .clang
1534 }
1535 cc.contains('emcc') {
1536 .emcc
1537 }
1538 cc == 'cl' || cc == 'cl.exe' || cc.contains('msvc') {
1539 .msvc
1540 }
1541 cc.contains('mingw') {
1542 .mingw
1543 }
1544 cc.contains('++') {
1545 .cplusplus
1546 }
1547 else {
1548 .gcc
1549 }
1550 }
1551}
1552
1553fn (mut prefs Preferences) parse_compile_value(define string) {
1554 if !define.contains('=') {
1555 eprintln_exit('V error: Define argument value missing for ${define}.')
1556 return
1557 }
1558 name := define.all_before('=')
1559 value := define.all_after_first('=')
1560 prefs.compile_values[name] = value
1561}
1562
1563fn (mut prefs Preferences) parse_define(define string) {
1564 if !(prefs.is_debug && define == 'debug') {
1565 prefs.build_options << '-d ${define}'
1566 }
1567 if !define.contains('=') {
1568 prefs.compile_values[define] = 'true'
1569 prefs.compile_defines << define
1570 prefs.compile_defines_all << define
1571 return
1572 }
1573 dname := define.all_before('=')
1574 dvalue := define.all_after_first('=')
1575 prefs.compile_values[dname] = dvalue
1576 prefs.compile_defines_all << dname
1577 match dvalue {
1578 '' {}
1579 else {
1580 prefs.compile_defines << dname
1581 }
1582 }
1583}
1584
1585pub fn supported_test_runners_list() string {
1586 return supported_test_runners.map('`${it}`').join(', ')
1587}
1588
1589pub fn (pref &Preferences) should_trace_fn_name(fname string) bool {
1590 return pref.trace_fns.any(fname.match_glob(it))
1591}
1592
1593pub fn (pref &Preferences) should_use_segfault_handler() bool {
1594 return !('no_segfault_handler' in pref.compile_defines
1595 || pref.os in [.wasm32, .wasm32_emscripten])
1596}
1597