2015-07-14 18:09:25 -04:00
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
"text/template"
|
2019-11-12 21:44:24 +09:00
|
|
|
|
|
|
|
"golang.org/x/tools/go/packages"
|
2015-07-14 18:09:25 -04:00
|
|
|
)
|
|
|
|
|
2019-11-12 21:44:24 +09:00
|
|
|
func goIOSBind(gobind string, pkgs []*packages.Package, archs []string) error {
|
2018-03-07 22:51:37 +01:00
|
|
|
// Run gobind to generate the bindings
|
|
|
|
cmd := exec.Command(
|
2018-03-16 08:34:03 +01:00
|
|
|
gobind,
|
2018-03-07 22:51:37 +01:00
|
|
|
"-lang=go,objc",
|
|
|
|
"-outdir="+tmpdir,
|
|
|
|
)
|
2018-03-09 10:32:43 +01:00
|
|
|
cmd.Env = append(cmd.Env, "GOOS=darwin")
|
2018-04-19 23:38:10 +02:00
|
|
|
cmd.Env = append(cmd.Env, "CGO_ENABLED=1")
|
2019-11-20 16:55:32 +09:00
|
|
|
tags := append(buildTags, "ios")
|
|
|
|
cmd.Args = append(cmd.Args, "-tags="+strings.Join(tags, ","))
|
2018-03-07 22:51:37 +01:00
|
|
|
if bindPrefix != "" {
|
|
|
|
cmd.Args = append(cmd.Args, "-prefix="+bindPrefix)
|
2015-11-13 13:57:15 -05:00
|
|
|
}
|
2018-03-07 22:51:37 +01:00
|
|
|
for _, p := range pkgs {
|
2019-11-12 21:44:24 +09:00
|
|
|
cmd.Args = append(cmd.Args, p.PkgPath)
|
2017-07-31 16:13:01 +02:00
|
|
|
}
|
2018-03-07 22:51:37 +01:00
|
|
|
if err := runCmd(cmd); err != nil {
|
2015-07-14 18:09:25 -04:00
|
|
|
return err
|
|
|
|
}
|
2018-03-07 22:51:37 +01:00
|
|
|
|
|
|
|
srcDir := filepath.Join(tmpdir, "src", "gobind")
|
|
|
|
|
|
|
|
name := pkgs[0].Name
|
2015-10-01 18:47:53 -04:00
|
|
|
title := strings.Title(name)
|
2015-07-14 18:09:25 -04:00
|
|
|
|
2015-07-19 15:12:22 -04:00
|
|
|
if buildO != "" && !strings.HasSuffix(buildO, ".framework") {
|
|
|
|
return fmt.Errorf("static framework name %q missing .framework suffix", buildO)
|
2015-07-14 18:09:25 -04:00
|
|
|
}
|
|
|
|
if buildO == "" {
|
2015-10-01 18:47:53 -04:00
|
|
|
buildO = title + ".framework"
|
2015-07-14 18:09:25 -04:00
|
|
|
}
|
|
|
|
|
2018-03-07 22:51:37 +01:00
|
|
|
fileBases := make([]string, len(pkgs)+1)
|
|
|
|
for i, pkg := range pkgs {
|
|
|
|
fileBases[i] = bindPrefix + strings.Title(pkg.Name)
|
mobile/bind: replace seq serialization with direct calls
The seq serialization machinery is a historic artifact from when Go
mobile code had to run in a separate process. Now that Go code is running
in-process, replace the explicit serialization with direct calls and pass
arguments on the stack.
The benefits are a much smaller bind runtime, much less garbage (and, in
Java, fewer objects with finalizers), less argument copying, and faster
cross-language calls.
The cost is a more complex generator, because some of the work from the
bind runtime is moved to generated code. Generated code now handles
conversion between Go and Java/ObjC types, multiple return values and memory
management of byte slice and string arguments.
To overcome the lack of calling C code between Go packages, all bound
packages now end up in the same (fake) package, "gomobile_bind", instead of
separate packages (go_<pkgname>). To avoid name clashes, the package name is
added as a prefix to generated functions and types.
Also, don't copy byte arrays passed to Go, saving call time and
allowing read([]byte)-style interfaces to foreign callers (#12113).
Finally, add support for nil interfaces and struct pointers to objc.
This is a large CL, but most of the changes stem from changing testdata.
The full benchcmp output on the CL/20095 benchmarks on my Nexus 5 is
reproduced below. Note that the savings for the JavaSlice* benchmarks are
skewed because byte slices are no longer copied before passing them to Go.
benchmark old ns/op new ns/op delta
BenchmarkJavaEmpty 26.0 19.0 -26.92%
BenchmarkJavaEmptyDirect 23.0 22.0 -4.35%
BenchmarkJavaNoargs 7685 2339 -69.56%
BenchmarkJavaNoargsDirect 17405 8041 -53.80%
BenchmarkJavaOnearg 26887 2366 -91.20%
BenchmarkJavaOneargDirect 34266 7910 -76.92%
BenchmarkJavaOneret 38325 2245 -94.14%
BenchmarkJavaOneretDirect 46265 7708 -83.34%
BenchmarkJavaManyargs 41720 2535 -93.92%
BenchmarkJavaManyargsDirect 51026 8373 -83.59%
BenchmarkJavaRefjava 38139 21260 -44.26%
BenchmarkJavaRefjavaDirect 42706 28150 -34.08%
BenchmarkJavaRefgo 34403 6843 -80.11%
BenchmarkJavaRefgoDirect 40193 16582 -58.74%
BenchmarkJavaStringShort 32366 9323 -71.20%
BenchmarkJavaStringShortDirect 41973 19118 -54.45%
BenchmarkJavaStringLong 127879 94420 -26.16%
BenchmarkJavaStringLongDirect 133776 114760 -14.21%
BenchmarkJavaStringShortUnicode 32562 9221 -71.68%
BenchmarkJavaStringShortUnicodeDirect 41464 19094 -53.95%
BenchmarkJavaStringLongUnicode 131015 89401 -31.76%
BenchmarkJavaStringLongUnicodeDirect 134130 90786 -32.31%
BenchmarkJavaSliceShort 42462 7538 -82.25%
BenchmarkJavaSliceShortDirect 52940 17017 -67.86%
BenchmarkJavaSliceLong 138391 8466 -93.88%
BenchmarkJavaSliceLongDirect 205804 15666 -92.39%
BenchmarkGoEmpty 3.00 3.00 +0.00%
BenchmarkGoEmptyDirect 3.00 3.00 +0.00%
BenchmarkGoNoarg 40342 13716 -66.00%
BenchmarkGoNoargDirect 46691 13569 -70.94%
BenchmarkGoOnearg 43529 13757 -68.40%
BenchmarkGoOneargDirect 44867 14078 -68.62%
BenchmarkGoOneret 45456 13559 -70.17%
BenchmarkGoOneretDirect 44694 13442 -69.92%
BenchmarkGoRefjava 55111 28071 -49.06%
BenchmarkGoRefjavaDirect 60883 26872 -55.86%
BenchmarkGoRefgo 57038 29223 -48.77%
BenchmarkGoRefgoDirect 56153 27812 -50.47%
BenchmarkGoManyargs 67967 17398 -74.40%
BenchmarkGoManyargsDirect 60617 16998 -71.96%
BenchmarkGoStringShort 57538 22600 -60.72%
BenchmarkGoStringShortDirect 52627 22704 -56.86%
BenchmarkGoStringLong 128485 52530 -59.12%
BenchmarkGoStringLongDirect 138377 52079 -62.36%
BenchmarkGoStringShortUnicode 57062 22994 -59.70%
BenchmarkGoStringShortUnicodeDirect 62563 22938 -63.34%
BenchmarkGoStringLongUnicode 139913 55553 -60.29%
BenchmarkGoStringLongUnicodeDirect 150863 57791 -61.69%
BenchmarkGoSliceShort 59279 20215 -65.90%
BenchmarkGoSliceShortDirect 60160 21136 -64.87%
BenchmarkGoSliceLong 411225 301870 -26.59%
BenchmarkGoSliceLongDirect 399029 298915 -25.09%
Fixes golang/go#12619
Fixes golang/go#12113
Fixes golang/go#13033
Change-Id: I2b45e9e98a1248e3c23a5137f775f7364908bec7
Reviewed-on: https://go-review.googlesource.com/19821
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
2016-02-12 18:50:33 +01:00
|
|
|
}
|
2018-10-26 05:24:47 +00:00
|
|
|
fileBases[len(fileBases)-1] = "Universe"
|
2015-07-14 18:09:25 -04:00
|
|
|
|
2018-03-07 22:51:37 +01:00
|
|
|
cmd = exec.Command("xcrun", "lipo", "-create")
|
2015-07-16 13:32:51 -04:00
|
|
|
|
2018-03-28 13:37:41 +02:00
|
|
|
for _, arch := range archs {
|
2019-12-09 16:01:06 +09:00
|
|
|
if err := writeGoMod("darwin", arch); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-03-28 13:37:41 +02:00
|
|
|
env := darwinEnv[arch]
|
2019-11-27 22:57:30 +09:00
|
|
|
// Add the generated packages to GOPATH for reverse bindings.
|
|
|
|
gopath := fmt.Sprintf("GOPATH=%s%c%s", tmpdir, filepath.ListSeparator, goEnv("GOPATH"))
|
2016-09-13 06:05:52 +02:00
|
|
|
env = append(env, gopath)
|
2019-11-27 22:57:30 +09:00
|
|
|
path, err := goIOSBindArchive(name, env, filepath.Join(tmpdir, "src"))
|
2015-07-16 13:32:51 -04:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("darwin-%s: %v", arch, err)
|
|
|
|
}
|
2018-03-28 13:37:41 +02:00
|
|
|
cmd.Args = append(cmd.Args, "-arch", archClang(arch), path)
|
2015-07-14 18:09:25 -04:00
|
|
|
}
|
|
|
|
|
2015-07-19 15:12:22 -04:00
|
|
|
// Build static framework output directory.
|
|
|
|
if err := removeAll(buildO); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
headers := buildO + "/Versions/A/Headers"
|
|
|
|
if err := mkdir(headers); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := symlink("A", buildO+"/Versions/Current"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := symlink("Versions/Current/Headers", buildO+"/Headers"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-10-01 18:47:53 -04:00
|
|
|
if err := symlink("Versions/Current/"+title, buildO+"/"+title); err != nil {
|
2015-07-19 15:12:22 -04:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-10-01 18:47:53 -04:00
|
|
|
cmd.Args = append(cmd.Args, "-o", buildO+"/Versions/A/"+title)
|
2015-07-19 21:29:35 -04:00
|
|
|
if err := runCmd(cmd); err != nil {
|
|
|
|
return err
|
2015-07-14 18:09:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy header file next to output archive.
|
2015-12-01 09:37:56 +05:30
|
|
|
headerFiles := make([]string, len(fileBases))
|
|
|
|
if len(fileBases) == 1 {
|
|
|
|
headerFiles[0] = title + ".h"
|
2018-03-07 22:51:37 +01:00
|
|
|
err := copyFile(
|
2015-12-01 09:37:56 +05:30
|
|
|
headers+"/"+title+".h",
|
2016-11-24 16:53:21 +01:00
|
|
|
srcDir+"/"+bindPrefix+title+".objc.h",
|
2015-12-01 09:37:56 +05:30
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for i, fileBase := range fileBases {
|
2016-11-24 16:53:21 +01:00
|
|
|
headerFiles[i] = fileBase + ".objc.h"
|
2018-03-07 22:51:37 +01:00
|
|
|
err := copyFile(
|
2016-11-24 16:53:21 +01:00
|
|
|
headers+"/"+fileBase+".objc.h",
|
|
|
|
srcDir+"/"+fileBase+".objc.h")
|
2015-12-01 09:37:56 +05:30
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2018-03-07 22:51:37 +01:00
|
|
|
err := copyFile(
|
2016-09-13 06:05:52 +02:00
|
|
|
headers+"/ref.h",
|
|
|
|
srcDir+"/ref.h")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2015-12-01 09:37:56 +05:30
|
|
|
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
|
|
|
|
}
|
2015-09-13 17:55:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
resources := buildO + "/Versions/A/Resources"
|
|
|
|
if err := mkdir(resources); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := symlink("Versions/Current/Resources", buildO+"/Resources"); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2018-04-03 16:24:44 +02:00
|
|
|
err := writeFile(buildO+"/Resources/Info.plist", func(w io.Writer) error {
|
|
|
|
_, err := w.Write([]byte(iosBindInfoPlist))
|
|
|
|
return err
|
|
|
|
})
|
|
|
|
if err != nil {
|
2015-09-27 13:34:13 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
var mmVals = struct {
|
2015-12-01 09:37:56 +05:30
|
|
|
Module string
|
|
|
|
Headers []string
|
2015-09-27 13:34:13 -07:00
|
|
|
}{
|
2015-12-01 09:37:56 +05:30
|
|
|
Module: title,
|
|
|
|
Headers: headerFiles,
|
2015-09-27 13:34:13 -07:00
|
|
|
}
|
2018-04-03 16:24:44 +02:00
|
|
|
err = writeFile(buildO+"/Versions/A/Modules/module.modulemap", func(w io.Writer) error {
|
2015-09-27 13:34:13 -07:00
|
|
|
return iosModuleMapTmpl.Execute(w, mmVals)
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return symlink("Versions/Current/Modules", buildO+"/Modules")
|
2015-07-14 18:09:25 -04:00
|
|
|
}
|
|
|
|
|
2015-09-13 17:55:49 -04:00
|
|
|
const iosBindInfoPlist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
|
|
<plist version="1.0">
|
|
|
|
<dict>
|
|
|
|
</dict>
|
|
|
|
</plist>
|
|
|
|
`
|
|
|
|
|
2015-09-27 13:34:13 -07:00
|
|
|
var iosModuleMapTmpl = template.Must(template.New("iosmmap").Parse(`framework module "{{.Module}}" {
|
2016-09-13 06:05:52 +02:00
|
|
|
header "ref.h"
|
2015-12-01 09:37:56 +05:30
|
|
|
{{range .Headers}} header "{{.}}"
|
|
|
|
{{end}}
|
2015-09-27 13:34:13 -07:00
|
|
|
export *
|
|
|
|
}`))
|
|
|
|
|
2019-11-27 22:57:30 +09:00
|
|
|
func goIOSBindArchive(name string, env []string, gosrc string) (string, error) {
|
2015-07-14 18:09:25 -04:00
|
|
|
arch := getenv(env, "GOARCH")
|
|
|
|
archive := filepath.Join(tmpdir, name+"-"+arch+".a")
|
2019-11-27 22:57:30 +09:00
|
|
|
err := goBuildAt(gosrc, "./gobind", env, "-buildmode=c-archive", "-o", archive)
|
2015-07-14 18:09:25 -04:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return archive, nil
|
|
|
|
}
|
|
|
|
|
2015-12-01 09:37:56 +05:30
|
|
|
var iosBindHeaderTmpl = template.Must(template.New("ios.h").Parse(`
|
|
|
|
// Objective-C API for talking to the following Go packages
|
|
|
|
//
|
2019-11-12 21:44:24 +09:00
|
|
|
{{range .pkgs}}// {{.PkgPath}}
|
2015-12-01 09:37:56 +05:30
|
|
|
{{end}}//
|
|
|
|
// File is generated by gomobile bind. Do not edit.
|
2017-01-17 22:25:53 +01:00
|
|
|
#ifndef __{{.title}}_FRAMEWORK_H__
|
|
|
|
#define __{{.title}}_FRAMEWORK_H__
|
2015-12-01 09:37:56 +05:30
|
|
|
|
2016-11-24 16:53:21 +01:00
|
|
|
{{range .bases}}#include "{{.}}.objc.h"
|
2015-12-01 09:37:56 +05:30
|
|
|
{{end}}
|
|
|
|
#endif
|
|
|
|
`))
|