From 74012d48698bd011a5d1b64930a865aca03824e0 Mon Sep 17 00:00:00 2001 From: Aofei Sheng Date: Tue, 16 Jul 2024 08:09:57 +0800 Subject: [PATCH] build(macOS): change full library paths to @rpath --- internal/build/build.go | 34 ++++++++++++++++++++++++++- xtool/llvm/install_name_tool/rpath.go | 4 ++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/internal/build/build.go b/internal/build/build.go index 04732108..393440c8 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -17,6 +17,7 @@ package build import ( + "debug/macho" "fmt" "go/constant" "go/token" @@ -403,11 +404,14 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, llFiles } }() - // add rpath + // add rpath and find libs exargs := make([]string, 0, ctx.nLibdir<<1) + libs := make([]string, 0, ctx.nLibdir*3) for _, arg := range args { if strings.HasPrefix(arg, "-L") { exargs = append(exargs, "-rpath", arg[2:]) + } else if strings.HasPrefix(arg, "-l") { + libs = append(libs, arg[2:]) } } args = append(args, exargs...) @@ -419,6 +423,18 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, llFiles err := ctx.env.Clang().Exec(args...) check(err) + if runtime.GOOS == "darwin" { + dylibDeps := make([]string, 0, len(libs)) + for _, lib := range libs { + dylibDep := findDylibDep(app, lib) + if dylibDep != "" { + dylibDeps = append(dylibDeps, dylibDep) + } + } + err := ctx.env.InstallNameTool().ChangeToRpath(app, dylibDeps...) + check(err) + } + switch mode { case ModeRun: cmd := exec.Command(app, conf.RunArgs...) @@ -706,6 +722,22 @@ func canSkipToBuild(pkgPath string) bool { } } +// findDylibDep finds the dylib dependency in the executable. It returns empty +// string if not found. +func findDylibDep(exe, lib string) string { + file, err := macho.Open(exe) + check(err) + defer file.Close() + for _, load := range file.Loads { + if dylib, ok := load.(*macho.Dylib); ok { + if strings.HasPrefix(filepath.Base(dylib.Name), fmt.Sprintf("lib%s.", lib)) { + return dylib.Name + } + } + } + return "" +} + type none struct{} var hasAltPkg = map[string]none{ diff --git a/xtool/llvm/install_name_tool/rpath.go b/xtool/llvm/install_name_tool/rpath.go index 90f8f103..01fe7b34 100644 --- a/xtool/llvm/install_name_tool/rpath.go +++ b/xtool/llvm/install_name_tool/rpath.go @@ -54,7 +54,7 @@ type Change struct { // Change changes dependent shared library install name. func (p *Cmd) Change(target string, chgs ...Change) error { - args := make([]string, len(chgs)*3+1) + args := make([]string, 0, len(chgs)*3+1) for _, chg := range chgs { args = append(args, "-change", chg.Old, chg.New) } @@ -64,7 +64,7 @@ func (p *Cmd) Change(target string, chgs ...Change) error { // ChangeToRpath changes dependent shared library install name to @rpath. func (p *Cmd) ChangeToRpath(target string, dylibDeps ...string) error { - args := make([]string, len(dylibDeps)*3+1) + args := make([]string, 0, len(dylibDeps)*3+1) for _, dep := range dylibDeps { args = append(args, "-change", dep, "@rpath/"+filepath.Base(dep)) }