Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ mut:
inside_call bool
inside_curry_call bool // inside foo()()!, foo()()?, foo()()
inside_dump_fn bool
inside_c_extern bool // inside `@[c_extern] fn C.somename(param1 int, param2 voidptr, param3 &char) &char`
expected_fixed_arr bool
inside_for_c_stmt bool
inside_cast_in_heap int // inside cast to interface type in heap (resolve recursive calls)
Expand Down Expand Up @@ -2799,6 +2800,9 @@ fn (mut g Gen) gen_attrs(attrs []ast.Attr) {
if g.pref.skip_unused {
return
}
if g.inside_c_extern {
return
}
for attr in attrs {
g.writeln('// Attr: [${attr.name}]')
}
Expand Down
52 changes: 42 additions & 10 deletions vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
g.definitions.write_string('#define _v_malloc GC_MALLOC\n')
return
}

if g.pref.parallel_cc {
if node.is_anon {
g.write('static ')
Expand All @@ -64,6 +65,16 @@ fn (mut g Gen) fn_decl(node ast.FnDecl) {
defer {
g.is_direct_array_access = prev_is_direct_array_access
}

// handle `@[c_extern] fn C.some_name() int` declarations:
old_inside_c_extern := g.inside_c_extern
defer {
g.inside_c_extern = old_inside_c_extern
}
if node.language == .c && node.attrs.contains('c_extern') {
g.inside_c_extern = true
}

g.gen_attrs(node.attrs)
mut skip := false
pos := g.out.len
Expand Down Expand Up @@ -133,7 +144,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
// as it's only informative, comment it for now
// g.gen_attrs(it.attrs)
if node.language == .c {
return
if !g.inside_c_extern {
return
}
}

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

if node.trace_fns.len > 0 {
if !g.inside_c_extern && node.trace_fns.len > 0 {
for trace_fn, call_fn in node.trace_fns {
if trace_fn in g.trace_fn_definitions {
continue
Expand Down Expand Up @@ -345,6 +358,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
g.write('${type_name} ${impl_fn_name}(')
}
}
} else if g.inside_c_extern {
c_extern_fn_header := 'extern ${type_name} ${fn_attrs}${name.all_after_first('C__')}('
g.definitions.write_string(c_extern_fn_header)
} else {
if !(node.is_pub || g.pref.is_debug) {
// Private functions need to marked as static so that they are not exportable in the
Expand Down Expand Up @@ -380,7 +396,9 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
&& !g.pref.is_test) || skip {
// Just a function header. Builtin function bodies are defined in builtin.o
g.definitions.writeln(');') // NO BODY')
g.writeln(');')
if !g.inside_c_extern {
g.writeln(');')
}
return
}
if node.params.len == 0 {
Expand Down Expand Up @@ -690,7 +708,9 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
mut heap_promoted := []bool{}
if params.len == 0 {
// in C, `()` is untyped, unlike `(void)`
g.write('void')
if !g.inside_c_extern {
g.write('void')
}
}
/// mut is_implicit_ctx := false
// Veb actions defined by user can have implicit context
Expand All @@ -702,7 +722,9 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
//}
if g.cur_fn.return_type == typ_veb_result {
// is_implicit_ctx = true
g.write('/*veb*/')
if !g.inside_c_extern {
g.write('/*veb*/')
}
}
}
*/
Expand All @@ -721,10 +743,14 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
if param_type_sym.kind == .function && !typ.has_flag(.option) {
info := param_type_sym.info as ast.FnType
func := info.func
g.write('${g.typ(func.return_type)} (*${caname})(')
if !g.inside_c_extern {
g.write('${g.typ(func.return_type)} (*${caname})(')
}
g.definitions.write_string('${g.typ(func.return_type)} (*${caname})(')
g.fn_decl_params(func.params, unsafe { nil }, func.is_variadic, func.is_c_variadic)
g.write(')')
if !g.inside_c_extern {
g.write(')')
}
g.definitions.write_string(')')
fparams << caname
fparamtypes << param_type_name
Expand All @@ -748,14 +774,18 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
''
}
s := '${const_prefix}${param_type_name} ${var_name_prefix}${caname}'
g.write(s)
if !g.inside_c_extern {
g.write(s)
}
g.definitions.write_string(s)
fparams << caname
fparamtypes << param_type_name
heap_promoted << heap_prom
}
if i < params.len - 1 {
g.write(', ')
if !g.inside_c_extern {
g.write(', ')
}
g.definitions.write_string(', ')
}

Expand All @@ -765,7 +795,9 @@ fn (mut g Gen) fn_decl_params(params []ast.Param, scope &ast.Scope, is_variadic
//}
}
if (g.pref.translated && is_variadic) || is_c_variadic {
g.write(', ... ')
if !g.inside_c_extern {
g.write(', ... ')
}
g.definitions.write_string(', ... ')
}
return fparams, fparamtypes, heap_promoted
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extern char* GifErrorString(int ecode);
16 changes: 16 additions & 0 deletions vlib/v/gen/c/testdata/c_extern_on_C_fn_declarations.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Note: there is NO #include here.
// The V compiler will generate an `extern` declaration for the C function itself.
// If you want to compile it, you need to have installed `libgif-dev` on your system.
// After installing that package (or its equivalent), try for example:
// `./v -cc gcc -cstrict run vlib/v/gen/c/testdata/c_extern_on_C_fn_declarations.vv`
// There should be no error, and you should see a list of error messages, that the library ligif provides.

#flag -lgif

@[c_extern]
fn C.GifErrorString(ecode int) &char

println('hi')
for i in 1 .. 10 {
unsafe { dump(cstring_to_vstring(C.GifErrorString(i))) }
}