diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 0f3e968009..2034d7734b 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -401,7 +401,8 @@ fn (mut g Gen) gen_fn_decl(node &ast.FnDecl, skip bool) { for attr in node.attrs { if attr.name == 'export' { g.writeln('// export alias: $attr.arg -> $name') - export_alias := '$type_name ${attr.arg}($arg_str)' + calling_conv := if msvc_attrs.len > 0 { '$msvc_attrs ' } else { '' } + export_alias := '$type_name $calling_conv${attr.arg}($arg_str)' g.definitions.writeln('VV_EXPORTED_SYMBOL $export_alias; // exported fn $node.name') g.writeln('$export_alias {') g.write('\treturn ${name}(') diff --git a/vlib/v/tests/create_dll/create_win_dll.v b/vlib/v/tests/create_dll/create_win_dll.v new file mode 100644 index 0000000000..02ef5d68e1 --- /dev/null +++ b/vlib/v/tests/create_dll/create_win_dll.v @@ -0,0 +1,34 @@ +module test + +fn C._vinit(int, voidptr) +fn C.GC_INIT() + +const ( + foo = 1 + bar = (foo << 5) + 9 +) + +[export: Tatltuae] +pub fn test_tatltuae() int { + return test.foo + test.bar +} + +[export: DllMain] +[windows_stdcall] +fn main(hinst voidptr, fdw_reason int, lp_reserved voidptr) bool { + match fdw_reason { + C.DLL_PROCESS_ATTACH { + $if static_boehm ? { + C.GC_INIT() + } + C._vinit(0, 0) + } + C.DLL_THREAD_ATTACH {} + C.DLL_THREAD_DETACH {} + C.DLL_PROCESS_DETACH {} + else { + return false + } + } + return true +} diff --git a/vlib/v/tests/create_dll/create_win_dll_test.v b/vlib/v/tests/create_dll/create_win_dll_test.v new file mode 100644 index 0000000000..0c359dabce --- /dev/null +++ b/vlib/v/tests/create_dll/create_win_dll_test.v @@ -0,0 +1,61 @@ +import dl +import os + +type Func = fn () int + +fn run_test(cc_used string) { + cc_flag := match cc_used { + 'tcc64' { '-cc tcc' } + 'gcc64' { '-cc gcc' } + 'clang64' { '-cc clang' } + 'msvc64' { '-cc msvc' } + 'tcc32' { '-cc tcc -m32 -d no_backtrace' } + 'gcc32' { '-cc gcc -m32' } + 'clang32' { '-cc clang -m32' } + 'msvc32' { '-cc msvc -m32' } + else { '' } + } + + assert os.system('"${@VEXE}" $cc_flag -o create_win_${cc_used}.dll -shared create_win_dll.v') == 0 + assert os.exists('create_win_${cc_used}.dll') + handle := dl.open('create_win_${cc_used}.dll', 0) + assert handle != 0 + test := Func(dl.sym(handle, 'Tatltuae')) + assert test() == 42 + assert test() != 666 + // dl.close(handle) // works for gcc, clang and msvc but crashes with tcc +} + +fn test_create_and_dllmain() { + os.chdir(os.dir(@FILE)) or {} + $if windows { + $if x64 { + $if tinyc { + run_test('tcc64') + } + $if gcc { + run_test('gcc64') + } + $if clang { + run_test('clang64') + } + $if msvc { + run_test('msvc64') + } + } + $if x32 { + $if tinyc { + run_test('tcc32') + } + $if gcc { + run_test('gcc32') + } + $if clang { + run_test('clang32') + } + $if msvc { + // run_test('msvc32') // something wrong as it passes when it should fail + } + } + } +}