From c2f7afdbf535a3e65a26ec1276b2b2bedaefc533 Mon Sep 17 00:00:00 2001 From: Delyan Angelov Date: Sat, 13 Jul 2024 00:09:44 +0300 Subject: [PATCH] builtin: add `pub fn arguments() []string {`; make `os.args` use it, remove edge case in cgen (#21852) --- vlib/builtin/builtin.c.v | 20 ++++++++- vlib/os/os.c.v | 2 +- vlib/os/os_nix.c.v | 2 + vlib/os/os_windows.c.v | 2 + vlib/v/gen/c/cgen.v | 43 +++++++++---------- vlib/v/markused/markused.v | 2 - vlib/v/slow_tests/profile/profile_test.v | 8 ++-- .../trace_calls/with_modules.vv.must_match | 2 +- 8 files changed, 49 insertions(+), 32 deletions(-) diff --git a/vlib/builtin/builtin.c.v b/vlib/builtin/builtin.c.v index e8d2c837e75257..bd8d5d5f372859 100644 --- a/vlib/builtin/builtin.c.v +++ b/vlib/builtin/builtin.c.v @@ -711,7 +711,7 @@ fn v_fixed_index(i int, len int) int { // NOTE: g_main_argc and g_main_argv are filled in right after C's main start. // They are used internally by V's builtin; for user code, it is much -// more convenient to just use `os.args` instead. +// more convenient to just use `os.args` or call `arguments()` instead. @[markused] __global g_main_argc = int(0) @@ -719,6 +719,24 @@ __global g_main_argc = int(0) @[markused] __global g_main_argv = unsafe { nil } +// arguments returns the command line arguments, used for starting the current program as a V array of strings. +// The first string in the array (index 0), is the name of the program, used for invoking the program. +// The second string in the array (index 1), if it exists, is the first argument to the program, etc. +// For example, if you started your program as `myprogram -option`, then arguments() will return ['myprogram', '-option']. +// Note: if you `v run file.v abc def`, then arguments() will return ['file', 'abc', 'def'], or ['file.exe', 'abc', 'def'] (on Windows). +pub fn arguments() []string { + argv := &&u8(g_main_argv) + mut res := []string{cap: g_main_argc} + for i in 0 .. g_main_argc { + $if windows { + res << unsafe { string_from_wide(&u16(argv[i])) } + } $else { + res << unsafe { tos_clone(argv[i]) } + } + } + return res +} + @[if vplayground ?] fn vplayground_mlimit(n isize) { if n > 10000 { diff --git a/vlib/os/os.c.v b/vlib/os/os.c.v index 2a4a56101f792e..a33dc9dba96a45 100644 --- a/vlib/os/os.c.v +++ b/vlib/os/os.c.v @@ -9,7 +9,7 @@ $if freebsd || openbsd { #include } -pub const args = []string{} +pub const args = arguments() fn C.readdir(voidptr) &C.dirent diff --git a/vlib/os/os_nix.c.v b/vlib/os/os_nix.c.v index 08d5833d658f97..4611c4dda699d7 100644 --- a/vlib/os/os_nix.c.v +++ b/vlib/os/os_nix.c.v @@ -272,6 +272,8 @@ pub fn loginname() !string { return error(posix_get_error_msg(C.errno)) } +@[deprecated: 'os.args now uses arguments()'] +@[deprecated_after: '2024-07-30'] fn init_os_args(argc int, argv &&u8) []string { mut args_ := []string{len: argc} for i in 0 .. argc { diff --git a/vlib/os/os_windows.c.v b/vlib/os/os_windows.c.v index 74ac799abf0721..5823c44ca630ca 100644 --- a/vlib/os/os_windows.c.v +++ b/vlib/os/os_windows.c.v @@ -103,6 +103,8 @@ pub struct C._utimbuf { fn C._utime(&char, voidptr) int +@[deprecated: 'os.args now uses arguments()'] +@[deprecated_after: '2024-07-30'] fn init_os_args_wide(argc int, argv &&u8) []string { mut args_ := []string{len: argc} for i in 0 .. argc { diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 2a55ea75246306..1094136b1856b0 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6116,29 +6116,22 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ mut styp := g.typ(typ) cname := g.c_const_name(name) mut init := strings.new_builder(100) - if cname == '_const_os__args' { - if g.pref.os == .windows { - init.writeln('\t_const_os__args = os__init_os_args_wide(___argc, (byteptr*)___argv);') - } else { - init.writeln('\t_const_os__args = os__init_os_args(___argc, (byte**)___argv);') - } + + if surround_cbr { + init.writeln('{') + } + if unwrap_option { + init.writeln(g.expr_string_surround('\t${cname} = *(${styp}*)', expr, '.data;')) + } else if expr is ast.ArrayInit && (expr as ast.ArrayInit).has_index { + init.writeln(g.expr_string_surround('\tmemcpy(&${cname}, &', expr, ', sizeof(${styp}));')) + } else if expr is ast.CallExpr + && g.table.final_sym(g.unwrap_generic((expr as ast.CallExpr).return_type)).kind == .array_fixed { + init.writeln(g.expr_string_surround('\tmemcpy(&${cname}, ', expr, ', sizeof(${styp}));')) } else { - if surround_cbr { - init.writeln('{') - } - if unwrap_option { - init.writeln(g.expr_string_surround('\t${cname} = *(${styp}*)', expr, '.data;')) - } else if expr is ast.ArrayInit && (expr as ast.ArrayInit).has_index { - init.writeln(g.expr_string_surround('\tmemcpy(&${cname}, &', expr, ', sizeof(${styp}));')) - } else if expr is ast.CallExpr - && g.table.final_sym(g.unwrap_generic((expr as ast.CallExpr).return_type)).kind == .array_fixed { - init.writeln(g.expr_string_surround('\tmemcpy(&${cname}, ', expr, ', sizeof(${styp}));')) - } else { - init.writeln(g.expr_string_surround('\t${cname} = ', expr, ';')) - } - if surround_cbr { - init.writeln('}') - } + init.writeln(g.expr_string_surround('\t${cname} = ', expr, ';')) + } + if surround_cbr { + init.writeln('}') } mut def := '${styp} ${cname}' expr_sym := g.table.sym(typ) @@ -6288,7 +6281,11 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) { } else { // More complex expressions need to be moved to `_vinit()` // e.g. `__global ( mygblobal = 'hello ' + world' )` - init = '\t${field.name} = ${g.expr_string(field.expr)}; // 3global' + if field.name in ['g_main_argc', 'g_main_argv'] { + init = '\t// skipping ${field.name}, it was initialised in main' + } else { + init = '\t${field.name} = ${g.expr_string(field.expr)}; // 3global' + } } } else if !g.pref.translated { // don't zero globals from C code default_initializer := g.type_default(field.typ) diff --git a/vlib/v/markused/markused.v b/vlib/v/markused/markused.v index 543df4c1d6de0c..c7baa6b7f43845 100644 --- a/vlib/v/markused/markused.v +++ b/vlib/v/markused/markused.v @@ -135,8 +135,6 @@ pub fn mark_used(mut table ast.Table, mut pref_ pref.Preferences, ast_files []&a 'main.vtest_new_metainfo', 'main.vtest_new_filemetainfo', 'os.getwd', - 'os.init_os_args', - 'os.init_os_args_wide', 'v.embed_file.find_index_entry_by_path', ] } diff --git a/vlib/v/slow_tests/profile/profile_test.v b/vlib/v/slow_tests/profile/profile_test.v index 439157d8fa34b7..d327e6fb7f9610 100644 --- a/vlib/v/slow_tests/profile/profile_test.v +++ b/vlib/v/slow_tests/profile/profile_test.v @@ -67,10 +67,10 @@ fn test_v_profile_works() { println(@FN) sfile := 'vlib/v/slow_tests/profile/profile_test_1.v' validate_output(@FN, '', sfile, { - 'os__init_os_args': 1 - 'main__main': 1 - 'println': 1 - 'strconv__atoi': 1 + 'arguments': 1 + 'main__main': 1 + 'println': 1 + 'strconv__atoi': 1 }) } diff --git a/vlib/v/tests/testdata/trace_calls/with_modules.vv.must_match b/vlib/v/tests/testdata/trace_calls/with_modules.vv.must_match index 8a6d81f25dcd54..3385101e739249 100644 --- a/vlib/v/tests/testdata/trace_calls/with_modules.vv.must_match +++ b/vlib/v/tests/testdata/trace_calls/with_modules.vv.must_match @@ -1,6 +1,6 @@ *> trace * C.main* *> trace * _vinit* -*> trace * os os.init_os_args* +*> trace * builtin arguments/0* *> trace * main main.main/0* *> trace * main main.f1/0* *> trace * main main.f2/0*