golang / go

The Go programming language
https://go.dev
BSD 3-Clause "New" or "Revised" License
124.53k stars 17.72k forks source link

x/mobile: bind framework not found by Xcode #35641

Closed pontusntengnas closed 4 years ago

pontusntengnas commented 5 years ago

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

$ go version
go version go1.13.4 darwin/amd64

Does this issue reproduce with the latest release?

I believe I am on the latest version

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

go env Output
$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/pontusnt/Library/Caches/go-build"
GOENV="/Users/pontusnt/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="MY_GO_PATH"
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/68/_7g0dkds1zx17wwpnmh6k4wr0000gn/T/go-build239061966=/tmp/go-build -gno-record-gcc-switches -fno-common"

What did you do?

gomobile bind -o frameworks/ios/Shared.framework -target=ios

This completed successfully and I got a folder named Shared.Framework with obj-c files.

I drag and drop this into Xcode 11.2.1 (11B500) to use it in my app.

What did you expect to see?

I expected to be able to compile the app and use the framework in my Swift code.

What did you see instead?

The Xcode project no longer compiles, but fails with:

ld: framework not found Shared clang: error: linker command failed with exit code 1 (use -v to see invocation)

I alos tried adding the absolut path to Xcode build setting Framework search paths without success.

Thankful for your help!

andybons commented 5 years ago

@eliasnaur

eliasnaur commented 5 years ago

I alos tried adding the absolut path to Xcode build setting Framework search paths without success.

FWIW, this works for me in Xcode 11.1. Did you add the path to the framework ("/path/to/Shared.framework") or the path to the containing directory ("/path/to")? Xcode expects the latter.

pontusntengnas commented 5 years ago

Thanks for you reply. I tried both of them without success. I really cannot understand why this is happening, there is a framework in that folder. I do not know if it matters but it is just a folder called "Shared.Framework" containing the files and not that "Lego-ish" icon that i have seen some frameworks have.

The app is targeting iOS 13.

I get the exact same issue trying to use the example at go get -d golang.org/x/mobile/example/bind/...

pontusntengnas commented 5 years ago

Am I missing something? I drag n drop the framework into Xcode and it shows up nicely under "Frameworks, Libraries, and embedded content". Then I added the framework search path and tried to build.

eliasnaur commented 5 years ago

I installed Xcode 11.2.1 with no change: the bind example builds successfully.

Thanks for you reply. I tried both of them without success. I really cannot understand why this is happening, there is a framework in that folder. I do not know if it matters but it is just a folder called "Shared.Framework" containing the files and not that "Lego-ish" icon that i have seen some frameworks have.

Did you name the framework "Shared.Framework" or "Shared.framework"?

pontusntengnas commented 5 years ago

I am using "Shared.framework". Capital F gives me an error when binding.

pontusntengnas commented 5 years ago

Okey I got it working now! What was causing the issue was probably my use of the name "Shared" when there where no Go package called "shared" in the files I was binding.

If i omit the naming of the output -o and just bind it, the frameworks gets a different name but this frameworks gets found by Xcode and can be used, awesome!

But then a follow up question, is it not possible to name my framework to something custom?

In my case I am binding 3 different Go packages and want to create a single output framework of that. I do this like this:

gomobile bind -target=ios \ services/departure \ services/search \ presenters

And then the name of the framework becomes Departure, so I guess it just gets the name of the first package argument I give to bind.

So it works but it would be nice to name it something else. And am I doing it right when binding my 3 packages like I do?

Thanks.

eliasnaur commented 5 years ago

Can you send a complete example, with you xcode project ready to use and a set of packages for gomobile bind? The easier it is to reproduce, the better.

@hajimehoshi

pontusntengnas commented 5 years ago

I do not see it is as necessary as it is working for me now. Now I just wonder if I can have a custom name on the .framework output and if the way I am binding the three packages is the correct way to do it, see my above comment.

eliasnaur commented 5 years ago

On Sun Nov 24, 2019 at 9:19 AM Pontus Nilsson Tengnäs wrote:

I do not see it is as necessary as it is working for me now. Now I just wonder if I can have a custom name on the .framework output and if the way I am binding the three packages is the correct way to do it, see my above comment.

The -o option should let you name your framework any way you want, providing the name ends with .framework. That's why I wanted you to provide us with exact reproduction steps.

pontusntengnas commented 5 years ago

Ok I see I will try to find time to make an example and attach here.

arjenveenhuizen commented 4 years ago

We ran into the same issue when upgrading from xcode 10.3 to 11.3.1. Module not found whatever we tried or change on our gomobile bind command line.

Triggered by https://github.com/golang/go/issues/35641#issuecomment-555159238 we finally figured out that we had to change the Framework Search Paths from $(SRCROOT)/../../../path/to/Myframework.framework/ to $(SRCROOT)/../../../path/to/

cooolinx commented 4 years ago

I ran into the same issue today, and thanks to @pontusntengnas , I resolve it by omitting -o option.

I made a simple example and hope it helps @eliasnaur

Env

go env
GO111MODULE="on"
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/guolin/Library/Caches/go-build"
GOENV="/Users/guolin/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="darwin"
GOPATH="/Users/guolin/Work/go"
GOPRIVATE=""
GOPROXY="https://goproxy.io,direct"
GOROOT="/usr/local/Cellar/go/1.14.3/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.14.3/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD="/Users/guolin/Work/colin/go/issue/gogo/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/0k/r288ywwx49zcyx8dpgh5tt5r0000gn/T/go-build768315077=/tmp/go-build -gno-record-gcc-switches -fno-common"

Reproduce

Download the issue.zip file then extract, will get two projects:

  1. Build gogo:
cd gogo
gomobile bind -o gogo.framework -a -ldflags '-s -w' -target=ios gogo.go/fly gogo.go/swim
  1. Open Soso project by Xcode
  2. Add gogo.framework into Xcode project
  3. Press Command+Shift+R to build project will see the error: Framework not found gogo

hope it helps

ToJen commented 4 years ago

It appears that if the framework name is different from the name of the package that was built, this ld not found error will be thrown. In "Example.framework/Versions/A/Modules/module.modulemap" you should see something like this:

framework module "Example" {
    header "ref.h"
    header "Example.objc.h"
    header "Universe.objc.h"
    header "Example.h"

    export *
}

I notice that Example.framework won't work if the root module I'm trying to import is not called Example. So if the first line of that snippet is framework module "Random" you can't import from Example, only Random.

So it kinda makes sense that when @fallenlord removed -o it worked because gomobile will have used the actual package name which you would use when importing. Could this be a bug in gomobile? If so, I think the framework name from the -o flag should take precedence over the golang package name being bound.

hajimehoshi commented 4 years ago

So, fixing modulemap by using the specified framework name would solve this issue? That makes sense. I'll take a look next week.

ToJen commented 4 years ago

That’s my guess. It may need testing on Android and iOS apps. Happy to spend some time contributing to that @hajimehoshi.

gopherbot commented 4 years ago

Change https://golang.org/cl/239237 mentions this issue: cmd/gomobile: use the specified output name for the module name on iOS