Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(428)

Side by Side Diff: third_party/go/src/golang.org/x/mobile/cmd/gomobile/build.go

Issue 1275153002: Remove third_party/golang.org/x/mobile as it is no longer used with Go 1.5. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Remove golang.org/x/mobile Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "bytes"
9 "crypto/x509"
10 "encoding/pem"
11 "errors"
12 "fmt"
13 "go/build"
14 "io"
15 "io/ioutil"
16 "os"
17 "os/exec"
18 "path"
19 "path/filepath"
20 "strconv"
21 "strings"
22 )
23
24 var ctx = build.Default
25 var pkg *build.Package
26 var ndkccpath string
27 var tmpdir string
28
29 var cmdBuild = &command{
30 run: runBuild,
31 Name: "build",
32 Usage: "[package]",
33 Short: "compile android APK and/or iOS app",
34 Long: `
35 Build compiles and encodes the app named by the import path.
36
37 The named package must define a main function.
38
39 If an AndroidManifest.xml is defined in the package directory, it is
40 added to the APK file. Otherwise, a default manifest is generated.
41
42 If the package directory contains an assets subdirectory, its contents
43 are copied into the APK file.
44
45 The -o flag specifies the output file name. If not specified, the
46 output file name depends on the package built. The output file must end
47 in '.apk'.
48
49 The -v flag provides verbose output, including the list of packages built.
50
51 These build flags are shared by the build, install, and test commands.
52 For documentation, see 'go help build':
53 -a
54 -i
55 -n
56 -x
57 -tags 'tag list'
58 `,
59 }
60
61 // TODO: -mobile
62
63 func runBuild(cmd *command) error {
64 cwd, err := os.Getwd()
65 if err != nil {
66 panic(err)
67 }
68 args := cmd.flag.Args()
69
70 switch len(args) {
71 case 0:
72 pkg, err = ctx.ImportDir(cwd, build.ImportComment)
73 case 1:
74 pkg, err = ctx.Import(args[0], cwd, build.ImportComment)
75 default:
76 cmd.usage()
77 os.Exit(1)
78 }
79 if err != nil {
80 return err
81 }
82
83 if pkg.Name != "main" {
84 // Not an app, don't build a final package.
85 return gobuild(pkg.ImportPath, "")
86 }
87
88 // Building a program, make sure it is appropriate for mobile.
89 importsApp := false
90 for _, path := range pkg.Imports {
91 if path == "golang.org/x/mobile/app" {
92 importsApp = true
93 break
94 }
95 }
96 if !importsApp {
97 return fmt.Errorf(`%s does not import "golang.org/x/mobile/app"` , pkg.ImportPath)
98 }
99
100 if buildN {
101 tmpdir = "$WORK"
102 } else {
103 tmpdir, err = ioutil.TempDir("", "gobuildapk-work-")
104 if err != nil {
105 return err
106 }
107 }
108 defer removeAll(tmpdir)
109 if buildX {
110 fmt.Fprintln(os.Stderr, "WORK="+tmpdir)
111 }
112
113 libName := path.Base(pkg.ImportPath)
114 manifestData, err := ioutil.ReadFile(filepath.Join(pkg.Dir, "AndroidMani fest.xml"))
115 if err != nil {
116 if !os.IsNotExist(err) {
117 return err
118 }
119 buf := new(bytes.Buffer)
120 buf.WriteString(`<?xml version="1.0" encoding="utf-8"?>`)
121 err := manifestTmpl.Execute(buf, manifestTmplData{
122 // TODO(crawshaw): a better package path.
123 JavaPkgPath: "org.golang.todo." + pkg.Name,
124 Name: strings.ToUpper(pkg.Name[:1]) + pkg.Name[1: ],
125 LibName: libName,
126 })
127 if err != nil {
128 return err
129 }
130 manifestData = buf.Bytes()
131 if buildV {
132 fmt.Fprintf(os.Stderr, "generated AndroidManifest.xml:\n %s\n", manifestData)
133 }
134 } else {
135 libName, err = manifestLibName(manifestData)
136 if err != nil {
137 return err
138 }
139 }
140 libPath := filepath.Join(tmpdir, "lib"+libName+".so")
141
142 if err := gobuild(pkg.ImportPath, libPath); err != nil {
143 return err
144 }
145 block, _ := pem.Decode([]byte(debugCert))
146 if block == nil {
147 return errors.New("no debug cert")
148 }
149 privKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
150 if err != nil {
151 return err
152 }
153
154 if *buildO == "" {
155 *buildO = filepath.Base(pkg.Dir) + ".apk"
156 }
157 if !strings.HasSuffix(*buildO, ".apk") {
158 return fmt.Errorf("output file name %q does not end in '.apk'", *buildO)
159 }
160 out, err := os.Create(*buildO)
161 if err != nil {
162 return err
163 }
164
165 var apkw *Writer
166 if !buildN {
167 apkw = NewWriter(out, privKey)
168 }
169 apkwcreate := func(name string) (io.Writer, error) {
170 if buildV {
171 fmt.Fprintf(os.Stderr, "apk: %s\n", name)
172 }
173 if buildN {
174 return ioutil.Discard, nil
175 }
176 return apkw.Create(name)
177 }
178
179 w, err := apkwcreate("AndroidManifest.xml")
180 if err != nil {
181 return err
182 }
183 if _, err := w.Write(manifestData); err != nil {
184 return err
185 }
186
187 w, err = apkwcreate("lib/armeabi/lib" + libName + ".so")
188 if err != nil {
189 return err
190 }
191 if !buildN {
192 r, err := os.Open(libPath)
193 if err != nil {
194 return err
195 }
196 if _, err := io.Copy(w, r); err != nil {
197 return err
198 }
199 }
200
201 // Add any assets.
202 assetsDir := filepath.Join(pkg.Dir, "assets")
203 assetsDirExists := true
204 fi, err := os.Stat(assetsDir)
205 if err != nil {
206 if os.IsNotExist(err) {
207 assetsDirExists = false
208 } else {
209 return err
210 }
211 } else {
212 assetsDirExists = fi.IsDir()
213 }
214 if assetsDirExists {
215 filepath.Walk(assetsDir, func(path string, info os.FileInfo, err error) error {
216 if err != nil {
217 return err
218 }
219 if info.IsDir() {
220 return nil
221 }
222 name := "assets/" + path[len(assetsDir)+1:]
223 w, err := apkwcreate(name)
224 if err != nil {
225 return err
226 }
227 f, err := os.Open(path)
228 if err != nil {
229 return err
230 }
231 defer f.Close()
232 _, err = io.Copy(w, f)
233 return err
234 })
235 }
236
237 // TODO: add gdbserver to apk?
238
239 if buildN {
240 return nil
241 }
242 return apkw.Close()
243 }
244
245 var xout io.Writer = os.Stderr
246
247 func printcmd(format string, args ...interface{}) {
248 cmd := fmt.Sprintf(format+"\n", args...)
249 if tmpdir != "" {
250 cmd = strings.Replace(cmd, tmpdir, "$WORK", -1)
251 }
252 if ndkccpath != "" {
253 cmd = strings.Replace(cmd, ndkccpath, "$NDKCCPATH", -1)
254 }
255 if env := os.Getenv("HOME"); env != "" {
256 cmd = strings.Replace(cmd, env, "$HOME", -1)
257 }
258 fmt.Fprint(xout, cmd)
259 }
260
261 // "Build flags", used by multiple commands.
262 var (
263 buildA bool // -a
264 buildI bool // -i
265 buildN bool // -n
266 buildV bool // -v
267 buildX bool // -x
268 buildO *string // -o
269 )
270
271 func addBuildFlags(cmd *command) {
272 cmd.flag.BoolVar(&buildA, "a", false, "")
273 cmd.flag.BoolVar(&buildI, "i", false, "")
274 cmd.flag.Var((*stringsFlag)(&ctx.BuildTags), "tags", "")
275 }
276
277 func addBuildFlagsNVX(cmd *command) {
278 cmd.flag.BoolVar(&buildN, "n", false, "")
279 cmd.flag.BoolVar(&buildV, "v", false, "")
280 cmd.flag.BoolVar(&buildX, "x", false, "")
281 }
282
283 // gobuild builds a package.
284 // If libPath is specified then it builds as a shared library.
285 func gobuild(src, libPath string) error {
286 version, err := goVersion()
287 if err != nil {
288 return err
289 }
290
291 gopath := goEnv("GOPATH")
292 gomobilepath := ""
293 for _, p := range filepath.SplitList(gopath) {
294 gomobilepath = filepath.Join(p, "pkg", "gomobile")
295 if _, err = os.Stat(gomobilepath); err == nil {
296 break
297 }
298 }
299 if err != nil || gomobilepath == "" {
300 return errors.New("android toolchain not installed, run:\n\tgomo bile init")
301 }
302 verpath := filepath.Join(gomobilepath, "version")
303 installedVersion, err := ioutil.ReadFile(verpath)
304 if err != nil {
305 return errors.New("android toolchain partially installed, run:\n \tgomobile init")
306 }
307 if !bytes.Equal(installedVersion, version) {
308 return errors.New("android toolchain out of date, run:\n\tgomobi le init")
309 }
310
311 ndkccpath = filepath.Join(gomobilepath, "android-"+ndkVersion)
312 ndkccbin := filepath.Join(ndkccpath, "arm", "bin")
313 if buildX {
314 fmt.Fprintln(os.Stderr, "NDKCCPATH="+ndkccpath)
315 }
316
317 gocmd := exec.Command(
318 `go`,
319 `build`,
320 `-tags=`+strconv.Quote(strings.Join(ctx.BuildTags, ",")),
321 `-toolexec=`+filepath.Join(ndkccbin, "toolexec"))
322 if buildV {
323 gocmd.Args = append(gocmd.Args, "-v")
324 }
325 if buildI {
326 gocmd.Args = append(gocmd.Args, "-i")
327 }
328 if buildX {
329 gocmd.Args = append(gocmd.Args, "-x")
330 }
331 if libPath == "" {
332 if *buildO != "" {
333 gocmd.Args = append(gocmd.Args, `-o`, *buildO)
334 }
335 } else {
336 gocmd.Args = append(gocmd.Args,
337 `-ldflags="-shared"`,
338 `-o`, libPath,
339 )
340 }
341
342 gocmd.Args = append(gocmd.Args, src)
343
344 gocmd.Stdout = os.Stdout
345 gocmd.Stderr = os.Stderr
346 gocmd.Env = []string{
347 `GOOS=android`,
348 `GOARCH=arm`,
349 `GOARM=7`,
350 `CGO_ENABLED=1`,
351 `CC=` + filepath.Join(ndkccbin, "arm-linux-androideabi-gcc"),
352 `CXX=` + filepath.Join(ndkccbin, "arm-linux-androideabi-g++"),
353 `GOGCCFLAGS="-fPIC -marm -pthread -fmessage-length=0"`,
354 `GOROOT=` + goEnv("GOROOT"),
355 `GOPATH=` + gopath,
356 `GOMOBILEPATH=` + ndkccbin, // for toolexec
357 }
358 if buildX {
359 printcmd("%s", strings.Join(gocmd.Env, " ")+" "+strings.Join(goc md.Args, " "))
360 }
361 if !buildN {
362 if err := gocmd.Run(); err != nil {
363 return err
364 }
365 }
366 return nil
367 }
368
369 func init() {
370 buildO = cmdBuild.flag.String("o", "", "output file")
371 addBuildFlags(cmdBuild)
372 addBuildFlagsNVX(cmdBuild)
373
374 addBuildFlags(cmdInstall)
375 addBuildFlagsNVX(cmdInstall)
376
377 addBuildFlagsNVX(cmdInit)
378
379 addBuildFlags(cmdBind)
380 addBuildFlagsNVX(cmdBind)
381 }
382
383 // A random uninteresting private key.
384 // Must be consistent across builds so newer app versions can be installed.
385 const debugCert = `
386 -----BEGIN RSA PRIVATE KEY-----
387 MIIEowIBAAKCAQEAy6ItnWZJ8DpX9R5FdWbS9Kr1U8Z7mKgqNByGU7No99JUnmyu
388 NQ6Uy6Nj0Gz3o3c0BXESECblOC13WdzjsH1Pi7/L9QV8jXOXX8cvkG5SJAyj6hcO
389 LOapjDiN89NXjXtyv206JWYvRtpexyVrmHJgRAw3fiFI+m4g4Qop1CxcIF/EgYh7
390 rYrqh4wbCM1OGaCleQWaOCXxZGm+J5YNKQcWpjZRrDrb35IZmlT0bK46CXUKvCqK
391 x7YXHgfhC8ZsXCtsScKJVHs7gEsNxz7A0XoibFw6DoxtjKzUCktnT0w3wxdY7OTj
392 9AR8mobFlM9W3yirX8TtwekWhDNTYEu8dwwykwIDAQABAoIBAA2hjpIhvcNR9H9Z
393 BmdEecydAQ0ZlT5zy1dvrWI++UDVmIp+Ve8BSd6T0mOqV61elmHi3sWsBN4M1Rdz
394 3N38lW2SajG9q0fAvBpSOBHgAKmfGv3Ziz5gNmtHgeEXfZ3f7J95zVGhlHqWtY95
395 JsmuplkHxFMyITN6WcMWrhQg4A3enKLhJLlaGLJf9PeBrvVxHR1/txrfENd2iJBH
396 FmxVGILL09fIIktJvoScbzVOneeWXj5vJGzWVhB17DHBbANGvVPdD5f+k/s5aooh
397 hWAy/yLKocr294C4J+gkO5h2zjjjSGcmVHfrhlXQoEPX+iW1TGoF8BMtl4Llc+jw
398 lKWKfpECgYEA9C428Z6CvAn+KJ2yhbAtuRo41kkOVoiQPtlPeRYs91Pq4+NBlfKO
399 2nWLkyavVrLx4YQeCeaEU2Xoieo9msfLZGTVxgRlztylOUR+zz2FzDBYGicuUD3s
400 EqC0Wv7tiX6dumpWyOcVVLmR9aKlOUzA9xemzIsWUwL3PpyONhKSq7kCgYEA1X2F
401 f2jKjoOVzglhtuX4/SP9GxS4gRf9rOQ1Q8DzZhyH2LZ6Dnb1uEQvGhiqJTU8CXxb
402 7odI0fgyNXq425Nlxc1Tu0G38TtJhwrx7HWHuFcbI/QpRtDYLWil8Zr7Q3BT9rdh
403 moo4m937hLMvqOG9pyIbyjOEPK2WBCtKW5yabqsCgYEAu9DkUBr1Qf+Jr+IEU9I8
404 iRkDSMeusJ6gHMd32pJVCfRRQvIlG1oTyTMKpafmzBAd/rFpjYHynFdRcutqcShm
405 aJUq3QG68U9EAvWNeIhA5tr0mUEz3WKTt4xGzYsyWES8u4tZr3QXMzD9dOuinJ1N
406 +4EEumXtSPKKDG3M8Qh+KnkCgYBUEVSTYmF5EynXc2xOCGsuy5AsrNEmzJqxDUBI
407 SN/P0uZPmTOhJIkIIZlmrlW5xye4GIde+1jajeC/nG7U0EsgRAV31J4pWQ5QJigz
408 0+g419wxIUFryGuIHhBSfpP472+w1G+T2mAGSLh1fdYDq7jx6oWE7xpghn5vb9id
409 EKLjdwKBgBtz9mzbzutIfAW0Y8F23T60nKvQ0gibE92rnUbjPnw8HjL3AZLU05N+
410 cSL5bhq0N5XHK77sscxW9vXjG0LJMXmFZPp9F6aV6ejkMIXyJ/Yz/EqeaJFwilTq
411 Mc6xR47qkdzu0dQ1aPm4XD7AWDtIvPo/GG2DKOucLBbQc2cOWtKS
412 -----END RSA PRIVATE KEY-----
413 `
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698