| // 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() {} |
| `)) |