Skip to content

Commit

Permalink
cgen,builder: fix windows 32bit dll function name mangle (fix #23689) (
Browse files Browse the repository at this point in the history
  • Loading branch information
kbkpbot authored Feb 11, 2025
1 parent 01096bc commit 793487f
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 2 deletions.
7 changes: 7 additions & 0 deletions vlib/v/builder/msvc_windows.v
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,13 @@ pub fn (mut v Builder) cc_msvc() {
// Libs are passed to cl.exe which passes them to the linker
a << real_libs.join(' ')
a << '/link'
if v.pref.is_shared {
// generate a .def for export function names, avoid function name mangle
// must put after the /link flag!
def_name := v.pref.out_name[0..v.pref.out_name.len - 4]
a << '/DEF:' + os.quoted_path('${def_name}.def')
}

a << '/nologo' // NOTE: /NOLOGO is explicitly not recognised!
a << '/OUT:${os.quoted_path(v.pref.out_name)}'
a << r.library_paths()
Expand Down
15 changes: 14 additions & 1 deletion vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,8 @@ mut:
has_debugger bool // $dbg has been used in the code
reflection_strings &map[string]int
defer_return_tmp_var string
vweb_filter_fn_name string // vweb__filter or x__vweb__filter, used by $vweb.html() for escaping strings in the templates, depending on which `vweb` import is used
vweb_filter_fn_name string // vweb__filter or x__vweb__filter, used by $vweb.html() for escaping strings in the templates, depending on which `vweb` import is used
export_funcs []string // for .dll export function names
}

@[heap]
Expand Down Expand Up @@ -403,6 +404,7 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
global_g.embedded_data.write(g.embedded_data) or { panic(err) }
global_g.shared_types.write(g.shared_types) or { panic(err) }
global_g.shared_functions.write(g.channel_definitions) or { panic(err) }
global_g.export_funcs << g.export_funcs

global_g.force_main_console = global_g.force_main_console || g.force_main_console

Expand Down Expand Up @@ -717,6 +719,15 @@ pub fn gen(files []&ast.File, mut table ast.Table, pref_ &pref.Preferences) GenO
helpers.writeln(fn_def)
}
}

if g.pref.is_shared && g.pref.os == .windows && g.export_funcs.len > 0 {
// generate a .def for export function names, avoid function name mangle
def_name := g.pref.out_name[0..g.pref.out_name.len - 4]
dll_name := g.pref.out_name.all_after_last('\\')
file_content := 'LIBRARY ${dll_name}.dll\n\nEXPORTS\n' + g.export_funcs.join('\n')
os.write_file('${def_name}.def', file_content) or { panic(err) }
}

// End of out_0.c

shelpers := helpers.str()
Expand Down Expand Up @@ -6366,6 +6377,7 @@ fn (mut g Gen) write_init_function() {
if g.pref.os != .windows {
g.writeln('__attribute__ ((constructor))')
}
g.export_funcs << '_vinit_caller'
g.writeln('void _vinit_caller() {')
g.writeln('\tstatic bool once = false; if (once) {return;} once = true;')
if g.nr_closures > 0 {
Expand All @@ -6377,6 +6389,7 @@ fn (mut g Gen) write_init_function() {
if g.pref.os != .windows {
g.writeln('__attribute__ ((destructor))')
}
g.export_funcs << '_vcleanup_caller'
g.writeln('void _vcleanup_caller() {')
g.writeln('\tstatic bool once = false; if (once) {return;} once = true;')
g.writeln('\t_vcleanup();')
Expand Down
2 changes: 2 additions & 0 deletions vlib/v/gen/c/fn.v
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
}
if is_liveshared {
if g.pref.os == .windows {
g.export_funcs << impl_fn_name
g.definitions.write_string('VV_EXPORTED_SYMBOL ${type_name} ${impl_fn_name}(')
g.write('VV_EXPORTED_SYMBOL ${type_name} ${impl_fn_name}(')
} else {
Expand Down Expand Up @@ -538,6 +539,7 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) {
if attr.name == 'export' {
weak := if node.attrs.any(it.name == 'weak') { 'VWEAK ' } else { '' }
g.writeln('// export alias: ${attr.arg} -> ${name}')
g.export_funcs << attr.arg
export_alias := '${weak}${type_name} ${fn_attrs}${attr.arg}(${arg_str})'
g.definitions.writeln('VV_EXPORTED_SYMBOL ${export_alias}; // exported fn ${node.name}')
g.writeln('${export_alias} {')
Expand Down
2 changes: 1 addition & 1 deletion vlib/v/tests/create_dll/create_win_dll_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ fn test_create_and_dllmain() {
run_test('clang32')
}
$if msvc {
// run_test('msvc32') // something wrong as it passes when it should fail
run_test('msvc32')
}
}
}
Expand Down

0 comments on commit 793487f

Please sign in to comment.