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

Side by Side Diff: third_party/go/src/golang.org/x/mobile/cmd/gomobile/init.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 // TODO(crawshaw): build darwin/arm cross compiler on darwin/{386,amd64}
8 // TODO(crawshaw): android/{386,arm64}
9
10 import (
11 "archive/tar"
12 "bytes"
13 "compress/gzip"
14 "fmt"
15 "io"
16 "io/ioutil"
17 "net/http"
18 "os"
19 "os/exec"
20 "path/filepath"
21 "runtime"
22 "strings"
23 )
24
25 // useStrippedNDK determines whether the init subcommand fetches the GCC
26 // toolchain from the original Android NDK, or from the stripped-down NDK
27 // hosted specifically for the gomobile tool.
28 //
29 // There is a significant size different (400MB compared to 30MB).
30 var useStrippedNDK = goos == "linux" || goos == "darwin"
31
32 const ndkVersion = "ndk-r10d"
33
34 var (
35 goos = runtime.GOOS
36 goarch = runtime.GOARCH
37 ndkarch string
38 )
39
40 func init() {
41 if runtime.GOARCH == "amd64" {
42 ndkarch = "x86_64"
43 } else {
44 ndkarch = runtime.GOARCH
45 }
46 }
47
48 var cmdInit = &command{
49 run: runInit,
50 Name: "init",
51 Short: "install android compiler toolchain",
52 Long: `
53 Init downloads and installs the Android C++ compiler toolchain.
54
55 The toolchain is installed in $GOPATH/pkg/gomobile.
56 If the Android C++ compiler toolchain already exists in the path,
57 it skips download and uses the existing toolchain.
58
59 The -u option forces download and installation of the new toolchain
60 even when the toolchain exists.
61 `,
62 }
63
64 var initU bool // -u
65
66 func init() {
67 cmdInit.flag.BoolVar(&initU, "u", false, "force toolchain download")
68 }
69
70 func runInit(cmd *command) error {
71 version, err := goVersion()
72 if err != nil {
73 return err
74 }
75
76 gopaths := filepath.SplitList(goEnv("GOPATH"))
77 if len(gopaths) == 0 {
78 return fmt.Errorf("GOPATH is not set")
79 }
80 ndkccpath = filepath.Join(gopaths[0], "pkg", "gomobile", "android-"+ndkV ersion)
81 ndkccdl := filepath.Join(ndkccpath, "downloaded")
82 verpath := filepath.Join(gopaths[0], "pkg", "gomobile", "version")
83 if buildX {
84 fmt.Fprintln(xout, "NDKCCPATH="+ndkccpath)
85 }
86
87 needNDK := initU
88 if !needNDK {
89 if _, err := os.Stat(ndkccdl); err != nil {
90 needNDK = true
91 }
92 }
93
94 if needNDK {
95 if err := removeAll(ndkccpath); err != nil && !os.IsExist(err) {
96 return err
97 }
98 if err := mkdir(ndkccpath); err != nil {
99 return err
100 }
101 }
102
103 if buildN {
104 tmpdir = filepath.Join(ndkccpath, "work")
105 } else {
106 var err error
107 tmpdir, err = ioutil.TempDir(ndkccpath, "gomobile-init-")
108 if err != nil {
109 return err
110 }
111 }
112 if buildX {
113 fmt.Fprintln(xout, "WORK="+tmpdir)
114 }
115 defer removeAll(tmpdir)
116
117 goroot := goEnv("GOROOT")
118 tmpGoroot := filepath.Join(tmpdir, "go")
119 if err := copyGoroot(tmpGoroot, goroot); err != nil {
120 return err
121 }
122
123 if needNDK {
124 if err := fetchNDK(); err != nil {
125 return err
126 }
127
128 if !buildN {
129 if err := ioutil.WriteFile(ndkccdl, []byte("done"), 0644 ); err != nil {
130 return err
131 }
132 }
133 }
134
135 dst := filepath.Join(ndkccpath, "arm")
136
137 // TODO(crawshaw): make.bat on windows
138 ndkccbin := filepath.Join(dst, "bin")
139 envpath := os.Getenv("PATH")
140 if buildN {
141 envpath = "$PATH"
142 }
143 make := exec.Command(filepath.Join(tmpGoroot, "src", "make.bash"), "--no -clean")
144 make.Dir = filepath.Join(tmpGoroot, "src")
145 make.Env = []string{
146 `PATH=` + envpath,
147 `TMPDIR=` + tmpdir,
148 `HOME=` + os.Getenv("HOME"), // for default the go1.4 bootstrap
149 `GOOS=android`,
150 `GOARCH=arm`,
151 `GOARM=7`,
152 `CGO_ENABLED=1`,
153 `CC_FOR_TARGET=` + filepath.Join(ndkccbin, "arm-linux-androideab i-gcc"),
154 `CXX_FOR_TARGET=` + filepath.Join(ndkccbin, "arm-linux-androidea bi-g++"),
155 }
156 if v := goEnv("GOROOT_BOOTSTRAP"); v != "" {
157 make.Env = append(make.Env, `GOROOT_BOOTSTRAP=`+v)
158 }
159 if buildV {
160 fmt.Fprintf(os.Stderr, "building android/arm cross compiler\n")
161 make.Stdout = os.Stdout
162 make.Stderr = os.Stderr
163 }
164 if buildX {
165 printcmd("%s", strings.Join(make.Env, " ")+" "+strings.Join(make .Args, " "))
166 }
167 if !buildN {
168 if err := make.Run(); err != nil {
169 return err
170 }
171 }
172
173 // Move the Go cross compiler toolchain into GOPATH.
174 gotoolsrc := filepath.Join(tmpGoroot, "pkg", "tool", goos+"_"+goarch)
175 if err := move(ndkccbin, gotoolsrc, "5a", "5l", "5g", "cgo", "nm", "pack ", "link"); err != nil {
176 return err
177 }
178
179 // Build toolexec command.
180 toolexecSrc := filepath.Join(tmpdir, "toolexec.go")
181 if !buildN {
182 if err := ioutil.WriteFile(toolexecSrc, []byte(toolexec), 0644); err != nil {
183 return err
184 }
185 }
186 make = exec.Command("go", "build", "-o", filepath.Join(ndkccbin, "toolex ec"), toolexecSrc)
187 if buildV {
188 fmt.Fprintf(os.Stderr, "building gomobile toolexec\n")
189 make.Stdout = os.Stdout
190 make.Stderr = os.Stderr
191 }
192 if buildX {
193 printcmd("%s", strings.Join(make.Args, " "))
194 }
195 if !buildN {
196 if err := make.Run(); err != nil {
197 return err
198 }
199 }
200
201 // Move pre-compiled stdlib for android into GOROOT. This is
202 // the only time we modify the user's GOROOT.
203 cannotRemove := false
204 if err := removeAll(filepath.Join(goroot, "pkg", "android_arm")); err != nil {
205 cannotRemove = true
206 }
207 if err := move(filepath.Join(goroot, "pkg"), filepath.Join(tmpGoroot, "p kg"), "android_arm"); err != nil {
208 // Move android_arm into a temp directory that outlives
209 // this process and give the user installation instructions.
210 dir, err := ioutil.TempDir("", "gomobile-")
211 if err != nil {
212 return err
213 }
214 if err := move(dir, filepath.Join(tmpGoroot, "pkg"), "android_ar m"); err != nil {
215 return err
216 }
217 // TODO: modify instructions for windows.
218 remove := ""
219 if cannotRemove {
220 remove = "\trm -r -f %s/pkg/android_arm\n"
221 }
222 return fmt.Errorf(
223 `Cannot install android/arm in GOROOT.
224 Make GOROOT writable (possibly by becoming the super user, using sudo) and run:
225 %s mv %s %s`,
226 remove,
227 filepath.Join(dir, "android_arm"),
228 filepath.Join(goroot, "pkg"),
229 )
230 }
231
232 if buildX {
233 printcmd("go version > %s", verpath)
234 }
235 if !buildN {
236 if err := ioutil.WriteFile(verpath, version, 0644); err != nil {
237 return err
238 }
239 }
240
241 return nil
242 }
243
244 // toolexec is the source of a small program designed to be passed to
245 // the -toolexec flag of go build.
246 const toolexec = `package main
247
248 import (
249 "fmt"
250 "os"
251 "os/exec"
252 "path/filepath"
253 )
254
255 func main() {
256 args := append([]string{}, os.Args[1:]...)
257 args[0] = filepath.Join(os.Getenv("GOMOBILEPATH"), filepath.Base(args[0] ))
258 cmd := exec.Command(args[0], args[1:]...)
259 cmd.Stdout = os.Stdout
260 cmd.Stderr = os.Stderr
261 if err := cmd.Run(); err != nil {
262 fmt.Fprintf(os.Stderr, "%v\n", err)
263 os.Exit(1)
264 }
265 }
266 `
267
268 func move(dst, src string, names ...string) error {
269 for _, name := range names {
270 srcf := filepath.Join(src, name)
271 dstf := filepath.Join(dst, name)
272 if buildX {
273 printcmd("mv %s %s", srcf, dstf)
274 }
275 if buildN {
276 continue
277 }
278 if err := os.Rename(srcf, dstf); err != nil {
279 return err
280 }
281 }
282 return nil
283 }
284
285 func mkdir(dir string) error {
286 if buildX {
287 printcmd("mkdir -p %s", dir)
288 }
289 if buildN {
290 return nil
291 }
292 return os.MkdirAll(dir, 0755)
293 }
294
295 func symlink(src, dst string) error {
296 if buildX {
297 printcmd("ln -s %s %s", src, dst)
298 }
299 if buildN {
300 return nil
301 }
302 return os.Symlink(src, dst)
303 }
304
305 func rm(name string) error {
306 if buildX {
307 printcmd("rm %s", name)
308 }
309 if buildN {
310 return nil
311 }
312 return os.Remove(name)
313 }
314
315 func goVersion() ([]byte, error) {
316 if err := exec.Command("which", "go").Run(); err != nil {
317 return nil, fmt.Errorf(`no Go tool on $PATH`)
318 }
319 buildHelp, err := exec.Command("go", "help", "build").Output()
320 if err != nil {
321 return nil, fmt.Errorf("bad Go tool: %v", err)
322 }
323 if !bytes.Contains(buildHelp, []byte("-toolexec")) {
324 return nil, fmt.Errorf("installed Go tool does not support -tool exec")
325 }
326 return exec.Command("go", "version").Output()
327 }
328
329 func fetchNDK() error {
330 if useStrippedNDK {
331 if err := fetchStrippedNDK(); err != nil {
332 return err
333 }
334 } else {
335 ndkName := "android-" + ndkVersion + "-" + goos + "-" + ndkarch + "."
336 if goos == "windows" {
337 ndkName += "exe"
338 } else {
339 ndkName += "bin"
340 }
341 url := "https://dl.google.com/android/ndk/" + ndkName
342 if err := fetch(filepath.Join(tmpdir, ndkName), url); err != nil {
343 return err
344 }
345
346 inflate := exec.Command(filepath.Join(tmpdir, ndkName))
347 inflate.Dir = tmpdir
348 if buildX {
349 printcmd("%s", inflate.Args[0])
350 }
351 if !buildN {
352 out, err := inflate.CombinedOutput()
353 if err != nil {
354 if buildV {
355 os.Stderr.Write(out)
356 }
357 return err
358 }
359 }
360 }
361
362 dst := filepath.Join(ndkccpath, "arm")
363 dstSysroot := filepath.Join(dst, "sysroot", "usr")
364 if err := mkdir(dstSysroot); err != nil {
365 return err
366 }
367
368 srcSysroot := filepath.Join(tmpdir, "android-ndk-r10d", "platforms", "an droid-15", "arch-arm", "usr")
369 if err := move(dstSysroot, srcSysroot, "include", "lib"); err != nil {
370 return err
371 }
372
373 ndkpath := filepath.Join(tmpdir, "android-ndk-r10d", "toolchains", "arm- linux-androideabi-4.8", "prebuilt", goos+"-"+ndkarch)
374 if err := move(dst, ndkpath, "bin", "lib", "libexec"); err != nil {
375 return err
376 }
377
378 linkpath := filepath.Join(dst, "arm-linux-androideabi", "bin")
379 if err := mkdir(linkpath); err != nil {
380 return err
381 }
382 for _, name := range []string{"ld", "as", "gcc", "g++"} {
383 if err := symlink(filepath.Join(dst, "bin", "arm-linux-androidea bi-"+name), filepath.Join(linkpath, name)); err != nil {
384 return err
385 }
386 }
387 return nil
388 }
389
390 func fetchStrippedNDK() error {
391 name := "gomobile-ndk-r10d-" + goos + "-" + ndkarch + ".tar.gz"
392 url := "https://dl.google.com/go/mobile/" + name
393 if err := fetch(filepath.Join(tmpdir, name), url); err != nil {
394 return err
395 }
396 if buildX {
397 printcmd("tar xfz %s", name)
398 }
399 if buildN {
400 return nil
401 }
402
403 tf, err := os.Open(filepath.Join(tmpdir, name))
404 if err != nil {
405 return err
406 }
407 defer tf.Close()
408 zr, err := gzip.NewReader(tf)
409 if err != nil {
410 return err
411 }
412 tr := tar.NewReader(zr)
413 for {
414 hdr, err := tr.Next()
415 if err == io.EOF {
416 break
417 }
418 if err != nil {
419 return err
420 }
421 dst := filepath.Join(tmpdir, hdr.Name)
422 if hdr.Typeflag == tar.TypeSymlink {
423 if err := symlink(hdr.Linkname, dst); err != nil {
424 return err
425 }
426 continue
427 }
428 if err := os.MkdirAll(filepath.Dir(dst), 0755); err != nil {
429 return err
430 }
431 f, err := os.OpenFile(dst, os.O_CREATE|os.O_EXCL|os.O_WRONLY, os .FileMode(hdr.Mode)&0777)
432 if err != nil {
433 return err
434 }
435 if _, err := io.Copy(f, tr); err != nil {
436 return err
437 }
438 if err := f.Close(); err != nil {
439 return err
440 }
441 }
442 return nil
443 }
444
445 func fetch(dst, url string) error {
446 if buildV {
447 fmt.Fprintf(os.Stderr, "fetching %s\n", url)
448 }
449 if buildX {
450 printcmd("curl -o%s %s", dst, url)
451 }
452 if buildN {
453 return nil
454 }
455
456 f, err := os.OpenFile(dst, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0755)
457 if err != nil {
458 return err
459 }
460
461 resp, err := http.Get(url)
462 if err != nil {
463 return err
464 }
465 _, err = io.Copy(f, resp.Body)
466 err2 := resp.Body.Close()
467 err3 := f.Close()
468 if err != nil {
469 return err
470 }
471 if err2 != nil {
472 return err2
473 }
474 return err3
475 }
476
477 // copyGoroot copies GOROOT from src to dst.
478 //
479 // It skips the pkg directory, which is not necessary for make.bash,
480 // and symlinks .git to avoid a 70MB copy.
481 func copyGoroot(dst, src string) error {
482 if err := mkdir(filepath.Join(dst, "pkg")); err != nil {
483 return err
484 }
485 for _, dir := range []string{"include", "lib", "src"} {
486 if err := copyAll(filepath.Join(dst, dir), filepath.Join(src, di r)); err != nil {
487 return err
488 }
489 }
490 return symlink(filepath.Join(src, ".git"), filepath.Join(dst, ".git"))
491 }
492
493 func copyAll(dst, src string) error {
494 if buildX {
495 printcmd("cp -a %s %s", src, dst)
496 }
497 if buildN {
498 return nil
499 }
500 return filepath.Walk(src, func(path string, info os.FileInfo, errin erro r) (err error) {
501 if errin != nil {
502 return errin
503 }
504 prefixLen := len(src)
505 if len(path) > prefixLen {
506 prefixLen++ // file separator
507 }
508 outpath := filepath.Join(dst, path[prefixLen:])
509 if info.IsDir() {
510 return os.Mkdir(outpath, 0755)
511 }
512 in, err := os.Open(path)
513 if err != nil {
514 return err
515 }
516 defer in.Close()
517 out, err := os.OpenFile(outpath, os.O_CREATE|os.O_EXCL|os.O_WRON LY, info.Mode())
518 if err != nil {
519 return err
520 }
521 defer func() {
522 if errc := out.Close(); err == nil {
523 err = errc
524 }
525 }()
526 _, err = io.Copy(out, in)
527 return err
528 })
529 }
530
531 func removeAll(path string) error {
532 if buildX {
533 printcmd("rm -r -f %q", path)
534 }
535 if buildN {
536 return nil
537 }
538 return os.RemoveAll(path)
539 }
540
541 func goEnv(name string) string {
542 if val := os.Getenv(name); val != "" {
543 return val
544 }
545 val, err := exec.Command("go", "env", name).Output()
546 if err != nil {
547 panic(err) // the Go tool was tested to work earlier
548 }
549 return strings.TrimSpace(string(val))
550 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698