github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/cmd/gomobile/bind_iosapp.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "fmt" 9 "go/build" 10 "io" 11 "os/exec" 12 "path/filepath" 13 "strings" 14 "text/template" 15 ) 16 17 func goIOSBind(pkg *build.Package) error { 18 binder, err := newBinder(pkg) 19 if err != nil { 20 return err 21 } 22 name := binder.pkg.Name() 23 24 if buildO != "" && !strings.HasSuffix(buildO, ".framework") { 25 return fmt.Errorf("static framework name %q missing .framework suffix", buildO) 26 } 27 if buildO == "" { 28 buildO = name + ".framework" 29 } 30 31 if err := binder.GenGo(filepath.Join(tmpdir, "src")); err != nil { 32 return err 33 } 34 mainFile := filepath.Join(tmpdir, "src/iosbin/main.go") 35 err = writeFile(mainFile, func(w io.Writer) error { 36 return iosBindTmpl.Execute(w, "../go_"+name) 37 }) 38 if err != nil { 39 return fmt.Errorf("failed to create the binding package for iOS: %v", err) 40 } 41 if err := binder.GenObjc(filepath.Join(tmpdir, "objc")); err != nil { 42 return err 43 } 44 45 cmd := exec.Command("xcrun", "lipo", "-create") 46 47 for _, env := range [][]string{darwinArmEnv, darwinArm64Env, darwinAmd64Env} { 48 arch := archClang(getenv(env, "GOARCH")) 49 path, err := goIOSBindArchive(name, mainFile, env) 50 if err != nil { 51 return fmt.Errorf("darwin-%s: %v", arch, err) 52 } 53 cmd.Args = append(cmd.Args, "-arch", arch, path) 54 } 55 56 // Build static framework output directory. 57 if err := removeAll(buildO); err != nil { 58 return err 59 } 60 headers := buildO + "/Versions/A/Headers" 61 if err := mkdir(headers); err != nil { 62 return err 63 } 64 if err := symlink("A", buildO+"/Versions/Current"); err != nil { 65 return err 66 } 67 if err := symlink("Versions/Current/Headers", buildO+"/Headers"); err != nil { 68 return err 69 } 70 if err := symlink("Versions/Current/"+strings.Title(name), buildO+"/"+strings.Title(name)); err != nil { 71 return err 72 } 73 74 cmd.Args = append(cmd.Args, "-o", buildO+"/Versions/A/"+strings.Title(name)) 75 if err := runCmd(cmd); err != nil { 76 return err 77 } 78 79 // Copy header file next to output archive. 80 return copyFile( 81 headers+"/"+strings.Title(name)+".h", 82 tmpdir+"/objc/Go"+strings.Title(name)+".h", 83 ) 84 } 85 86 func goIOSBindArchive(name, path string, env []string) (string, error) { 87 arch := getenv(env, "GOARCH") 88 archive := filepath.Join(tmpdir, name+"-"+arch+".a") 89 err := goBuild(path, env, "-buildmode=c-archive", "-tags=ios", "-o", archive) 90 if err != nil { 91 return "", err 92 } 93 94 obj := "gobind-" + name + "-" + arch + ".o" 95 cmd := exec.Command( 96 getenv(env, "CC"), 97 "-I", ".", 98 "-g", "-O2", 99 "-o", obj, 100 "-c", "Go"+strings.Title(name)+".m", 101 ) 102 cmd.Args = append(cmd.Args, strings.Split(getenv(env, "CGO_CFLAGS"), " ")...) 103 cmd.Dir = filepath.Join(tmpdir, "objc") 104 cmd.Env = append([]string{}, env...) 105 if err := runCmd(cmd); err != nil { 106 return "", err 107 } 108 109 cmd = exec.Command("ar", "-q", "-s", archive, obj) 110 cmd.Dir = filepath.Join(tmpdir, "objc") 111 if err := runCmd(cmd); err != nil { 112 return "", err 113 } 114 return archive, nil 115 } 116 117 var iosBindTmpl = template.Must(template.New("ios.go").Parse(` 118 package main 119 120 import ( 121 _ "github.com/c-darwin/mobile/bind/objc" 122 _ "{{.}}" 123 ) 124 125 import "C" 126 127 func main() {} 128 `))