@squadglad, it is certainly possible to compile go code into a windows DLL, and to use cgo. I've done it successfully.
You'll want to study up on cgo. There are strict rules for keeping go pointers and C pointers apart, and they
Also you are back in the land of malloc() and free(), where it is easy to footgun yourself with a memory leak.
So its not the easiest design to make work. I would recommend generally against it,
if you can avoid it.
Each Go DLL (if there are multiple) will have its own copy of the Go runtime, which sets various signal handlers. The host
process, if Go based, will also have a runtime, and it will set various signal handlers.
Now we're getting into really dicey territory, which I happen to be working with just now,
since signal handling is going to be different on unix and windows, and you'll have to carefully figure out how to
coordinate; this might not even be possible if you don't control the host process.
To say, "there be dragons" on the map, is apt.
I'll go into one particularly other subtle point to illustrate the hazards on Windows of Go DLLs:
The biggest gotcha that isn't well known is that your go DLL on windows will not behave like a normal windows DLL. Once it
is loaded, it cannot be unloaded. The go runtime starts background goroutines (threads), and there
is no way to safely stop these. Hence if you unload a c-shared Go DLL from a windows process,
it will crash the process when those threads try to run their code at addresses that no longer have
code after the DLL unload.
There is a partial workaround. Windows lets you pin a DLL to a process. Then, even if the
host process tries to unload the DLL, that request will be ignored. If you control
the host process code, then you should simply never call FreeLibrary(). I was in
a situation some time back where I did not control the host process, and it would
try to unload my Go based DLL, and thus crash. I had to pin the DLL to the process, so that
the FreeLibrary() call on it becomes a no-op. Something like this:
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved) {
switch(ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
LockLibraryIntoProcessMem(hModule, &g_Self);
// On XP or later you can use GetModuleHandleEx with the
// GET_MODULE_HANDLE_EX_FLAG_PIN flag to prevent unloading of the DLL.
// Really strong. Can't be undone by double FreeLibrary().
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, &g_ModuleName[0], &g_Self2);
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
TCHAR g_ModuleName[1024];
// sets *LocalDllHandle == g_Self, and g_ModuleName, as side effects.
int LockLibraryIntoProcessMem(
HMODULE DllHandle,
HMODULE *LocalDllHandle)
{
if(NULL == LocalDllHandle) {
return ERROR_INVALID_PARAMETER;
}
*LocalDllHandle = NULL;
if(0 == GetModuleFileName(
DllHandle,
g_ModuleName,
sizeof(g_ModuleName)/ sizeof(TCHAR)))
return GetLastError();
*LocalDllHandle = LoadLibrary(g_ModuleName);
if(NULL == *LocalDllHandle)
return GetLastError();
return NO_ERROR;
}
Usually you would unload and re-load a DLL only to upgrade its code
while keeping the host process running. That isn't going to be possible
when the DLL is pinned. You have to restart the host process to
change the go code. At this point, if you control the host code,
you might well conclude that it is easier to just compile the go
code into the host process, and skip the whole DLL thing.
And you would be right.
On Monday, October 3, 2022 at 11:47:49 PM UTC-5 squadglad. wrote:
We have some disk space restrictions and hence we do not want to include the common code as a library in the service. That will increase the size of each exe. We would like to keep the common code and service code independent of each other. Changes in one should not affect or cause recompilation of the other.
On Mon, Oct 3, 2022 at 4:01 PM Brian Candler wrote: