go: cmd/go: dylib on macos with rpath fails to run with go run/test

What version of Go are you using (go version)?

$ go version
go version go1.13.6 darwin/amd64

What version of macOS are you using (go version)?

$ sw_vers -productVersion
10.15.2

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="auto"
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/eric/Library/Caches/go-build"
GOENV="/Users/eric/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/eric/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/v4/m6f6w8h54j58bp8q4h_138180000gn/T/go-build216040480=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

When trying to run a simple go source file that links against an rpath based dylib, it fails to run with either go run or go test on 1.13.6. However, doing go build followed by running the executable works fine. It also works fine when I build go and test it from the go1.13.6 tag. It also works in go 1.13.5 but from looking at the commits between the two, I cannot find an issue. This leads me to believe that however the 1.13.6 was built on google servers introduced some kind of issue.

A repro with a makefile is located at https://github.com/edaniels/go1136dylibissue.

What did you expect to see?

I expected to see a log output of 2 from:

LD_LIBRARY_PATH=`pwd`/dylib/lib go run github.com/edaniels/go1136dylibissue/cmd

What did you see instead?

dyld: Library not loaded: @rpath/libfoo.dylib
  Referenced from: /var/folders/v4/m6f6w8h54j58bp8q4h_138180000gn/T/go-build330381377/b001/exe/cmd
  Reason: image not found
signal: abort trap

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 6
  • Comments: 20 (16 by maintainers)

Commits related to this issue

Most upvoted comments

That first one might possibly fix this issue. I don’t think we would want the second one. We don’t want to actually allow unvalidated libraries to be run by the go tool. This entitlement is one that Go-generated binaries would need (assuming they were hardened, which they aren’t at the moment) to use LD_LIBRARY_PATH successfully.

I don’t think that’s really the right way to go though. It’s kind of an accident that the go tool passes environment variables unmolested through to temporary executables. It’s asking for issues related to the same environment variable meaning different things in the go binary and the user’s binary. (e.g. what if you wanted a different CC value for the go tool and the user’s binary? Can’t do that with CC=gcc go run.)

I think it is reasonable to ask that if you want to pass environment variables to a program written in Go, you have to build and run as separate steps.

You might be able to use the -exec flag to go run to introduce an environment variable at the right time. Something like

go run -exec "env LD_LIBRARY_PATH=/my/library/path" myprogram.go

Instead of finding a way to pass LD_LIBRARY_PATH through, another workaround appears to be hardcoding the rpath of the resultant binary using the -rpath linker option. This also avoids having to build test binaries and run them ourselves. For instance:

CGO_LDFLAGS='-Wl,-rpath,/path/to/library' go test ./pkg

where /path/to/library is the value of LD_LIBRARY_PATH. I haven’t tried, but this should also work well with the GoLand IDE.

Edit: Unfortunately, this only works if the external linker is used… i.e., if ./pkg itself uses cgo. If ./pkg itself doesn’t use cgo but one of its dependencies does, you may need to add -ldflags=-linkmode=external – or you could use the -exec trick as mentioned before.

Yep -exec does work. I think in this case, it makes sense to build up a whitelist of environment variables and have LD_LIBRARY_PATH be in it via entitlement.