Drops the time for `gomobile init` on my machine from 46s to 30s. Change-Id: Iab89f2e1d1cee4b414dc2fb1c735b4167aef9036 Reviewed-on: https://go-review.googlesource.com/12641 Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
129 lines
3.1 KiB
Go
129 lines
3.1 KiB
Go
// 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"
|
|
"go/build"
|
|
"io"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"text/template"
|
|
)
|
|
|
|
func goIOSBind(pkg *build.Package) error {
|
|
binder, err := newBinder(pkg)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
name := binder.pkg.Name()
|
|
|
|
if buildO != "" && !strings.HasSuffix(buildO, ".framework") {
|
|
return fmt.Errorf("static framework name %q missing .framework suffix", buildO)
|
|
}
|
|
if buildO == "" {
|
|
buildO = name + ".framework"
|
|
}
|
|
|
|
if err := binder.GenGo(filepath.Join(tmpdir, "src")); 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)
|
|
})
|
|
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
|
|
}
|
|
|
|
cmd := exec.Command("xcrun", "lipo", "-create")
|
|
|
|
for _, env := range [][]string{darwinArmEnv, darwinArm64Env, darwinAmd64Env} {
|
|
arch := archClang(getenv(env, "GOARCH"))
|
|
path, err := goIOSBindArchive(name, mainFile, env)
|
|
if err != nil {
|
|
return fmt.Errorf("darwin-%s: %v", arch, err)
|
|
}
|
|
cmd.Args = append(cmd.Args, "-arch", arch, path)
|
|
}
|
|
|
|
// 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
|
|
}
|
|
if err := symlink("Versions/Current/"+strings.Title(name), buildO+"/"+strings.Title(name)); err != nil {
|
|
return err
|
|
}
|
|
|
|
cmd.Args = append(cmd.Args, "-o", buildO+"/Versions/A/"+strings.Title(name))
|
|
if err := runCmd(cmd); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Copy header file next to output archive.
|
|
return copyFile(
|
|
headers+"/"+strings.Title(name)+".h",
|
|
tmpdir+"/objc/Go"+strings.Title(name)+".h",
|
|
)
|
|
}
|
|
|
|
func goIOSBindArchive(name, path string, env []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)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
obj := "gobind-" + name + "-" + arch + ".o"
|
|
cmd := exec.Command(
|
|
getenv(env, "CC"),
|
|
"-I", ".",
|
|
"-g", "-O2",
|
|
"-o", obj,
|
|
"-c", "Go"+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
|
|
}
|
|
|
|
cmd = exec.Command("ar", "-q", "-s", archive, obj)
|
|
cmd.Dir = filepath.Join(tmpdir, "objc")
|
|
if err := runCmd(cmd); err != nil {
|
|
return "", err
|
|
}
|
|
return archive, nil
|
|
}
|
|
|
|
var iosBindTmpl = template.Must(template.New("ios.go").Parse(`
|
|
package main
|
|
|
|
import (
|
|
_ "golang.org/x/mobile/bind/objc"
|
|
_ "{{.}}"
|
|
)
|
|
|
|
import "C"
|
|
|
|
func main() {}
|
|
`))
|