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