Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/go: go tool rejects #cgo LDFLAGS: -Wl,-rpath,@executable_path/../Frameworks #40559

Open
abeMedia opened this issue Aug 3, 2020 · 10 comments
Open

Comments

@abeMedia
Copy link

@abeMedia abeMedia commented Aug 3, 2020

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

$ go version
go version go1.14.6 darwin/amd64

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=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/adam/Library/Caches/go-build"
GOENV="/Users/adam/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/adam/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.14.6/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.14.6/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/adam/Work/go-test/go.mod"
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/rp/mzkkm6297lv16qf_qgszt3wm0000gn/T/go-build776046366=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

I tried to build a MacOS bundle using dynamically linked libraries. As per convention these are stored in MyApp.app/Contents/Frameworks which requires LC_RPATH to point there.

I added the following flag:

#cgo LDFLAGS: -Wl,-rpath,@executable_path/../Frameworks

What did you expect to see?

go build builds binary with LC_RPATH set to @executable_path/../Frameworks

What did you see instead?

I got an invalid flag error upon running go build.

I also tried replacing @executable_path for $ORIGIN as I would in Linux but then I got an image not found error when running the resulting binary (I assume this isn't supported on MacOS).

@ianlancetaylor ianlancetaylor changed the title cgo: cannot set @rpath to point to Frameworks on darwin cmd/go: go tool rejects #cgo LDFLAGS: -Wl,-rpath,@executable_path/../Frameworks Aug 4, 2020
@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Aug 4, 2020

What does @executable_path mean?

Any fix for this will have to be very careful. For the GNU tools, among others, starting a parameter with @ causes it to be replaced with the contents of a file with the string following the @. So if we do need to handle @executable_path, we need to be careful to only do it in a context in which we know for sure that it won't be replaced by a file. Otherwise all of this flag vetting no longer works.

@abeMedia
Copy link
Author

@abeMedia abeMedia commented Aug 4, 2020

@exexutable_path is like the MacOS version of $ORIGIN on Linux i.e. it is the path that the binary is in at runtime to be able to dynamically link to a library using a relative path.

@abeMedia
Copy link
Author

@abeMedia abeMedia commented Aug 4, 2020

Here's some more info: https://wincent.com/wiki/@executable_path,_@load_path_and_@rpath
While we're at it we should probably add @loader_path as well as @executable_path.

@jayconrod
Copy link
Contributor

@jayconrod jayconrod commented Aug 4, 2020

It looks like @ is specifically forbidden as a leading character since we started validating cgo flags in 1dcb5836.

A wrinkle in all this is that GNU binutils uniformly accept
@foo on the command line to mean "if the file foo exists,
then substitute its contents for @foo in the command line".
So we must also reject @x.go, flags and flag arguments
beginning with @, and so on.

That would still be an issue here. Perhaps we could support specifically @loader_path and @executable_path (nothing else that starts with @), and only allow those when GOOS=darwin?

@abeMedia
Copy link
Author

@abeMedia abeMedia commented Aug 4, 2020

Yes, that sounds like the ideal solution!

@abeMedia
Copy link
Author

@abeMedia abeMedia commented Aug 5, 2020

If someone can point me to where I need to look I'm happy to have a bash at a PR.

@jayconrod
Copy link
Contributor

@jayconrod jayconrod commented Aug 5, 2020

security.go contains regular expressions for allowed flags.

cfg.GOOS may be used to check the target operating system. I don't think we have any regular expressions that are allowed on one platform but not others, but that would be necessary here.

cgo_bad_directives.txt tests this filtering, so that would need to be expanded. See README.txt in that directory for information on the test format.

@snmed
Copy link

@snmed snmed commented Aug 26, 2020

Actually I'm evaluating go for a project on mac and i've a poc that needs to load an external *.dylib from a directory relative to the binary. So I stumbled over @executable_path and this issue with go, so is there any known workaround to get a go binary working that can load a *.dylib from a directory relative to the binary?

Any suggestions would be great, I really would like to use go for the project, but we need to load external C libraries that are not installed in any of the OS search paths.

Update:
Sorry for the post but I've found at least a workaround for that:

  1. Compile my go file with cgo flags
package native

/*
#cgo LDFLAGS: -L../path/to/libs -Wl,-rpath,./libs -lgreeter
#include "path/to/libs/include/greeter.h"
#include <stdlib.h>
*/
import "C"

// Rest of code omitted for brevity
  1. Run go build -o mybinary
  2. Run the install_name_tool
# You can check the correct name for change with otool -L mybinary
install_name_tool -change @rpath/libgreeter.dylib @executable_path/libs/x64/libgreeter.dylib mybinary

I'm not sure if this would break anything else, but so far everything is working as expected. I still hope that the go tooling will allow the @executable_path and @loader_path flags in the future.

@ianlancetaylor
Copy link
Contributor

@ianlancetaylor ianlancetaylor commented Aug 26, 2020

@snmed I'm glad you found a way. You can also set set the CGO_LDFLAGS_ALLOW environment variable. https://golang.org/cmd/go/#hdr-Environment_variables

@snmed
Copy link

@snmed snmed commented Aug 27, 2020

@ianlancetaylor Thanks for your advice, that worked very well with CGO_LDFLAGS_ALLOW="-Wl,-rpath,@executable_path/.*" go build, now only the vscode extensions still shows the invalid flag in #cgo LDFLAGS:-Wl,-rpath,@executable_path/libs maybe there is some setting for that. A workaround for that is to set the variable for the whole development environment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.