Skip to content

Commit 4fcd94a

Browse files
authored
cgen: allow for @[c_extern] fn C.somename(param1 int, param2 &char) &char (#22502)
1 parent ddd5254 commit 4fcd94a

4 files changed

Lines changed: 63 additions & 10 deletions

File tree

vlib/v/gen/c/cgen.v

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ mut:
145145
inside_call bool
146146
inside_curry_call bool // inside foo()()!, foo()()?, foo()()
147147
inside_dump_fn bool
148+
inside_c_extern bool // inside `@[c_extern] fn C.somename(param1 int, param2 voidptr, param3 &char) &char`
148149
expected_fixed_arr bool
149150
inside_for_c_stmt bool
150151
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
@@ -2799,6 +2800,9 @@ fn (mut g Gen) gen_attrs(attrs []ast.Attr) {
27992800
if g.pref.skip_unused {
28002801
return
28012802
}
2803+
if g.inside_c_extern {
2804+
return
2805+
}
28022806
for attr in attrs {
28032807
g.writeln('// Attr: [${attr.name}]')
28042808
}

vlib/v/gen/c/fn.v

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
5050
g.definitions.write_string('#define _v_malloc GC_MALLOC\n')
5151
return
5252
}
53+
5354
if g.pref.parallel_cc {
5455
if node.is_anon {
5556
g.write('static ')
@@ -64,6 +65,16 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
6465
defer {
6566
g.is_direct_array_access = prev_is_direct_array_access
6667
}
68+
69+
// handle `@[c_extern] fn C.some_name() int` declarations:
70+
old_inside_c_extern := g.inside_c_extern
71+
defer {
72+
g.inside_c_extern = old_inside_c_extern
73+
}
74+
if node.language == .c && node.attrs.contains('c_extern') {
75+
g.inside_c_extern = true
76+
}
77+
6778
g.gen_attrs(node.attrs)
6879
mut skip := false
6980
pos := g.out.len
@@ -133,7 +144,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
133144
// as it's only informative, comment it for now
134145
// g.gen_attrs(it.attrs)
135146
if node.language == .c {
136-
return
147+
if !g.inside_c_extern {
148+
return
149+
}
137150
}
138151

139152
old_is_vlines_enabled := g.is_vlines_enabled
@@ -260,7 +273,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
260273
}
261274
g.last_fn_c_name = impl_fn_name
262275

263-
if node.trace_fns.len > 0 {
276+
if !g.inside_c_extern && node.trace_fns.len > 0 {
264277
for trace_fn, call_fn in node.trace_fns {
265278
if trace_fn in g.trace_fn_definitions {
266279
continue
@@ -345,6 +358,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
345358
g.write('${type_name} ${impl_fn_name}(')
346359
}
347360
}
361+
} else if g.inside_c_extern {
362+
c_extern_fn_header := 'extern ${type_name} ${fn_attrs}${name.all_after_first('C__')}('
363+
g.definitions.write_string(c_extern_fn_header)
348364
} else {
349365
if !(node.is_pub || g.pref.is_debug) {
350366
// Private functions need to marked as static so that they are not exportable in the
@@ -380,7 +396,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
380396
&& !g.pref.is_test) || skip {
381397
// Just a function header. Builtin function bodies are defined in builtin.o
382398
g.definitions.writeln(');') // NO BODY')
383-
g.writeln(');')
399+
if !g.inside_c_extern {
400+
g.writeln(');')
401+
}
384402
return
385403
}
386404
if node.params.len == 0 {
@@ -690,7 +708,9 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
690708
mut heap_promoted := []bool{}
691709
if params.len == 0 {
692710
// in C, `()` is untyped, unlike `(void)`
693-
g.write('void')
711+
if !g.inside_c_extern {
712+
g.write('void')
713+
}
694714
}
695715
/// mut is_implicit_ctx := false
696716
// Veb actions defined by user can have implicit context
@@ -702,7 +722,9 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
702722
//}
703723
if g.cur_fn.return_type == typ_veb_result {
704724
// is_implicit_ctx = true
705-
g.write('/*veb*/')
725+
if !g.inside_c_extern {
726+
g.write('/*veb*/')
727+
}
706728
}
707729
}
708730
*/
@@ -721,10 +743,14 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
721743
if param_type_sym.kind == .function && !typ.has_flag(.option) {
722744
info := param_type_sym.info as ast.FnType
723745
func := info.func
724-
g.write('${g.typ(func.return_type)} (*${caname})(')
746+
if !g.inside_c_extern {
747+
g.write('${g.typ(func.return_type)} (*${caname})(')
748+
}
725749
g.definitions.write_string('${g.typ(func.return_type)} (*${caname})(')
726750
g.fn_decl_params(func.params, unsafe { nil }, func.is_variadic, func.is_c_variadic)
727-
g.write(')')
751+
if !g.inside_c_extern {
752+
g.write(')')
753+
}
728754
g.definitions.write_string(')')
729755
fparams << caname
730756
fparamtypes << param_type_name
@@ -748,14 +774,18 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
748774
''
749775
}
750776
s := '${const_prefix}${param_type_name} ${var_name_prefix}${caname}'
751-
g.write(s)
777+
if !g.inside_c_extern {
778+
g.write(s)
779+
}
752780
g.definitions.write_string(s)
753781
fparams << caname
754782
fparamtypes << param_type_name
755783
heap_promoted << heap_prom
756784
}
757785
if i < params.len - 1 {
758-
g.write(', ')
786+
if !g.inside_c_extern {
787+
g.write(', ')
788+
}
759789
g.definitions.write_string(', ')
760790
}
761791

@@ -765,7 +795,9 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
765795
//}
766796
}
767797
if (g.pref.translated && is_variadic) || is_c_variadic {
768-
g.write(', ... ')
798+
if !g.inside_c_extern {
799+
g.write(', ... ')
800+
}
769801
g.definitions.write_string(', ... ')
770802
}
771803
return fparams, fparamtypes, heap_promoted
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern char* GifErrorString(int ecode);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Note: there is NO #include here.
2+
// The V compiler will generate an `extern` declaration for the C function itself.
3+
// If you want to compile it, you need to have installed `libgif-dev` on your system.
4+
// After installing that package (or its equivalent), try for example:
5+
// `./v -cc gcc -cstrict run vlib/v/gen/c/testdata/c_extern_on_C_fn_declarations.vv`
6+
// There should be no error, and you should see a list of error messages, that the library ligif provides.
7+
8+
#flag -lgif
9+
10+
@[c_extern]
11+
fn C.GifErrorString(ecode int) &char
12+
13+
println('hi')
14+
for i in 1 .. 10 {
15+
unsafe { dump(cstring_to_vstring(C.GifErrorString(i))) }
16+
}

0 commit comments

Comments
 (0)