github.com/c-darwin/mobile@v0.0.0-20160313183840-ff625c46f7c9/cmd/gomobile/build.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 //go:generate go run gendex.go -o dex.go 6 7 package main 8 9 import ( 10 "bufio" 11 "fmt" 12 "go/build" 13 "io" 14 "os" 15 "os/exec" 16 "regexp" 17 "runtime" 18 "strconv" 19 "strings" 20 ) 21 22 var ctx = build.Default 23 var pkg *build.Package // TODO(crawshaw): remove global pkg variable 24 var tmpdir string 25 26 var cmdBuild = &command{ 27 run: runBuild, 28 Name: "build", 29 Usage: "[-target android|ios] [-o output] [build flags] [package]", 30 Short: "compile android APK and iOS app", 31 Long: ` 32 Build compiles and encodes the app named by the import path. 33 34 The named package must define a main function. 35 36 The -target flag takes a target system name, either android (the 37 default) or ios. 38 39 For -target android, if an AndroidManifest.xml is defined in the 40 package directory, it is added to the APK output. Otherwise, a default 41 manifest is generated. 42 43 For -target ios, gomobile must be run on an OS X machine with Xcode 44 installed. Support is not complete. 45 46 If the package directory contains an assets subdirectory, its contents 47 are copied into the output. 48 49 The -o flag specifies the output file name. If not specified, the 50 output file name depends on the package built. 51 52 The -v flag provides verbose output, including the list of packages built. 53 54 The build flags -a, -i, -n, -x, -gcflags, -ldflags, -tags, and -work are 55 shared with the build command. For documentation, see 'go help build'. 56 `, 57 } 58 59 func runBuild(cmd *command) (err error) { 60 cleanup, err := buildEnvInit() 61 if err != nil { 62 return err 63 } 64 defer cleanup() 65 66 args := cmd.flag.Args() 67 68 ctx.GOARCH = "arm" 69 switch buildTarget { 70 case "android": 71 ctx.GOOS = "android" 72 case "ios": 73 ctx.GOOS = "darwin" 74 default: 75 return fmt.Errorf(`unknown -target, %q.`, buildTarget) 76 } 77 78 switch len(args) { 79 case 0: 80 pkg, err = ctx.ImportDir(cwd, build.ImportComment) 81 case 1: 82 pkg, err = ctx.Import(args[0], cwd, build.ImportComment) 83 default: 84 cmd.usage() 85 os.Exit(1) 86 } 87 if err != nil { 88 return err 89 } 90 91 if pkg.Name != "main" && buildO != "" { 92 return fmt.Errorf("cannot set -o when building non-main package") 93 } 94 95 var nmpkgs map[string]bool 96 switch buildTarget { 97 case "android": 98 if pkg.Name != "main" { 99 return goBuild(pkg.ImportPath, androidArmEnv) 100 } 101 nmpkgs, err = goAndroidBuild(pkg) 102 if err != nil { 103 return err 104 } 105 case "ios": 106 if runtime.GOOS != "darwin" { 107 return fmt.Errorf("-target=ios requires darwin host") 108 } 109 if pkg.Name != "main" { 110 if err := goBuild(pkg.ImportPath, darwinArmEnv); err != nil { 111 return err 112 } 113 return goBuild(pkg.ImportPath, darwinArm64Env) 114 } 115 nmpkgs, err = goIOSBuild(pkg) 116 if err != nil { 117 return err 118 } 119 } 120 121 if !nmpkgs["github.com/c-darwin/mobile/app"] { 122 return fmt.Errorf(`%s does not import "github.com/c-darwin/mobile/app"`, pkg.ImportPath) 123 } 124 125 return nil 126 } 127 128 var nmRE = regexp.MustCompile(`[0-9a-f]{8} t (github.com/democratic-coin/dcoin-go/vendor/src/golang.org/x.*/[^.]*)`) 129 130 func extractPkgs(nm string, path string) (map[string]bool, error) { 131 if buildN { 132 return map[string]bool{"github.com/c-darwin/mobile/app": true}, nil 133 } 134 r, w := io.Pipe() 135 cmd := exec.Command(nm, path) 136 cmd.Stdout = w 137 cmd.Stderr = os.Stderr 138 139 nmpkgs := make(map[string]bool) 140 errc := make(chan error, 1) 141 go func() { 142 s := bufio.NewScanner(r) 143 for s.Scan() { 144 if res := nmRE.FindStringSubmatch(s.Text()); res != nil { 145 nmpkgs[res[1]] = true 146 } 147 } 148 errc <- s.Err() 149 }() 150 151 err := cmd.Run() 152 w.Close() 153 if err != nil { 154 return nil, fmt.Errorf("%s %s: %v", nm, path, err) 155 } 156 if err := <-errc; err != nil { 157 return nil, fmt.Errorf("%s %s: %v", nm, path, err) 158 } 159 return nmpkgs, nil 160 } 161 162 func importsApp(pkg *build.Package) error { 163 // Building a program, make sure it is appropriate for mobile. 164 for _, path := range pkg.Imports { 165 if path == "github.com/c-darwin/mobile/app" { 166 return nil 167 } 168 } 169 return fmt.Errorf(`%s does not import "github.com/c-darwin/mobile/app"`, pkg.ImportPath) 170 } 171 172 var xout io.Writer = os.Stderr 173 174 func printcmd(format string, args ...interface{}) { 175 cmd := fmt.Sprintf(format+"\n", args...) 176 if tmpdir != "" { 177 cmd = strings.Replace(cmd, tmpdir, "$WORK", -1) 178 } 179 if androidHome := os.Getenv("ANDROID_HOME"); androidHome != "" { 180 cmd = strings.Replace(cmd, androidHome, "$ANDROID_HOME", -1) 181 } 182 if gomobilepath != "" { 183 cmd = strings.Replace(cmd, gomobilepath, "$GOMOBILE", -1) 184 } 185 if goroot := goEnv("GOROOT"); goroot != "" { 186 cmd = strings.Replace(cmd, goroot, "$GOROOT", -1) 187 } 188 if gopath := goEnv("GOPATH"); gopath != "" { 189 cmd = strings.Replace(cmd, gopath, "$GOPATH", -1) 190 } 191 if env := os.Getenv("HOME"); env != "" { 192 cmd = strings.Replace(cmd, env, "$HOME", -1) 193 } 194 if env := os.Getenv("HOMEPATH"); env != "" { 195 cmd = strings.Replace(cmd, env, "$HOMEPATH", -1) 196 } 197 fmt.Fprint(xout, cmd) 198 } 199 200 // "Build flags", used by multiple commands. 201 var ( 202 buildA bool // -a 203 buildI bool // -i 204 buildN bool // -n 205 buildV bool // -v 206 buildX bool // -x 207 buildO string // -o 208 buildGcflags string // -gcflags 209 buildLdflags string // -ldflags 210 buildTarget string // -target 211 productName string // -name 212 buildWork bool // -work 213 ) 214 215 func addBuildFlags(cmd *command) { 216 cmd.flag.StringVar(&buildO, "o", "", "") 217 cmd.flag.StringVar(&buildGcflags, "gcflags", "", "") 218 cmd.flag.StringVar(&buildLdflags, "ldflags", "", "") 219 cmd.flag.StringVar(&buildTarget, "target", "android", "") 220 cmd.flag.StringVar(&productName, "name", "ProductName", "") 221 222 cmd.flag.BoolVar(&buildA, "a", false, "") 223 cmd.flag.BoolVar(&buildI, "i", false, "") 224 cmd.flag.Var((*stringsFlag)(&ctx.BuildTags), "tags", "") 225 } 226 227 func addBuildFlagsNVXWork(cmd *command) { 228 cmd.flag.BoolVar(&buildN, "n", false, "") 229 cmd.flag.BoolVar(&buildV, "v", false, "") 230 cmd.flag.BoolVar(&buildX, "x", false, "") 231 cmd.flag.BoolVar(&buildWork, "work", false, "") 232 } 233 234 type binInfo struct { 235 hasPkgApp bool 236 hasPkgAL bool 237 } 238 239 func init() { 240 addBuildFlags(cmdBuild) 241 addBuildFlagsNVXWork(cmdBuild) 242 243 addBuildFlags(cmdInstall) 244 addBuildFlagsNVXWork(cmdInstall) 245 246 addBuildFlagsNVXWork(cmdInit) 247 248 addBuildFlags(cmdBind) 249 addBuildFlagsNVXWork(cmdBind) 250 } 251 252 func goBuild(src string, env []string, args ...string) error { 253 // The -p flag is to speed up darwin/arm builds. 254 // Remove when golang.org/issue/10477 is resolved. 255 cmd := exec.Command( 256 "go", 257 "build", 258 fmt.Sprintf("-p=%d", runtime.NumCPU()), 259 "-pkgdir="+pkgdir(env), 260 "-tags="+strconv.Quote(strings.Join(ctx.BuildTags, ",")), 261 ) 262 if buildV { 263 cmd.Args = append(cmd.Args, "-v") 264 } 265 if buildI { 266 cmd.Args = append(cmd.Args, "-i") 267 } 268 if buildX { 269 cmd.Args = append(cmd.Args, "-x") 270 } 271 if buildGcflags != "" { 272 cmd.Args = append(cmd.Args, "-gcflags", buildGcflags) 273 } 274 if buildLdflags != "" { 275 cmd.Args = append(cmd.Args, "-ldflags", buildLdflags) 276 } 277 if buildWork { 278 cmd.Args = append(cmd.Args, "-work") 279 } 280 cmd.Args = append(cmd.Args, args...) 281 cmd.Args = append(cmd.Args, src) 282 cmd.Env = append([]string{}, env...) 283 return runCmd(cmd) 284 }