Skip to content

cmd/gomobile: improve support for macOS and Catalyst #70

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

Closed
wants to merge 32 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7f2da24
cmd/gomobile, example/bind, .gitignore: rebase on current master
ydnar Sep 8, 2021
20d0977
cmd/gomobile: fix bind iOS test
ydnar Sep 8, 2021
f7ee8ba
cmd/gomobile: ios,darwin -> apple where appropriate
ydnar Sep 8, 2021
1b1b219
cmd/gomobile: revert debugging comments
ydnar Sep 8, 2021
648790b
cmd/gomobile: address PR feedback
ydnar Sep 8, 2021
4be809c
cmd/gomobile: add test coverage for macos and maccatalyst
ydnar Sep 8, 2021
74d471c
cmd/gomobile: address PR feedback
ydnar Sep 8, 2021
ecb6695
cmd/gomobile: arch == arm64 (PR feedback)
ydnar Sep 8, 2021
b15fb8c
cmd/gomobile: update docs per PR feedback
ydnar Sep 8, 2021
d0a8447
cmd/gomobile: do not end error in period
ydnar Sep 9, 2021
66a0873
cmd/gomobile: change parseBuildTarget to return a slice of targetInfo
ydnar Sep 9, 2021
1b95e9d
cmd/gomobile: rename iosArmNM to appleNM; iosEnv to appleEnv
ydnar Sep 9, 2021
93a5416
cmd/gomobile: pass target with arch to packagesConfig
ydnar Sep 9, 2021
b8cb7b1
cmd/gomobile: update help docs per PR feedback
ydnar Sep 9, 2021
37aff26
cmd/gomobile: remove redundant Apple platform list
ydnar Sep 9, 2021
7471be3
cmd/gomobile: do not run TestAppleBuild without Xcode
ydnar Sep 10, 2021
0c08a47
cmd/gomobile: enable disabled test; fix double loop in runBuildImpl
ydnar Sep 10, 2021
8cec8dd
cmd/gomobile: use correct form for clang -isysroot arg
ydnar Sep 11, 2021
59ffa87
cmd/gomobile: add TODO and potential fix commented out for maccatalys…
ydnar Sep 11, 2021
2afb593
cmd/gomobile: s/ios/apple/i
ydnar Sep 11, 2021
fb52b1e
cmd/gomobile: add additional comments about Mac Catalyst GOOS and bui…
ydnar Sep 11, 2021
a7ac4b9
cmd/gomobile: add additional comment on why GOOS=darwin for -target=m…
ydnar Sep 12, 2021
42bfc79
.gitignore, example/swift-package: example Swift package using gomobile
ydnar Sep 12, 2021
14c8d17
cmd/gomobile: re-add trailing whitespace from CL
ydnar Sep 12, 2021
d5bd4d7
cmd/gomobile: rename files to previous names
ydnar Sep 15, 2021
942f3b8
example/swift-package: remove this for now; re-add in follow up PR
ydnar Sep 15, 2021
fe18852
.gitignore: remove .build for SPM
ydnar Sep 16, 2021
4ca2ca5
cmd/gomobile: remove orderedSet
ydnar Sep 16, 2021
58248db
.gitignore: ignore Xcode user configuration files
ydnar Sep 16, 2021
9e5287b
example/ivy/ios: update README and Xcode project to support xcframewo…
ydnar Sep 16, 2021
b08c472
example/ivy/ios: support maccatalyst
ydnar Sep 16, 2021
01ab28e
.gitignore, example/{bind,ivy}: revert to master
ydnar Sep 16, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ last-change
*.apk
*.app
*.framework
*.xcframework
*.aar
*.iml
.idea
Expand Down
76 changes: 38 additions & 38 deletions cmd/gomobile/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ import (
var cmdBind = &command{
run: runBind,
Name: "bind",
Usage: "[-target android|ios] [-bootclasspath <path>] [-classpath <path>] [-o output] [build flags] [package]",
Usage: "[-target android|" + strings.Join(applePlatforms, "|") + "] [-bootclasspath <path>] [-classpath <path>] [-o output] [build flags] [package]",
Short: "build a library for Android and iOS",
Long: `
Bind generates language bindings for the package named by the import
path, and compiles a library for the named target system.

The -target flag takes a target system name, either android (the
default) or ios.
The -target flag takes either android (the default), or one or more
comma-delimited Apple platforms (` + strings.Join(applePlatforms, ", ") + `).

For -target android, the bind command produces an AAR (Android ARchive)
file that archives the precompiled Java API stub classes, the compiled
Expand All @@ -52,9 +52,9 @@ instruction sets (arm, arm64, 386, amd64). A subset of instruction sets
can be selected by specifying target type with the architecture name. E.g.,
-target=android/arm,android/386.

For -target ios, gomobile must be run on an OS X machine with Xcode
installed. The generated Objective-C types can be prefixed with the -prefix
flag.
For Apple -target platforms, gomobile must be run on an OS X machine with
Xcode installed. The generated Objective-C types can be prefixed with the
-prefix flag.

For -target android, the -bootclasspath and -classpath flags are used to
control the bootstrap classpath and the classpath for Go wrappers to Java
Expand All @@ -76,29 +76,29 @@ func runBind(cmd *command) error {

args := cmd.flag.Args()

targetOS, targetArchs, err := parseBuildTarget(buildTarget)
targets, err := parseBuildTarget(buildTarget)
if err != nil {
return fmt.Errorf(`invalid -target=%q: %v`, buildTarget, err)
}

if bindJavaPkg != "" && targetOS != "android" {
return fmt.Errorf("-javapkg is supported only for android target")
}
if bindPrefix != "" && targetOS != "ios" {
return fmt.Errorf("-prefix is supported only for ios target")
}

if targetOS == "android" {
if isAndroidPlatform(targets[0].platform) {
if bindPrefix != "" {
return fmt.Errorf("-prefix is supported only for Apple targets")
}
if _, err := ndkRoot(); err != nil {
return err
}
} else {
if bindJavaPkg != "" {
return fmt.Errorf("-javapkg is supported only for android target")
}
}

var gobind string
if !buildN {
gobind, err = exec.LookPath("gobind")
if err != nil {
return errors.New("gobind was not found. Please run gomobile init before trying again.")
return errors.New("gobind was not found. Please run gomobile init before trying again")
}
} else {
gobind = "gobind"
Expand All @@ -107,36 +107,34 @@ func runBind(cmd *command) error {
if len(args) == 0 {
args = append(args, ".")
}
pkgs, err := importPackages(args, targetOS)

// TODO(ydnar): this should work, unless build tags affect loading a single package.
// Should we try to import packages with different build tags per platform?
pkgs, err := packages.Load(packagesConfig(targets[0]), args...)
if err != nil {
return err
}

// check if any of the package is main
for _, pkg := range pkgs {
if pkg.Name == "main" {
return fmt.Errorf("binding 'main' package (%s) is not supported", pkg.PkgPath)
return fmt.Errorf(`binding "main" package (%s) is not supported`, pkg.PkgPath)
}
}

switch targetOS {
case "android":
return goAndroidBind(gobind, pkgs, targetArchs)
case "ios":
switch {
case isAndroidPlatform(targets[0].platform):
return goAndroidBind(gobind, pkgs, targets)
case isApplePlatform(targets[0].platform):
if !xcodeAvailable() {
return fmt.Errorf("-target=ios requires XCode")
return fmt.Errorf("-target=%q requires Xcode", buildTarget)
}
return goIOSBind(gobind, pkgs, targetArchs)
return goAppleBind(gobind, pkgs, targets)
default:
return fmt.Errorf(`invalid -target=%q`, buildTarget)
}
}

func importPackages(args []string, targetOS string) ([]*packages.Package, error) {
config := packagesConfig(targetOS)
return packages.Load(config, args...)
}

var (
bindPrefix string // -prefix
bindJavaPkg string // -javapkg
Expand Down Expand Up @@ -212,23 +210,25 @@ func writeFile(filename string, generate func(io.Writer) error) error {
return generate(f)
}

func packagesConfig(targetOS string) *packages.Config {
func packagesConfig(t targetInfo) *packages.Config {
config := &packages.Config{}
// Add CGO_ENABLED=1 explicitly since Cgo is disabled when GOOS is different from host OS.
config.Env = append(os.Environ(), "GOARCH=arm64", "GOOS="+targetOS, "CGO_ENABLED=1")
tags := buildTags
config.Env = append(os.Environ(), "GOARCH="+t.arch, "GOOS="+platformOS(t.platform), "CGO_ENABLED=1")
tags := append(buildTags[:], platformTags(t.platform)...)

if len(tags) > 0 {
config.BuildFlags = []string{"-tags=" + strings.Join(tags, ",")}
}
return config
}

// getModuleVersions returns a module information at the directory src.
func getModuleVersions(targetOS string, targetArch string, src string) (*modfile.File, error) {
func getModuleVersions(targetPlatform string, targetArch string, src string) (*modfile.File, error) {
cmd := exec.Command("go", "list")
cmd.Env = append(os.Environ(), "GOOS="+targetOS, "GOARCH="+targetArch)
cmd.Env = append(os.Environ(), "GOOS="+platformOS(targetPlatform), "GOARCH="+targetArch)

tags := append(buildTags[:], platformTags(targetPlatform)...)

tags := buildTags
// TODO(hyangah): probably we don't need to add all the dependencies.
cmd.Args = append(cmd.Args, "-m", "-json", "-tags="+strings.Join(tags, ","), "all")
cmd.Dir = src
Expand Down Expand Up @@ -281,7 +281,7 @@ func getModuleVersions(targetOS string, targetArch string, src string) (*modfile
}

// writeGoMod writes go.mod file at $WORK/src when Go modules are used.
func writeGoMod(targetOS string, targetArch string) error {
func writeGoMod(dir, targetPlatform, targetArch string) error {
m, err := areGoModulesUsed()
if err != nil {
return err
Expand All @@ -291,8 +291,8 @@ func writeGoMod(targetOS string, targetArch string) error {
return nil
}

return writeFile(filepath.Join(tmpdir, "src", "go.mod"), func(w io.Writer) error {
f, err := getModuleVersions(targetOS, targetArch, ".")
return writeFile(filepath.Join(dir, "src", "go.mod"), func(w io.Writer) error {
f, err := getModuleVersions(targetPlatform, targetArch, ".")
if err != nil {
return err
}
Expand Down
18 changes: 9 additions & 9 deletions cmd/gomobile/bind_androidapp.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"golang.org/x/tools/go/packages"
)

func goAndroidBind(gobind string, pkgs []*packages.Package, androidArchs []string) error {
func goAndroidBind(gobind string, pkgs []*packages.Package, targets []targetInfo) error {
if sdkDir := os.Getenv("ANDROID_HOME"); sdkDir == "" {
return fmt.Errorf("this command requires ANDROID_HOME environment variable (path to the Android SDK)")
}
Expand Down Expand Up @@ -58,12 +58,12 @@ func goAndroidBind(gobind string, pkgs []*packages.Package, androidArchs []strin
}

// Generate binding code and java source code only when processing the first package.
for _, arch := range androidArchs {
if err := writeGoMod("android", arch); err != nil {
for _, t := range targets {
if err := writeGoMod(tmpdir, "android", t.arch); err != nil {
return err
}

env := androidEnv[arch]
env := androidEnv[t.arch]
// Add the generated packages to GOPATH for reverse bindings.
gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, goEnv("GOPATH"))
env = append(env, gopath)
Expand All @@ -76,7 +76,7 @@ func goAndroidBind(gobind string, pkgs []*packages.Package, androidArchs []strin
}
}

toolchain := ndk.Toolchain(arch)
toolchain := ndk.Toolchain(t.arch)
err := goBuildAt(
filepath.Join(tmpdir, "src"),
"./gobind",
Expand All @@ -90,7 +90,7 @@ func goAndroidBind(gobind string, pkgs []*packages.Package, androidArchs []strin
}

jsrc := filepath.Join(tmpdir, "java")
if err := buildAAR(jsrc, androidDir, pkgs, androidArchs); err != nil {
if err := buildAAR(jsrc, androidDir, pkgs, targets); err != nil {
return err
}
return buildSrcJar(jsrc)
Expand Down Expand Up @@ -133,7 +133,7 @@ func buildSrcJar(src string) error {
// aidl (optional, not relevant)
//
// javac and jar commands are needed to build classes.jar.
func buildAAR(srcDir, androidDir string, pkgs []*packages.Package, androidArchs []string) (err error) {
func buildAAR(srcDir, androidDir string, pkgs []*packages.Package, targets []targetInfo) (err error) {
var out io.Writer = ioutil.Discard
if buildO == "" {
buildO = pkgs[0].Name + ".aar"
Expand Down Expand Up @@ -235,8 +235,8 @@ func buildAAR(srcDir, androidDir string, pkgs []*packages.Package, androidArchs
}
}

for _, arch := range androidArchs {
toolchain := ndk.Toolchain(arch)
for _, t := range targets {
toolchain := ndk.Toolchain(t.arch)
lib := toolchain.abi + "/libgojni.so"
w, err = aarwcreate("jni/" + lib)
if err != nil {
Expand Down
Loading