From 0ce6806d28271a51f00f1b17c43968d48967c860 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Wed, 15 Apr 2026 05:54:11 +0300 Subject: [PATCH] cgen: enable referencing C global variables from V code (fixes #22691) --- doc/docs.md | 5 ++++ vlib/v/checker/checker.v | 29 ++++++++++++++++++ vlib/v/gen/c/assign.v | 19 ++++++------ vlib/v/gen/c/cgen.v | 30 +++++++++++++++++-- ..._file_for_c_global_fixed_array_reference.c | 1 + .../c_global_fixed_array_reference.out | 5 ++++ .../c_global_fixed_array_reference.vv | 14 +++++++++ 7 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 vlib/v/gen/c/testdata/c_file_for_c_global_fixed_array_reference.c create mode 100644 vlib/v/gen/c/testdata/c_global_fixed_array_reference.out create mode 100644 vlib/v/gen/c/testdata/c_global_fixed_array_reference.vv diff --git a/doc/docs.md b/doc/docs.md index b0e5092bf..d6b31f352 100644 --- a/doc/docs.md +++ b/doc/docs.md @@ -8085,6 +8085,11 @@ f := C.name_of_the_C_function(123, c'here is some C style string', 1.23) dump(f) ``` +C globals can be exposed on the V side too. Use `@[c_extern] __global name C.Type` +when you want to redeclare an external symbol explicitly. When the type already comes +from the V context, direct references like `buffer = C.buffer` and `[4]u8(C.buffer)` +can be used as well. + **Example of using a C function from stdio, by redeclaring it on the V side** ```v #include diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 7398cefcb..792ea4779 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -5037,6 +5037,8 @@ fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type { old_expected_type := c.expected_type if c.table.sym(base_to_type).kind == .sum_type && node.expr is ast.ArrayInit { c.expected_type = ast.void_type + } else if node.expr is ast.Ident && node.expr.language == .c { + c.expected_type = base_to_type } expr_is_ident_or_cast := node.expr is ast.Ident || node.expr is ast.CastExpr node.expr_type = c.expr(mut node.expr) // type to be casted @@ -6333,6 +6335,33 @@ fn (mut c Checker) ident(mut node ast.Ident) ast.Type { if x := c.table.global_scope.find_const(node.name) { return x.typ } + expected_c_type := c.expected_type.clear_option_and_result() + if c.inside_assign && expected_c_type != ast.void_type + && expected_c_type != ast.none_type { + if obj := c.file.global_scope.find_global(node.name) { + node.kind = .global + node.info = ast.IdentVar{ + typ: obj.typ + } + node.obj = *obj + return obj.typ + } + c_global := ast.GlobalField{ + name: node.name + pos: node.pos + typ_pos: node.pos + typ: expected_c_type + language: .c + is_extern: true + } + c.table.global_scope.register(c_global) + node.kind = .global + node.info = ast.IdentVar{ + typ: expected_c_type + } + node.obj = c_global + return expected_c_type + } c_name := node.name.all_after('C.') if !c.pref.translated && !c.file.is_translated && c_name.len > 0 && c_name[0] >= `a` && c_name[0] <= `z` && c_name !in c.table.export_names.values() { diff --git a/vlib/v/gen/c/assign.v b/vlib/v/gen/c/assign.v index 2a2f739b2..962ea26fb 100644 --- a/vlib/v/gen/c/assign.v +++ b/vlib/v/gen/c/assign.v @@ -1391,8 +1391,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { g.expr(right) g.writeln(';') } else { - right := val as ast.Ident - v_var = right.name + v_var = g.expr_string(val) } pos := g.out.len g.expr(left) @@ -1795,7 +1794,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { g.is_shared = var_type.has_flag(.shared_f) if is_fixed_array_init && !has_val { if val is ast.ArrayInit { - g.array_init(val, c_name(ident.name)) + g.array_init(val, g.ident_cname(ident)) } else { g.write('{0}') } @@ -1829,7 +1828,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { g.expr_with_opt_or_block(val, val_type, left, var_type, is_option_auto_heap) } else if val is ast.ArrayInit { - cvar_name := c_name(ident.name) + cvar_name := g.ident_cname(ident) if val.is_fixed && ident.name in g.defer_vars { g.go_before_last_stmt() g.empty_line = true @@ -1842,7 +1841,7 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) { } } else if val is ast.ParExpr && val.expr is ast.ArrayInit { array_init := val.expr as ast.ArrayInit - cvar_name := c_name(ident.name) + cvar_name := g.ident_cname(ident) if array_init.is_fixed && ident.name in g.defer_vars { g.go_before_last_stmt() g.empty_line = true @@ -2269,20 +2268,20 @@ fn (mut g Gen) gen_cross_var_assign(node &ast.AssignStmt) { } if left_sym.info is ast.FnType { g.write_fn_ptr_decl(&left_sym.info, '_var_${left.pos.pos}') - g.writeln(' = ${anon_ctx}${c_name(left.name)};') + g.writeln(' = ${anon_ctx}${g.ident_cname(left)};') } else if left_is_auto_deref_var { styp := g.styp(left_typ).trim('*') if left_sym.kind == .array { - g.writeln('${styp} _var_${left.pos.pos} = builtin__array_clone(${anon_ctx}${c_name(left.name)});') + g.writeln('${styp} _var_${left.pos.pos} = builtin__array_clone(${anon_ctx}${g.ident_cname(left)});') } else { - g.writeln('${styp} _var_${left.pos.pos} = *${anon_ctx}${c_name(left.name)};') + g.writeln('${styp} _var_${left.pos.pos} = *${anon_ctx}${g.ident_cname(left)};') } } else { styp := g.styp(left_typ) if left_sym.kind == .array { - g.writeln('${styp} _var_${left.pos.pos} = builtin__array_clone(&${anon_ctx}${c_name(left.name)});') + g.writeln('${styp} _var_${left.pos.pos} = builtin__array_clone(&${anon_ctx}${g.ident_cname(left)});') } else { - g.writeln('${styp} _var_${left.pos.pos} = ${anon_ctx}${c_name(left.name)};') + g.writeln('${styp} _var_${left.pos.pos} = ${anon_ctx}${g.ident_cname(left)};') } } } diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index e2b56a4e6..f5991587b 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -6653,12 +6653,32 @@ fn (mut g Gen) check_var_scope(obj ast.Var, node_pos int) bool { return true } +@[inline] +fn (g &Gen) var_cname(obj ast.Var) string { + base_name := c_name(obj.name) + if c_global := g.table.global_scope.find_global('C.${obj.name}') { + if c_global.pos.file_idx >= 0 && int(c_global.pos.file_idx) < g.table.filelist.len + && g.table.filelist[c_global.pos.file_idx] == g.file.path { + return '${base_name}__local_${obj.pos.pos}' + } + } + return base_name +} + +@[inline] +fn (g &Gen) ident_cname(node ast.Ident) string { + if node.obj is ast.Var { + return g.var_cname(node.obj) + } + return c_name(node.name) +} + @[inline] fn (g &Gen) debugger_var_cname(obj ast.Var) string { if obj.is_inherited { - return '${closure_ctx}->${c_name(obj.name)}' + return '${closure_ctx}->${g.var_cname(obj)}' } - return c_name(obj.name) + return g.var_cname(obj) } // debugger_stmt writes the call to V debugger REPL @@ -7318,7 +7338,11 @@ fn (mut g Gen) ident(node ast.Ident) { g.write(util.no_dots(node.name[2..])) return } - mut name := if node.kind == .function { c_fn_name(node.name) } else { c_name(node.name) } + mut name := if node.kind == .function { + c_fn_name(node.name) + } else { + g.ident_cname(node) + } if node.kind == .function { if func := g.table.find_fn(node.name) { if func.mod == 'builtin' && !name.starts_with('builtin__') && func.language != .c { diff --git a/vlib/v/gen/c/testdata/c_file_for_c_global_fixed_array_reference.c b/vlib/v/gen/c/testdata/c_file_for_c_global_fixed_array_reference.c new file mode 100644 index 000000000..e74e50185 --- /dev/null +++ b/vlib/v/gen/c/testdata/c_file_for_c_global_fixed_array_reference.c @@ -0,0 +1 @@ +char buffer[4] = {65, 66, 67, 68}; diff --git a/vlib/v/gen/c/testdata/c_global_fixed_array_reference.out b/vlib/v/gen/c/testdata/c_global_fixed_array_reference.out new file mode 100644 index 000000000..6ca891b09 --- /dev/null +++ b/vlib/v/gen/c/testdata/c_global_fixed_array_reference.out @@ -0,0 +1,5 @@ +4 +65 +68 +66 +67 diff --git a/vlib/v/gen/c/testdata/c_global_fixed_array_reference.vv b/vlib/v/gen/c/testdata/c_global_fixed_array_reference.vv new file mode 100644 index 000000000..f206893ac --- /dev/null +++ b/vlib/v/gen/c/testdata/c_global_fixed_array_reference.vv @@ -0,0 +1,14 @@ +module main + +#include "@DIR/c_file_for_c_global_fixed_array_reference.c" + +fn main() { + mut buffer := [4]u8{} + buffer = C.buffer + cast_buffer := [4]u8(C.buffer) + println(buffer.len) + println(buffer[0]) + println(buffer[3]) + println(cast_buffer[1]) + println(cast_buffer[2]) +} -- 2.39.5