Skip to content

Commit de33470

Browse files
committed
v3: avoid Linux C header symbol conflicts
1 parent 2f37ab1 commit de33470

4 files changed

Lines changed: 44 additions & 1 deletion

File tree

vlib/v3/gen/c/cleanc.v

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,7 @@ mut:
337337
inlined_c_fns map[string]bool
338338
inlined_c_declared_fns map[string]bool
339339
possibly_active_c_macros map[string]bool
340+
unscanned_c_header_files map[string]bool
340341
inlined_c_static_fns map[string]bool
341342
cache_omitted_c_fns map[string]bool
342343
preserved_header_files_seen map[string]bool
@@ -1030,6 +1031,7 @@ pub fn FlatGen.new() FlatGen {
10301031
inlined_c_fns: map[string]bool{}
10311032
inlined_c_declared_fns: map[string]bool{}
10321033
possibly_active_c_macros: map[string]bool{}
1034+
unscanned_c_header_files: map[string]bool{}
10331035
inlined_c_static_fns: map[string]bool{}
10341036
cache_omitted_c_fns: map[string]bool{}
10351037
preserved_header_files_seen: map[string]bool{}
@@ -2616,6 +2618,7 @@ pub fn (mut g FlatGen) gen_with_used_options(a &flat.FlatAst, used_fns map[strin
26162618
g.inlined_c_fns.clear()
26172619
g.inlined_c_declared_fns.clear()
26182620
g.possibly_active_c_macros.clear()
2621+
g.unscanned_c_header_files.clear()
26192622
g.inlined_c_static_fns.clear()
26202623
g.cache_omitted_c_fns.clear()
26212624
g.preserved_header_files_seen.clear()
@@ -4421,6 +4424,10 @@ fn (mut g FlatGen) collect_c_directive(module_name string, node flat.Node, sourc
44214424
}
44224425
} else if c_should_preserve_uninlined_include(include_arg) || (g.cache_split
44234426
&& include_arg in ['<mach/mach.h>', '<mach/task.h>', '<mach/mach_time.h>']) {
4427+
// The preserved header is emitted before generated externs. When V cannot
4428+
// inspect it, avoid guessing prototypes that may differ in const qualifiers
4429+
// or other ABI details from the real declaration.
4430+
g.unscanned_c_header_files[source_file] = true
44244431
g.collect_preserved_c_fns(c_preserved_system_include_declared_fns(include_arg))
44254432
g.collect_preserved_c_structs(c_preserved_system_include_struct_names(include_arg))
44264433
g.collect_preserved_c_typedef_names(c_preserved_system_include_typedef_names(include_arg))

vlib/v3/gen/c/fn.v

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,9 @@ const c_main_runtime_shadow_fn_names = {
10531053
}
10541054

10551055
fn (g &FlatGen) main_runtime_shadow_fn_c_name(module_name string, name string) ?string {
1056-
if !c_main_runtime_shadow_fn_names[name] && !g.inlined_c_typedef_names[name] {
1056+
c_type_name := !isnil(g.tc)
1057+
&& ('C.${name}' in g.tc.structs || 'C.${name}' in g.tc.c_typedef_structs)
1058+
if !c_main_runtime_shadow_fn_names[name] && !g.inlined_c_typedef_names[name] && !c_type_name {
10571059
return none
10581060
}
10591061
if module_name.len == 0 || module_name == 'main' {
@@ -15094,6 +15096,9 @@ fn (g &FlatGen) c_extern_decl_is_cached_object_fallback(cfn string) bool {
1509415096
}
1509515097

1509615098
fn (g &FlatGen) should_emit_c_extern_decl_from_file(cfn string, source_file string) bool {
15099+
if g.unscanned_c_header_files[source_file] {
15100+
return false
15101+
}
1509715102
// builtin/cfns.c.v declares the static vschannel helper supplied by its C header.
1509815103
// A user C.request declaration is unrelated and still needs an extern prototype.
1509915104
if cfn == 'request' && source_file.replace('\\', '/').ends_with('/builtin/cfns.c.v') {

vlib/v3/gen/c/names_test.v

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,19 @@ fn test_main_function_is_prefixed_when_preserved_c_header_owns_typedef_name() {
111111
assert g.fn_c_name_in_module('database', 'sqlite3') == 'database__sqlite3'
112112
}
113113

114+
fn test_main_function_is_prefixed_when_declared_c_type_owns_name() {
115+
mut a := flat.FlatAst.new()
116+
mut tc := types.TypeChecker.new(&a)
117+
mut g := FlatGen.new()
118+
g.a = &a
119+
g.tc = &tc
120+
tc.structs['C.sqlite3'] = []types.StructField{}
121+
122+
assert g.fn_c_name_in_module('main', 'sqlite3') == 'main__sqlite3'
123+
assert g.main_runtime_shadow_fn_c_name('main', 'sqlite3') or { '' } == 'main__sqlite3'
124+
assert g.fn_c_name_in_module('database', 'sqlite3') == 'database__sqlite3'
125+
}
126+
114127
fn test_voidptr_method_value_arg_does_not_panic_for_alias_to_voidptr() {
115128
mut a := flat.FlatAst.new()
116129
mut tc := types.TypeChecker.new(&a)

vlib/v3/gen/c/source_directive_test.v

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ fn test_postinclude_header_does_not_suppress_earlier_c_prototype() {
7777
}, source, false)
7878
assert 'postinclude_api' !in postinclude_g.inlined_c_declared_fns
7979
assert '#include "${header}"' in postinclude_g.postinclude_directives
80+
assert postinclude_g.should_emit_c_extern_decl_from_file('postinclude_api', source)
8081

8182
mut preinclude_g := FlatGen.new()
8283
preinclude_g.collect_c_directive('main', flat.Node{
@@ -87,6 +88,23 @@ fn test_postinclude_header_does_not_suppress_earlier_c_prototype() {
8788
assert 'postinclude_api' in preinclude_g.inlined_c_declared_fns
8889
}
8990

91+
fn test_unscanned_preserved_header_suppresses_guessed_externs_from_its_source_file() {
92+
root := os.join_path(os.vtmp_dir(), 'v3_unscanned_header_${os.getpid()}')
93+
source := os.join_path(root, 'main.v')
94+
missing_header := os.join_path(root, 'compiler-search-only', 'api.h')
95+
96+
mut g := FlatGen.new()
97+
g.collect_c_directive('main', flat.Node{
98+
kind: .directive
99+
value: 'include'
100+
typ: '"${missing_header}"'
101+
}, source, false)
102+
103+
assert source in g.unscanned_c_header_files
104+
assert !g.should_emit_c_extern_decl_from_file('header_api', source)
105+
assert g.should_emit_c_extern_decl_from_file('header_api', os.join_path(root, 'other.v'))
106+
}
107+
90108
fn test_preinclude_carries_macro_state_to_later_preincludes() {
91109
root := os.join_path(os.vtmp_dir(), 'v3_preinclude_macro_state_${os.getpid()}')
92110
os.rmdir_all(root) or {}

0 commit comments

Comments
 (0)