应兄弟要求研究一下Go语言只发布二进制Module, 方便项目对代码权限进行管理。
查询一些资料,大概在go语言1.13版本支持一个 //go:binary-only-package;但在go v1.21版本实施时,显示:
不再支持。查询了源码后,发现很简单就可以恢复该功能:
C:\Go\src\cmd\go\internal\work\exec.go:
if p.BinaryOnly {
a.Target = "DO NOT USE - using static"
a.built = filepath.Join(p.Dir, "_pkg_"+runtime.GOOS+"_"+runtime.GOARCH+".a")
return nil
/* p.Stale = true
p.StaleReason = "binary-only packages are no longer supported"
if b.IsCmdList {
return nil
}
return errors.New("binary-only packages are no longer supported")*/
}
修改后重新编译出go.exe,尝试了一下,功能恢复。
测试代码:
mymodule用于编译静态库
mymodule2: _pkg_windows_amd64.a 用这个名字主要是为了支持跨平台交叉编译
<== mymodule.go
mylink的go.mod
快速产生静态库:继续对go.exe打补丁
命令行: C:\Go\src\cmd\go\go.exe build -libexport "*\tun*"
cfg.BuildLibExports string
go\internal\work\build.go:
func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
.....
cmd.Flag.Var((*buildvcsFlag)(&cfg.BuildBuildvcs), "buildvcs", "")
cmd.Flag.StringVar(&cfg.BuildLibExports, "libexport", "", "")
...
}
go\internal\work\exec.go:
func (b *Builder) libexports(a *Action) (err error) {
p := a.Package
if cfg.BuildLibExports == "" {
return
}
match, err := path.Match(cfg.BuildLibExports, p.Dir)
if !match || err != nil {
return
}
var pkg bytes.Buffer
pkg_name := filepath.Base(p.Internal.OrigImportPath)
pkg_file := filepath.Join(p.Dir, "pkg_"+pkg_name+".go")
fmt.Fprintf(&pkg, "//go:binary-only-package\n\n")
fmt.Fprintf(&pkg, "package %s\n\n", pkg_name)
for _, v := range p.Internal.RawImports {
fmt.Fprintf(&pkg, "import \"%s\"\n", v)
}
err = b.writeFile(pkg_file, pkg.Bytes())
if err != nil {
return
}
target := filepath.Join(p.Dir, "_pkg_"+runtime.GOOS+"_"+runtime.GOARCH+".a")
fmt.Println("export => "+target)
return copyFile(a.built, target)
}
line 552:
if need == 0 {
return b.libexports(a)
}
defer b.flushOutput(a)
}
go\internal\work\gc.go:
... ...
args = append(args, f)
}
output, err = b.runOut(a, base.Cwd(), nil, args...)
if err == nil {
err = b.libexports(a)
}
return ofile, output, err
}
搞定收工, 测试中将包里面其它的go文件删除,只保留.a和生成的包声明文件,可重新编译生成exe程序