以前から c-archive は作れたけど DLL にするとシンボルが被ったりして上手く DLL が作れなかった。
Big Sky :: golang の Windows 版が buildmode=c-archive をサポートした。
だいぶ時間が掛かった様ですが、ようやく buildmode=c-archive が Windows でも使える様になりました。 cmd/go: -buildmode=c-archive should ...
http://mattn.kaoriya.net/software/lang/go/20160405114638.htm
cmd/go: -buildmode=c-shared should work on windows · Issue #11058 · golang/go · GitHub
https://github.com/golang/go/issues/11058#issuecomment-248330515
-Wl,--allow-multiple-definition
を知らなかった。
package main
import "C"
func main() {
}
//export HelloWorld
func HelloWorld() {
println("Hello golang!")
}
まずこの様なソースコードを c-archive にして libxxx.a を作る。
go build -buildmode=c-archive -o libxxx.a xxx.go
次に HelloWorld をエントリにする def ファイルを作る。
LIBRARY helloworld
EXPORTS
HelloWorld
そして def ファイルを指定して DLL を生成する。この時 -Wl,--allow-multiple-definition
を指定すること。
gcc -m64 -shared -o xxx.dll xxx.def libxxx.a -Wl,--allow-multiple-definition -static -lstdc++ -lwinmm -lntdll -lWs2_32
後は呼び出し元を作って...
package main
import "syscall"
var (
lib = syscall.NewLazyDLL("xxx.dll")
helloworld = lib.NewProc("HelloWorld")
)
func main() {
helloworld.Call()
}
C言語からも
#include <windows.h>
typedef void (*pfn)(void);
int
main(int argc, char* argv[]) {
pfn fn;
HMODULE h = LoadLibrary("xxx.dll");
fn = (pfn) GetProcAddress(h, "HelloWorld");
fn();
return 0;
}
Golang のランタイムが FreeLibrary される事を想定していないので Vim の libcall からは直では呼び出せないけど libcallex-vim を使って解放なしに呼び出せば実行可能。ただしハンドルは持ちっぱなしにしないとリークする。
let xxx = libcallex#load("xxx.dll")
call xxx.call("HelloWorld", [], "")
"call xxx.free()
やったー!これで勝つる!