[mobile] bind: iOS support for multiple packages.

122 views
Skip to first unread message

Sridhar Venkatakrishnan (Gerrit)

unread,
Dec 6, 2015, 9:41:10 PM12/6/15
to Hyang-Ah Hana Kim, Ian Lance Taylor, golang-co...@googlegroups.com
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>

Hyang-Ah Hana Kim (Gerrit)

unread,
Dec 8, 2015, 9:14:36 AM12/8/15
to Sridhar Venkatakrishnan, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
Hyang-Ah Hana Kim has posted comments on this change.

bind: iOS support for multiple packages.

Patch Set 1:

(1 comment)

nice.

https://go-review.googlesource.com/#/c/17475/1/cmd/gomobile/bind_iosapp.go
File cmd/gomobile/bind_iosapp.go:

Line 176: for i, b := range fileBases {
can't we compile all source files in one command by supplying the list of
filenames?


--
https://go-review.googlesource.com/17475
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
Gerrit-HasComments: Yes

Sridhar Venkatakrishnan (Gerrit)

unread,
Dec 8, 2015, 11:37:53 AM12/8/15
to Hyang-Ah Hana Kim, golang-co...@googlegroups.com
Sridhar Venkatakrishnan has posted comments on this change.

bind: iOS support for multiple packages.

Patch Set 1:

(1 comment)

https://go-review.googlesource.com/#/c/17475/1/cmd/gomobile/bind_iosapp.go
File cmd/gomobile/bind_iosapp.go:

Line 176: for i, b := range fileBases {
> can't we compile all source files in one command by supplying the list of
> f
Yes we can. However, my understanding is that in this case we cannot
control the naming of the object files. We will need to remove the -o
<object_file> option. clang will then generate object files named
Go<PackageName>.o.

I didn't want to change the object file naming convention, but I can change
it to a single execution. Let me know what you prefer.


--
https://go-review.googlesource.com/17475
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
Gerrit-Reviewer: Sridhar Venkatakrishnan <sri...@laddoo.net>
Gerrit-HasComments: Yes

Hyang-Ah Hana Kim (Gerrit)

unread,
Dec 8, 2015, 12:18:48 PM12/8/15
to Sridhar Venkatakrishnan, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
Hyang-Ah Hana Kim has posted comments on this change.

bind: iOS support for multiple packages.

Patch Set 1:

(1 comment)

https://go-review.googlesource.com/#/c/17475/1/cmd/gomobile/bind_iosapp.go
File cmd/gomobile/bind_iosapp.go:

Line 176: for i, b := range fileBases {
> Yes we can. However, my understanding is that in this case we cannot
> contro
I didn't know clang doesn't accept -o if multiple input files are supplied.
I cannot find it from the manual.

It's unclear to me why the names of these objects matter either. I thought
we only care about the final archive name. Maybe I am missing something.


--
https://go-review.googlesource.com/17475
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>

Sridhar Venkatakrishnan (Gerrit)

unread,
Dec 9, 2015, 6:25:38 AM12/9/15
to Hyang-Ah Hana Kim, golang-co...@googlegroups.com
Reviewers: Hyang-Ah Hana Kim

Sridhar Venkatakrishnan uploaded a new patch set:
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, 93 insertions(+), 40 deletions(-)


--
https://go-review.googlesource.com/17475
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
Gerrit-Reviewer: Sridhar Venkatakrishnan <sri...@laddoo.net>

Sridhar Venkatakrishnan (Gerrit)

unread,
Dec 9, 2015, 6:45:15 AM12/9/15
to Hyang-Ah Hana Kim, golang-co...@googlegroups.com
Sridhar Venkatakrishnan has posted comments on this change.

bind: iOS support for multiple packages.

Patch Set 1:

(1 comment)

https://go-review.googlesource.com/#/c/17475/1/cmd/gomobile/bind_iosapp.go
File cmd/gomobile/bind_iosapp.go:

Line 176: for i, b := range fileBases {
> I didn't know clang doesn't accept -o if multiple input files are
> supplied.
This was a bit of a surprise to me as well (clang and -o). Regarding the
object file names, the names of the objects shouldn't matter. The archive
name is the only one we should care about. I just maintained the old names
for consistency sakes. I've sent an update with a single compile call.


--
https://go-review.googlesource.com/17475
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>

Hyang-Ah Hana Kim (Gerrit)

unread,
Dec 9, 2015, 11:23:56 AM12/9/15
to Sridhar Venkatakrishnan, Hyang-Ah Hana Kim, golang-co...@googlegroups.com
Hyang-Ah Hana Kim has posted comments on this change.

bind: iOS support for multiple packages.

Patch Set 2: Code-Review+2

--
https://go-review.googlesource.com/17475
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
Gerrit-Reviewer: Sridhar Venkatakrishnan <sri...@laddoo.net>
Gerrit-HasComments: No

Hyang-Ah Hana Kim (Gerrit)

unread,
Dec 9, 2015, 11:24:18 AM12/9/15
to Sridhar Venkatakrishnan, Hyang-Ah Hana Kim, golang-...@googlegroups.com, golang-co...@googlegroups.com
Hyang-Ah Hana Kim has submitted this change and it was merged.

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
Reviewed-on: https://go-review.googlesource.com/17475
Reviewed-by: Hyang-Ah Hana Kim <hya...@gmail.com>
---
M cmd/gomobile/bind.go
M cmd/gomobile/bind_iosapp.go
2 files changed, 93 insertions(+), 40 deletions(-)

Approvals:
Hyang-Ah Hana Kim: Looks good to me, approved


--
https://go-review.googlesource.com/17475
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
Gerrit-Reviewer: Sridhar Venkatakrishnan <sri...@laddoo.net>
Reply all
Reply to author
Forward
0 new messages