Reviewers: Hyang-Ah Hana Kim
Sridhar Venkatakrishnan uploaded a change:
https://go-review.googlesource.com/17475
bind: iOS support for multiple packages.
As discussed in golang/go#12245
Usage: gomobile bind [options] a.b.c x.y.z
For ObjC, gomobile bind will generate GoC.{h,m} and GoZ.{h,m}. If
-prefix=App is specified it will generate AppC.{h,m} and AppZ.{h,m}.
Tested on Darwin.
Change-Id: I6af8539a0fb7ed6256f3773efc514eff436014b4
---
M cmd/gomobile/bind.go
M cmd/gomobile/bind_iosapp.go
2 files changed, 100 insertions(+), 48 deletions(-)
diff --git a/cmd/gomobile/bind.go b/cmd/gomobile/bind.go
index 8cdc7d7..a4f7ecf 100644
--- a/cmd/gomobile/bind.go
+++ b/cmd/gomobile/bind.go
@@ -103,9 +103,6 @@
case "android":
return goAndroidBind(pkgs)
case "ios":
- if len(pkgs) > 1 {
- return fmt.Errorf("binding multiple packages not supported for ios")
- }
return goIOSBind(pkgs)
default:
return fmt.Errorf(`unknown -target, %q.`, buildTarget)
@@ -142,47 +139,51 @@
pkgs []*types.Package
}
-func (b *binder) GenObjc(outdir string) error {
+func (b *binder) GenObjc(pkg *types.Package, outdir string) (string,
error) {
const bindPrefixDefault = "Go"
if bindPrefix == "" {
bindPrefix = bindPrefixDefault
}
- name := strings.Title(b.pkgs[0].Name())
+ name := strings.Title(pkg.Name())
bindOption := "-lang=objc"
if bindPrefix != bindPrefixDefault {
bindOption += " -prefix=" + bindPrefix
}
- mfile := filepath.Join(outdir, bindPrefix+name+".m")
- hfile := filepath.Join(outdir, bindPrefix+name+".h")
+ fileBase := bindPrefix + name
+ mfile := filepath.Join(outdir, fileBase+".m")
+ hfile := filepath.Join(outdir, fileBase+".h")
generate := func(w io.Writer) error {
if buildX {
- printcmd("gobind %s -outdir=%s %s", bindOption, outdir,
b.pkgs[0].Path())
+ printcmd("gobind %s -outdir=%s %s", bindOption, outdir, pkg.Path())
}
if buildN {
return nil
}
- return bind.GenObjc(w, b.fset, b.pkgs[0], bindPrefix, false)
+ return bind.GenObjc(w, b.fset, pkg, bindPrefix, false)
}
if err := writeFile(mfile, generate); err != nil {
- return err
+ return "", err
}
generate = func(w io.Writer) error {
if buildN {
return nil
}
- return bind.GenObjc(w, b.fset, b.pkgs[0], bindPrefix, true)
+ return bind.GenObjc(w, b.fset, pkg, bindPrefix, true)
}
if err := writeFile(hfile, generate); err != nil {
- return err
+ return "", err
}
objcPkg, err := ctx.Import("
golang.org/x/mobile/bind/objc", "",
build.FindOnly)
if err != nil {
- return err
+ return "", err
}
- return copyFile(filepath.Join(outdir, "seq.h"),
filepath.Join(objcPkg.Dir, "seq.h"))
+ if err := copyFile(filepath.Join(outdir, "seq.h"),
filepath.Join(objcPkg.Dir, "seq.h")); err != nil {
+ return "", err
+ }
+ return fileBase, nil
}
func (b *binder) GenJava(pkg *types.Package, outdir string) error {
diff --git a/cmd/gomobile/bind_iosapp.go b/cmd/gomobile/bind_iosapp.go
index 9947334..3b1dea9 100644
--- a/cmd/gomobile/bind_iosapp.go
+++ b/cmd/gomobile/bind_iosapp.go
@@ -35,25 +35,33 @@
buildO = title + ".framework"
}
- if err := binder.GenGo(binder.pkgs[0], filepath.Join(tmpdir, "src"));
err != nil {
- return err
+ srcDir := filepath.Join(tmpdir, "src")
+ for _, pkg := range typesPkgs {
+ if err := binder.GenGo(pkg, srcDir); err != nil {
+ return err
+ }
}
mainFile := filepath.Join(tmpdir, "src/iosbin/main.go")
err = writeFile(mainFile, func(w io.Writer) error {
- return iosBindTmpl.Execute(w, "../go_"+name)
+ return iosBindTmpl.Execute(w, pkgs)
})
if err != nil {
return fmt.Errorf("failed to create the binding package for iOS: %v",
err)
}
- if err := binder.GenObjc(filepath.Join(tmpdir, "objc")); err != nil {
- return err
+
+ objcDir := filepath.Join(tmpdir, "objc")
+ fileBases := make([]string, len(typesPkgs))
+ for i, pkg := range typesPkgs {
+ if fileBases[i], err = binder.GenObjc(pkg, objcDir); err != nil {
+ return err
+ }
}
cmd := exec.Command("xcrun", "lipo", "-create")
for _, env := range [][]string{darwinArmEnv, darwinArm64Env,
darwinAmd64Env} {
arch := archClang(getenv(env, "GOARCH"))
- path, err := goIOSBindArchive(name, mainFile, env)
+ path, err := goIOSBindArchive(name, mainFile, env, fileBases)
if err != nil {
return fmt.Errorf("darwin-%s: %v", arch, err)
}
@@ -84,12 +92,35 @@
}
// Copy header file next to output archive.
- err = copyFile(
- headers+"/"+title+".h",
- tmpdir+"/objc/"+bindPrefix+title+".h",
- )
- if err != nil {
- return err
+ headerFiles := make([]string, len(fileBases))
+ if len(fileBases) == 1 {
+ headerFiles[0] = title + ".h"
+ err = copyFile(
+ headers+"/"+title+".h",
+ tmpdir+"/objc/"+bindPrefix+title+".h",
+ )
+ if err != nil {
+ return err
+ }
+ } else {
+ for i, fileBase := range fileBases {
+ headerFiles[i] = fileBase + ".h"
+ err = copyFile(
+ headers+"/"+fileBase+".h",
+ tmpdir+"/objc/"+fileBase+".h")
+ if err != nil {
+ return err
+ }
+ }
+ headerFiles = append(headerFiles, title+".h")
+ err = writeFile(headers+"/"+title+".h", func(w io.Writer) error {
+ return iosBindHeaderTmpl.Execute(w, map[string]interface{}{
+ "pkgs": pkgs, "title": title, "bases": fileBases,
+ })
+ })
+ if err != nil {
+ return err
+ }
}
resources := buildO + "/Versions/A/Resources"
@@ -104,11 +135,11 @@
}
var mmVals = struct {
- Module string
- Header string
+ Module string
+ Headers []string
}{
- Module: title,
- Header: title + ".h",
+ Module: title,
+ Headers: headerFiles,
}
err = writeFile(buildO+"/Versions/A/Modules/module.modulemap", func(w
io.Writer) error {
return iosModuleMapTmpl.Execute(w, mmVals)
@@ -128,11 +159,12 @@
`
var iosModuleMapTmpl =
template.Must(template.New("iosmmap").Parse(`framework module "{{.Module}}"
{
- header "{{.Header}}"
+{{range .Headers}} header "{{.}}"
+{{end}}
export *
}`))
-func goIOSBindArchive(name, path string, env []string) (string, error) {
+func goIOSBindArchive(name, path string, env, fileBases []string) (string,
error) {
arch := getenv(env, "GOARCH")
archive := filepath.Join(tmpdir, name+"-"+arch+".a")
err := goBuild(path, env, "-buildmode=c-archive", "-tags=ios", "-o",
archive)
@@ -140,23 +172,27 @@
return "", err
}
- obj := "gobind-" + name + "-" + arch + ".o"
- cmd := exec.Command(
- getenv(env, "CC"),
- "-I", ".",
- "-g", "-O2",
- "-o", obj,
- "-fobjc-arc", // enable ARC
- "-c", bindPrefix+strings.Title(name)+".m",
- )
- cmd.Args = append(cmd.Args,
strings.Split(getenv(env, "CGO_CFLAGS"), " ")...)
- cmd.Dir = filepath.Join(tmpdir, "objc")
- cmd.Env = append([]string{}, env...)
- if err := runCmd(cmd); err != nil {
- return "", err
+ objs := make([]string, len(fileBases))
+ for i, b := range fileBases {
+ objs[i] = "gobind-" + strings.ToLower(b) + "-" + arch + ".o"
+ cmd := exec.Command(
+ getenv(env, "CC"),
+ "-I", ".",
+ "-g", "-O2",
+ "-o", objs[i],
+ "-fobjc-arc", // enable ARC
+ "-c", b+".m",
+ )
+ cmd.Args = append(cmd.Args,
strings.Split(getenv(env, "CGO_CFLAGS"), " ")...)
+ cmd.Dir = filepath.Join(tmpdir, "objc")
+ cmd.Env = append([]string{}, env...)
+ if err := runCmd(cmd); err != nil {
+ return "", err
+ }
}
- cmd = exec.Command("ar", "-q", "-s", archive, obj)
+ arArgs := append([]string{"-q", "-s", archive}, objs...)
+ cmd := exec.Command("ar", arArgs...)
cmd.Dir = filepath.Join(tmpdir, "objc")
if err := runCmd(cmd); err != nil {
return "", err
@@ -169,10 +205,25 @@
import (
_ "
golang.org/x/mobile/bind/objc"
- _ "{{.}}"
+{{range .}} _ "../go_{{.Name}}"
+{{end}}
)
import "C"
func main() {}
`))
+
+var iosBindHeaderTmpl = template.Must(template.New("ios.h").Parse(`
+// Objective-C API for talking to the following Go packages
+//
+{{range .pkgs}}// {{.ImportPath}}
+{{end}}//
+// File is generated by gomobile bind. Do not edit.
+#ifndef __{{.title}}_H__
+#define __{{.title}}_H__
+
+{{range .bases}}#include "{{.}}.h"
+{{end}}
+#endif
+`))
--
https://go-review.googlesource.com/17475
Gerrit-Reviewer: Hyang-Ah Hana Kim <
hya...@gmail.com>