Is there a way to call go code from Microsoft Visual Studio C++?
Please Do Not close my question arbitrarily.
This link How to build a library with cgo using visual studio compiler? does not answer my question. It doesn't give a workable solution.
It seems cgo can only be compiled with mingw gcc at this time. https://github.com/golang/go/issues/49080#issuecomment-947865866
So, it seems this problem is unsolvable at this time.
Because mingw c header files are not completely the same as Windows SDK, there will always be some code that won't work.
This is like a "to be" or "not to be" problem.
If you want to call go code from c++, use mingw gcc to compile all your code.
you can't compile cgo with mingw and then use it in Visual Stdudio C++.(Maybe it will work, but there will always be some code that won't work)
All I can found is compile cgo with mingw gcc like this link https://gist.github.com/geraldstanje/4624ac47eb3dec5b8bbe12d4714ed330
But this method has a problem.
If you link the .a library with normal visual c++ code, it faied because .a library contains symbol that visual c++ doesn't know
clang -w *.cpp v2pn.a
LINK : warning LNK4217: symbol '__acrt_iob_func' defined in 'libucrt.lib(_file.obj)' is imported by 'v2pn.a(000005.o)' in function '_cgo_preinit_init'
LINK : warning LNK4286: symbol '__acrt_iob_func' defined in 'libucrt.lib(_file.obj)' is imported by 'v2pn.a(000006.o)'
LINK : warning LNK4217: symbol '_errno' defined in 'libucrt.lib(errno.obj)' is imported by 'v2pn.a(000005.o)' in function '_cgo_beginthread'
v2pn.a(000005.o) : error LNK2019: unresolved external symbol __imp__beginthread referenced in function _cgo_beginthread
v2pn.a(000005.o) : error LNK2019: unresolved external symbol __mingw_vfprintf referenced in function fprintf
v2pn.a(000006.o) : error LNK2001: unresolved external symbol __mingw_vfprintf
a.exe : fatal error LNK1120: 2 unresolved externals
clang: error: linker command failed with exit code 1120 (use -v to see invocation)
If you link the .a library with visual c++ code with mingw gcc,
Well, there will be much more problems. Because the mingw headers are not completely synchronous with windows SDK headers, there will be a lot errors.
Like this one
gcc.exe *.cpp v2pn.a
v2pn.cpp: In function 'void set_dns_by_guid(PCHAR)':
v2pn.cpp:48:5: error: 'DNS_INTERFACE_SETTINGS' was not declared in this scope
48 | DNS_INTERFACE_SETTINGS settings = {DNS_INTERFACE_SETTINGS_VERSION1};
| ^~~~~~~~~~~~~~~~~~~~~~
v2pn.cpp:49:5: error: 'settings' was not declared in this scope
49 | settings.Flags = 0x0002;
| ^~~~~~~~
v2pn.cpp:51:17: error: 'SetInterfaceDnsSettings' was not declared in this scope
51 | DWORD ret = SetInterfaceDnsSettings(interfaceGUID, &settings);
| ^~~~~~~~~~~~~~~~~~~~~~~
This is because the mingw netioapi.h header file is different from the Windows SDK netioapi.h.
And the Windows SDK netioapi.h header file contains the DNS_INTERFACE_SETTINGS declaration, but the mingw netioapi.h header file doesn't.
I finally successfully built both static and shared libraries with MSVC.
First, you need Mingw-w64 for go build
. I would recommend WinLibs port. I have tested with GCC 13.2.0 (with MCF threads) + MinGW-w64 11.0.1 (UCRT) - release 2
. Check your $env:PATH
to make sure there is no other gcc.exe
in your path: where.exe gcc
.
Then you can use go build
to build your go code.
To enable multithread support, use /MD
flag with cl.exe
. That's why you got error unresolved external symbol __imp__beginthread
.
If you using WinLibs's Mingw-w64, you will see error unresolved external symbol vfprintf
instead of __mingw_vfprintf
. That's because you need the library legacy_stdio_definitions.lib
.
But cgo still unable to initialize successfully. You also need some magic code.
#ifdef _MSC_VER
#ifdef __cplusplus
extern "C"
{
#endif
__pragma(comment(lib, "legacy_stdio_definitions.lib"));
void _rt0_amd64_windows_lib();
__pragma(section(".CRT$XCU", read));
__declspec(allocate(".CRT$XCU")) void (*init_lib)() = _rt0_amd64_windows_lib;
__pragma(comment(linker, "/include:init_lib"));
#ifdef __cplusplus
}
#endif
#endif
Add this code to your C/C++ project (do not forget to remove extern "C"
if the code is pure C). Special thanks to ks75vl. Seriously, I have no idea what this code does. But it does work.
You can successfully build your C/C++ project with MSVC now.
For dynamic-link library (.dll
), you also need a .def
file to export your functions. For example:
EXPORTS
_rt0_amd64_windows_lib
MyFunction
And a simple C file for compiling dll:
#include "mylib.h"
__pragma(comment(lib, "legacy_stdio_definitions.lib"));
For detailed commands, here is a example repo. I have written all the commands in readme and pretty simple example code with C, C++, Objective-C, and Swift. Yes, it also works with Clang on macOS. Just check the readme and src/cgo
folder.