Skip to content

Commit 3caeadf

Browse files
committed
cgen,vfmt: support [weak] tags for functions and globals
1 parent 7fba3e6 commit 3caeadf

File tree

9 files changed

+80
-16
lines changed

9 files changed

+80
-16
lines changed

vlib/v/ast/ast.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,7 @@ pub:
638638
mod string
639639
pos token.Position
640640
is_block bool // __global() block
641+
attrs []Attr
641642
pub mut:
642643
fields []GlobalField
643644
end_comments []Comment

vlib/v/fmt/fmt.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,7 @@ pub fn (mut f Fmt) for_stmt(node ast.ForStmt) {
10021002
}
10031003

10041004
pub fn (mut f Fmt) global_decl(node ast.GlobalDecl) {
1005+
f.attrs(node.attrs)
10051006
if node.fields.len == 0 && node.pos.line_nr == node.pos.last_line {
10061007
f.writeln('__global ()')
10071008
return

vlib/v/gen/c/cgen.v

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5853,6 +5853,10 @@ fn (mut g Gen) const_decl_init_later(mod string, name string, expr ast.Expr, typ
58535853

58545854
fn (mut g Gen) global_decl(node ast.GlobalDecl) {
58555855
mod := if g.pref.build_mode == .build_module && g.is_builtin_mod { 'static ' } else { '' }
5856+
mut attributes := ''
5857+
if node.attrs.contains('weak') {
5858+
attributes += 'VWEAK '
5859+
}
58565860
for field in node.fields {
58575861
if g.pref.skip_unused {
58585862
if field.name !in g.table.used_globals {
@@ -5864,7 +5868,7 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
58645868
}
58655869
styp := g.typ(field.typ)
58665870
if field.has_expr {
5867-
g.definitions.write_string('$mod$styp $field.name')
5871+
g.definitions.write_string('$mod$styp $attributes $field.name')
58685872
if field.expr.is_literal() {
58695873
g.definitions.writeln(' = ${g.expr_string(field.expr)}; // global')
58705874
} else {
@@ -5874,9 +5878,9 @@ fn (mut g Gen) global_decl(node ast.GlobalDecl) {
58745878
} else {
58755879
default_initializer := g.type_default(field.typ)
58765880
if default_initializer == '{0}' {
5877-
g.definitions.writeln('$mod$styp $field.name = {0}; // global')
5881+
g.definitions.writeln('$mod$styp $attributes $field.name = {0}; // global')
58785882
} else {
5879-
g.definitions.writeln('$mod$styp $field.name; // global')
5883+
g.definitions.writeln('$mod$styp $attributes $field.name; // global')
58805884
if field.name !in ['as_cast_type_indexes', 'g_memory_block'] {
58815885
g.global_init.writeln('\t$field.name = *($styp*)&(($styp[]){${g.type_default(field.typ)}}[0]); // global')
58825886
}

vlib/v/gen/c/cheaders.v

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,15 @@ const c_common_macros = '
254254
#undef __has_include
255255
#endif
256256
257+
258+
#if !defined(VWEAK)
259+
#define VWEAK __attribute__((weak))
260+
#ifdef _MSC_VER
261+
#undef VWEAK
262+
#define VWEAK
263+
#endif
264+
#endif
265+
257266
#if !defined(VNORETURN)
258267
#if defined(__TINYC__)
259268
#include <stdnoreturn.h>

vlib/v/gen/c/coutput_test.v

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,19 +105,22 @@ fn test_c_must_have_files() ? {
105105
alloptions := '-o - $file_options.vflags'
106106
print(mm('v $alloptions $relpath') +
107107
' matches all line patterns in ${mm(must_have_relpath)} ')
108-
compilation := os.execute('$vexe $alloptions $path')
108+
cmd := '$vexe $alloptions $path'
109+
compilation := os.execute(cmd)
109110
ensure_compilation_succeeded(compilation)
110111
expected_lines := os.read_lines(must_have_path) or { [] }
111112
generated_c_lines := compilation.output.split_into_lines()
112113
mut nmatches := 0
114+
mut failed_patterns := []string{}
113115
for idx_expected_line, eline in expected_lines {
114116
if does_line_match_one_of_generated_lines(eline, generated_c_lines) {
115117
nmatches++
116118
// eprintln('> testing: $must_have_path has line: $eline')
117119
} else {
120+
failed_patterns << eline
118121
println(term.red('FAIL'))
119122
eprintln('$must_have_path:${idx_expected_line + 1}: expected match error:')
120-
eprintln('`$vexe -o - $path` does NOT produce expected line:')
123+
eprintln('`$cmd` did NOT produce expected line:')
121124
eprintln(term.colorize(term.red, eline))
122125
total_errors++
123126
continue
@@ -128,6 +131,11 @@ fn test_c_must_have_files() ? {
128131
} else {
129132
eprintln('> ALL lines:')
130133
eprintln(compilation.output)
134+
eprintln('--------- failed patterns: -------------------------------------------')
135+
for fpattern in failed_patterns {
136+
eprintln(fpattern)
137+
}
138+
eprintln('----------------------------------------------------------------------')
131139
}
132140
}
133141
assert total_errors == 0

vlib/v/gen/c/fn.v

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
187187
}
188188

189189
g.write_v_source_line_info(node.pos)
190-
msvc_attrs := g.write_fn_attrs(node.attrs)
190+
fn_attrs := g.write_fn_attrs(node.attrs)
191191
// Live
192192
is_livefn := node.attrs.contains('live')
193193
is_livemain := g.pref.is_livemain && is_livefn
@@ -291,11 +291,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
291291
g.definitions.write_string('VV_LOCAL_SYMBOL ')
292292
}
293293
}
294-
fn_header := if msvc_attrs.len > 0 {
295-
'$type_name $msvc_attrs ${name}('
296-
} else {
297-
'$type_name ${name}('
298-
}
294+
fn_header := '$type_name $fn_attrs${name}('
299295
g.definitions.write_string(fn_header)
300296
g.write(fn_header)
301297
}
@@ -426,8 +422,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
426422
for attr in node.attrs {
427423
if attr.name == 'export' {
428424
g.writeln('// export alias: $attr.arg -> $name')
429-
calling_conv := if msvc_attrs.len > 0 { '$msvc_attrs ' } else { '' }
430-
export_alias := '$type_name $calling_conv${attr.arg}($arg_str)'
425+
export_alias := '$type_name $fn_attrs${attr.arg}($arg_str)'
431426
g.definitions.writeln('VV_EXPORTED_SYMBOL $export_alias; // exported fn $node.name')
432427
g.writeln('$export_alias {')
433428
g.write('\treturn ${name}(')
@@ -1565,7 +1560,7 @@ fn (g &Gen) fileis(s string) bool {
15651560
}
15661561

15671562
fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
1568-
mut msvc_attrs := ''
1563+
mut fn_attrs := ''
15691564
for attr in attrs {
15701565
match attr.name {
15711566
'inline' {
@@ -1575,6 +1570,12 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
15751570
// since these are supported by GCC, clang and MSVC, we can consider them officially supported.
15761571
g.write('__NOINLINE ')
15771572
}
1573+
'weak' {
1574+
// a `[weak]` tag tells the C compiler, that the next declaration will be weak, i.e. when linking,
1575+
// if there is another declaration of a symbol with the same name (a 'strong' one), it should be
1576+
// used instead, *without linker errors about duplicate symbols*.
1577+
g.write('VWEAK ')
1578+
}
15781579
'noreturn' {
15791580
// a `[noreturn]` tag tells the compiler, that a function
15801581
// *DOES NOT RETURN* to its callsites.
@@ -1641,7 +1642,7 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
16411642
'windows_stdcall' {
16421643
// windows attributes (msvc/mingw)
16431644
// prefixed by windows to indicate they're for advanced users only and not really supported by V.
1644-
msvc_attrs += '__stdcall '
1645+
fn_attrs += '__stdcall '
16451646
}
16461647
'console' {
16471648
g.force_main_console = true
@@ -1651,5 +1652,5 @@ fn (mut g Gen) write_fn_attrs(attrs []ast.Attr) string {
16511652
}
16521653
}
16531654
}
1654-
return msvc_attrs
1655+
return fn_attrs
16551656
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
u64 VWEAK abc = ((u64)(1U)); // global
2+
u64 xyz = ((u64)(2U)); // global
3+
u64 VWEAK weak_1 = ((u64)(4U)); // global
4+
u64 VWEAK weak_2 = ((u64)(5U)); // global
5+
VV_LOCAL_SYMBOL int main__a_weak_function(void);
6+
VV_LOCAL_SYMBOL void main__main(void);
7+
8+
VWEAK VV_LOCAL_SYMBOL int main__a_weak_function(void) {
9+
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// vtest vflags: -enable-globals
2+
3+
[weak]
4+
__global abc = u64(1)
5+
__global xyz = u64(2)
6+
7+
[weak]
8+
__global (
9+
weak_1 = u64(4)
10+
weak_2 = u64(5)
11+
)
12+
13+
[weak]
14+
fn a_weak_function() int {
15+
return 42
16+
}
17+
18+
fn main() {
19+
println('abc: $abc')
20+
println('xyz: $xyz')
21+
println('xyz: $xyz')
22+
println('weak_1: $weak_1')
23+
println('weak_2: $weak_2')
24+
println(a_weak_function())
25+
}

vlib/v/parser/parser.v

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3081,6 +3081,11 @@ fn (mut p Parser) return_stmt() ast.Return {
30813081

30823082
// left hand side of `=` or `:=` in `a,b,c := 1,2,3`
30833083
fn (mut p Parser) global_decl() ast.GlobalDecl {
3084+
mut attrs := []ast.Attr{}
3085+
if p.attrs.len > 0 {
3086+
attrs = p.attrs
3087+
p.attrs = []
3088+
}
30843089
if !p.has_globals && !p.pref.enable_globals && !p.pref.is_fmt && !p.pref.translated
30853090
&& !p.pref.is_livemain && !p.pref.building_v && !p.builtin_mod {
30863091
p.error('use `v -enable-globals ...` to enable globals')
@@ -3173,6 +3178,7 @@ fn (mut p Parser) global_decl() ast.GlobalDecl {
31733178
fields: fields
31743179
end_comments: comments
31753180
is_block: is_block
3181+
attrs: attrs
31763182
}
31773183
}
31783184

0 commit comments

Comments
 (0)