github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/mobile/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 "io/ioutil" 12 "os/exec" 13 "path/filepath" 14 "strings" 15 "text/template" 16 ) 17 18 func goIOSBind(pkgs []*build.Package) error { 19 typesPkgs, err := loadExportData(pkgs, darwinArmEnv) 20 if err != nil { 21 return err 22 } 23 24 binder, err := newBinder(typesPkgs) 25 if err != nil { 26 return err 27 } 28 name := binder.pkgs[0].Name() 29 title := strings.Title(name) 30 31 if buildO != "" && !strings.HasSuffix(buildO, ".framework") { 32 return fmt.Errorf("static framework name %q missing .framework suffix", buildO) 33 } 34 if buildO == "" { 35 buildO = title + ".framework" 36 } 37 38 srcDir := filepath.Join(tmpdir, "src") 39 for _, pkg := range typesPkgs { 40 if err := binder.GenGo(pkg, srcDir); err != nil { 41 return err 42 } 43 } 44 mainFile := filepath.Join(tmpdir, "src/iosbin/main.go") 45 err = writeFile(mainFile, func(w io.Writer) error { 46 return iosBindTmpl.Execute(w, pkgs) 47 }) 48 if err != nil { 49 return fmt.Errorf("failed to create the binding package for iOS: %v", err) 50 } 51 52 objcDir := filepath.Join(tmpdir, "objc") 53 fileBases := make([]string, len(typesPkgs)) 54 for i, pkg := range typesPkgs { 55 if fileBases[i], err = binder.GenObjc(pkg, objcDir); err != nil { 56 return err 57 } 58 } 59 60 cmd := exec.Command("xcrun", "lipo", "-create") 61 62 for _, env := range [][]string{darwinArmEnv, darwinArm64Env, darwinAmd64Env} { 63 arch := archClang(getenv(env, "GOARCH")) 64 path, err := goIOSBindArchive(name, mainFile, env, fileBases) 65 if err != nil { 66 return fmt.Errorf("darwin-%s: %v", arch, err) 67 } 68 cmd.Args = append(cmd.Args, "-arch", arch, path) 69 } 70 71 // Build static framework output directory. 72 if err := removeAll(buildO); err != nil { 73 return err 74 } 75 headers := buildO + "/Versions/A/Headers" 76 if err := mkdir(headers); err != nil { 77 return err 78 } 79 if err := symlink("A", buildO+"/Versions/Current"); err != nil { 80 return err 81 } 82 if err := symlink("Versions/Current/Headers", buildO+"/Headers"); err != nil { 83 return err 84 } 85 if err := symlink("Versions/Current/"+title, buildO+"/"+title); err != nil { 86 return err 87 } 88 89 cmd.Args = append(cmd.Args, "-o", buildO+"/Versions/A/"+title) 90 if err := runCmd(cmd); err != nil { 91 return err 92 } 93 94 // Copy header file next to output archive. 95 headerFiles := make([]string, len(fileBases)) 96 if len(fileBases) == 1 { 97 headerFiles[0] = title + ".h" 98 err = copyFile( 99 headers+"/"+title+".h", 100 tmpdir+"/objc/"+bindPrefix+title+".h", 101 ) 102 if err != nil { 103 return err 104 } 105 } else { 106 for i, fileBase := range fileBases { 107 headerFiles[i] = fileBase + ".h" 108 err = copyFile( 109 headers+"/"+fileBase+".h", 110 tmpdir+"/objc/"+fileBase+".h") 111 if err != nil { 112 return err 113 } 114 } 115 headerFiles = append(headerFiles, title+".h") 116 err = writeFile(headers+"/"+title+".h", func(w io.Writer) error { 117 return iosBindHeaderTmpl.Execute(w, map[string]interface{}{ 118 "pkgs": pkgs, "title": title, "bases": fileBases, 119 }) 120 }) 121 if err != nil { 122 return err 123 } 124 } 125 126 resources := buildO + "/Versions/A/Resources" 127 if err := mkdir(resources); err != nil { 128 return err 129 } 130 if err := symlink("Versions/Current/Resources", buildO+"/Resources"); err != nil { 131 return err 132 } 133 if err := ioutil.WriteFile(buildO+"/Resources/Info.plist", []byte(iosBindInfoPlist), 0666); err != nil { 134 return err 135 } 136 137 var mmVals = struct { 138 Module string 139 Headers []string 140 }{ 141 Module: title, 142 Headers: headerFiles, 143 } 144 err = writeFile(buildO+"/Versions/A/Modules/module.modulemap", func(w io.Writer) error { 145 return iosModuleMapTmpl.Execute(w, mmVals) 146 }) 147 if err != nil { 148 return err 149 } 150 return symlink("Versions/Current/Modules", buildO+"/Modules") 151 } 152 153 const iosBindInfoPlist = `<?xml version="1.0" encoding="UTF-8"?> 154 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 155 <plist version="1.0"> 156 <dict> 157 </dict> 158 </plist> 159 ` 160 161 var iosModuleMapTmpl = template.Must(template.New("iosmmap").Parse(`framework module "{{.Module}}" { 162 {{range .Headers}} header "{{.}}" 163 {{end}} 164 export * 165 }`)) 166 167 func goIOSBindArchive(name, path string, env, fileBases []string) (string, error) { 168 arch := getenv(env, "GOARCH") 169 archive := filepath.Join(tmpdir, name+"-"+arch+".a") 170 err := goBuild(path, env, "-buildmode=c-archive", "-tags=ios", "-o", archive) 171 if err != nil { 172 return "", err 173 } 174 175 objs, mfiles := make([]string, len(fileBases)), make([]string, len(fileBases)) 176 for i, b := range fileBases { 177 objs[i], mfiles[i] = b+".o", b+".m" 178 } 179 180 args := append([]string{ 181 "-I", ".", 182 "-g", "-O2", 183 "-fobjc-arc", // enable ARC 184 "-c", 185 }, mfiles...) 186 187 cmd := exec.Command(getenv(env, "CC"), args...) 188 cmd.Args = append(cmd.Args, strings.Split(getenv(env, "CGO_CFLAGS"), " ")...) 189 cmd.Dir = filepath.Join(tmpdir, "objc") 190 cmd.Env = append([]string{}, env...) 191 if err := runCmd(cmd); err != nil { 192 return "", err 193 } 194 195 arArgs := append([]string{"-q", "-s", archive}, objs...) 196 cmd = exec.Command("ar", arArgs...) 197 cmd.Dir = filepath.Join(tmpdir, "objc") 198 if err := runCmd(cmd); err != nil { 199 return "", err 200 } 201 return archive, nil 202 } 203 204 var iosBindTmpl = template.Must(template.New("ios.go").Parse(` 205 package main 206 207 import ( 208 _ "golang.org/x/mobile/bind/objc" 209 {{range .}} _ "../go_{{.Name}}" 210 {{end}} 211 ) 212 213 import "C" 214 215 func main() {} 216 `)) 217 218 var iosBindHeaderTmpl = template.Must(template.New("ios.h").Parse(` 219 // Objective-C API for talking to the following Go packages 220 // 221 {{range .pkgs}}// {{.ImportPath}} 222 {{end}}// 223 // File is generated by gomobile bind. Do not edit. 224 #ifndef __{{.title}}_H__ 225 #define __{{.title}}_H__ 226 227 {{range .bases}}#include "{{.}}.h" 228 {{end}} 229 #endif 230 `))