Skip to content

Commit fd269ca

Browse files
authored
cgen, dl: add windows dll support, fix (#20447) (#20459)
1 parent be4f717 commit fd269ca

File tree

4 files changed

+43
-9
lines changed

4 files changed

+43
-9
lines changed

examples/dynamic_library_loader/modules/library/library.v

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ module library
1010
// `library__add_1`, if not for the export: tag).
1111
@[export: 'add_1']
1212
pub fn add_1(x int, y int) int {
13-
return my_private_function(x + y)
13+
num := my_private_function(x + y)
14+
println('hello from ${@FN} , num = ${num}')
15+
return num
1416
}
1517

1618
// this function is not exported and will not be visible to external programs.

examples/dynamic_library_loader/use_test.v

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
module main
22

3-
// vtest flaky: true
4-
// vtest retry: 3
53
import os
64
import dl
75

@@ -31,6 +29,7 @@ fn test_can_compile_main_program() {
3129
assert os.is_file(library_file_path)
3230
result := v_compile('run use_shared_library.v')
3331
// dump(result)
32+
assert result.output.contains('hello from add_1 , num = 4')
3433
assert result.output.contains('res: 4')
3534
os.rm(library_file_path) or {}
3635
}

vlib/dl/dl_windows.c.v

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,32 @@ fn C.GetProcAddress(handle voidptr, procname &u8) voidptr
1313

1414
fn C.FreeLibrary(handle voidptr) bool
1515

16+
type FN_vinit_caller = fn ()
17+
18+
type FN_vcleanup_caller = fn ()
19+
1620
// open loads a given module into the address space of the calling process.
1721
pub fn open(filename string, flags int) voidptr {
1822
res := C.LoadLibrary(filename.to_wide())
23+
// Because LoadLibrary has no constructor, this is a workaround
24+
if !isnil(res) {
25+
vinit_caller := FN_vinit_caller(sym(res, '_vinit_caller'))
26+
if !isnil(vinit_caller) {
27+
vinit_caller()
28+
}
29+
}
1930
return res
2031
}
2132

2233
// close frees the loaded a given module.
2334
pub fn close(handle voidptr) bool {
35+
// Because FreeLibrary has no destructor, this is a workaround
36+
if !isnil(handle) {
37+
vcleanup_caller := FN_vcleanup_caller(sym(handle, '_vcleanup_caller'))
38+
if !isnil(vcleanup_caller) {
39+
vcleanup_caller()
40+
}
41+
}
2442
return C.FreeLibrary(handle)
2543
}
2644

vlib/v/gen/c/cgen.v

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5912,8 +5912,9 @@ fn (mut g Gen) write_init_function() {
59125912
g.writeln('\tv__trace_calls__on_call(_SLIT("_vinit"));')
59135913
}
59145914

5915-
if g.use_segfault_handler {
5915+
if g.use_segfault_handler && !g.pref.is_shared {
59165916
// 11 is SIGSEGV. It is hardcoded here, to avoid FreeBSD compilation errors for trivial examples.
5917+
// shared object does not need this
59175918
g.writeln('#if __STDC_HOSTED__ == 1\n\tsignal(11, v_segmentation_fault_handler);\n#endif')
59185919
}
59195920
if g.pref.is_bare {
@@ -5928,7 +5929,10 @@ fn (mut g Gen) write_init_function() {
59285929
// calling module init functions too, just in case they do fail...
59295930
g.write('\tas_cast_type_indexes = ')
59305931
g.writeln(g.as_cast_name_table())
5931-
g.writeln('\tbuiltin_init();')
5932+
if !g.pref.is_shared {
5933+
// shared object does not need this
5934+
g.writeln('\tbuiltin_init();')
5935+
}
59325936

59335937
if g.nr_closures > 0 {
59345938
g.writeln('\t_closure_mtx_init();')
@@ -6020,19 +6024,30 @@ fn (mut g Gen) write_init_function() {
60206024
println(g.out.after(fn_vcleanup_start_pos))
60216025
}
60226026

6023-
needs_constructor := g.pref.is_shared && g.pref.os != .windows
6024-
if needs_constructor {
6027+
if g.pref.is_shared {
60256028
// shared libraries need a way to call _vinit/2. For that purpose,
60266029
// provide a constructor/destructor pair, ensuring that all constants
60276030
// are initialized just once, and that they will be freed too.
60286031
// Note: os.args in this case will be [].
6029-
g.writeln('__attribute__ ((constructor))')
6032+
if g.pref.os == .windows {
6033+
g.writeln('// workaround for windows, export _vinit_caller, let dl.open() call it')
6034+
g.writeln('// NOTE: This is hardcoded in vlib/dl/dl_windows.c.v!')
6035+
g.writeln('VV_EXPORTED_SYMBOL void _vinit_caller();')
6036+
} else {
6037+
g.writeln('__attribute__ ((constructor))')
6038+
}
60306039
g.writeln('void _vinit_caller() {')
60316040
g.writeln('\tstatic bool once = false; if (once) {return;} once = true;')
60326041
g.writeln('\t_vinit(0,0);')
60336042
g.writeln('}')
60346043

6035-
g.writeln('__attribute__ ((destructor))')
6044+
if g.pref.os == .windows {
6045+
g.writeln('// workaround for windows, export _vcleanup_caller, let dl.close() call it')
6046+
g.writeln('// NOTE: This is hardcoded in vlib/dl/dl_windows.c.v!')
6047+
g.writeln('VV_EXPORTED_SYMBOL void _vcleanup_caller();')
6048+
} else {
6049+
g.writeln('__attribute__ ((destructor))')
6050+
}
60366051
g.writeln('void _vcleanup_caller() {')
60376052
g.writeln('\tstatic bool once = false; if (once) {return;} once = true;')
60386053
g.writeln('\t_vcleanup();')

0 commit comments

Comments
 (0)