I'm trying to write a tool to automatically set proper dependency versions for pluggable Go programs. As you may know, if a plugin and the main program has different dependency versions, Go would complain "plugin was built with a different version of package XXX".
I dug a little bit, and found src/runtime/plugin.go compare packages by comparing "link time hash" and "run time hash":
for _, pkghash := range md.pkghashes {
if pkghash.linktimehash != *pkghash.runtimehash {
md.bad = true
return "", nil, "plugin was built with a different version of package " + pkghash.modulename
}
}
Further, those hashes are copied from "package fingerprint"(src/cmd/link/internal/ld/symtab.go)
// pkghashes[i].linktimehash
addgostring(ctxt, ldr, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), string(l.Fingerprint[:]))
which is generated by compiler(src/cmd/compile/internal/gc/iexport.go):
// Flush output.
h := md5.New()
wr := io.MultiWriter(out, h)
io.Copy(wr, &hdr)
io.Copy(wr, &p.strings)
io.Copy(wr, &p.data0)
// Add fingerprint (used by linker object file).
// Attach this to the end, so tools (e.g. gcimporter) don't care.
copy(Ctxt.Fingerprint[:], h.Sum(nil)[:])
out.Write(Ctxt.Fingerprint[:])
I'd like to know if there's a way to calculate this "fingerprint" without building plugins, since this "build - test if the plugin is loadable - fix dependency" loop is time-wasting.
Or if there's a way to ensure dependencies are compatible? Force all programs (maybe in different modules and git repos) to have exactly the same version of every dependency seems a little overreaching(or not?)