| OLD | NEW |
| (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 //+build ignore | |
| 6 | |
| 7 // Release is a tool for building the NDK tarballs hosted on dl.google.com. | |
| 8 // | |
| 9 // The Go toolchain only needs the gcc compiler and headers, which are ~10MB. | |
| 10 // The entire NDK is ~400MB. Building smaller toolchain binaries reduces the | |
| 11 // run time of gomobile init significantly. | |
| 12 package main | |
| 13 | |
| 14 import ( | |
| 15 "archive/tar" | |
| 16 "bufio" | |
| 17 "compress/gzip" | |
| 18 "fmt" | |
| 19 "io" | |
| 20 "io/ioutil" | |
| 21 "log" | |
| 22 "net/http" | |
| 23 "os" | |
| 24 "os/exec" | |
| 25 "path/filepath" | |
| 26 "runtime" | |
| 27 ) | |
| 28 | |
| 29 const ndkVersion = "ndk-r10d" | |
| 30 | |
| 31 type version struct { | |
| 32 os string | |
| 33 arch string | |
| 34 } | |
| 35 | |
| 36 var hosts = []version{ | |
| 37 // TODO: windows | |
| 38 {"darwin", "x86"}, | |
| 39 {"darwin", "x86_64"}, | |
| 40 {"linux", "x86"}, | |
| 41 {"linux", "x86_64"}, | |
| 42 } | |
| 43 | |
| 44 var tmpdir string | |
| 45 | |
| 46 func main() { | |
| 47 var err error | |
| 48 tmpdir, err = ioutil.TempDir("", "gomobile-release-") | |
| 49 if err != nil { | |
| 50 log.Fatal(err) | |
| 51 } | |
| 52 defer os.RemoveAll(tmpdir) | |
| 53 | |
| 54 for _, host := range hosts { | |
| 55 if err := mkpkg(host); err != nil { | |
| 56 log.Fatal(err) | |
| 57 } | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 func mkpkg(host version) (err error) { | |
| 62 ndkName := "android-" + ndkVersion + "-" + host.os + "-" + host.arch + "
." | |
| 63 if host.os == "windows" { | |
| 64 ndkName += "exe" | |
| 65 } else { | |
| 66 ndkName += "bin" | |
| 67 } | |
| 68 url := "http://dl.google.com/android/ndk/" + ndkName | |
| 69 log.Printf("%s\n", url) | |
| 70 binPath := tmpdir + "/" + ndkName | |
| 71 if err := fetch(binPath, url); err != nil { | |
| 72 log.Fatal(err) | |
| 73 } | |
| 74 | |
| 75 src := tmpdir + "/" + host.os + "-" + host.arch + "-src" | |
| 76 dst := tmpdir + "/" + host.os + "-" + host.arch + "-dst" | |
| 77 if err := os.Mkdir(src, 0755); err != nil { | |
| 78 return err | |
| 79 } | |
| 80 if err := inflate(src, binPath); err != nil { | |
| 81 return err | |
| 82 } | |
| 83 | |
| 84 // The NDK is unpacked into tmpdir/linux-x86_64-src/android-ndk-r10d. | |
| 85 // Move the files we want into tmpdir/linux-x86_64-dst/android-ndk-r10d. | |
| 86 // We preserve the same file layout to make the full NDK interchangable | |
| 87 // with the cut down file. | |
| 88 usr := "android-" + ndkVersion + "/platforms/android-15/arch-arm/usr" | |
| 89 gcc := "android-" + ndkVersion + "/toolchains/arm-linux-androideabi-4.8/
prebuilt/" + host.os + "-" + host.arch | |
| 90 if err := os.MkdirAll(dst+"/"+usr, 0755); err != nil { | |
| 91 return err | |
| 92 } | |
| 93 if err := os.MkdirAll(dst+"/"+gcc, 0755); err != nil { | |
| 94 return err | |
| 95 } | |
| 96 if err := move(dst+"/"+usr, src+"/"+usr, "include", "lib"); err != nil { | |
| 97 return err | |
| 98 } | |
| 99 if err := move(dst+"/"+gcc, src+"/"+gcc, "bin", "lib", "libexec", "COPYI
NG", "COPYING.LIB"); err != nil { | |
| 100 return err | |
| 101 } | |
| 102 | |
| 103 // Build the tarball. | |
| 104 f, err := os.Create("gomobile-ndk-r10d-" + host.os + "-" + host.arch + "
.tar.gz") | |
| 105 if err != nil { | |
| 106 return err | |
| 107 } | |
| 108 bw := bufio.NewWriter(f) | |
| 109 zw, err := gzip.NewWriterLevel(bw, gzip.BestCompression) | |
| 110 if err != nil { | |
| 111 return err | |
| 112 } | |
| 113 tw := tar.NewWriter(zw) | |
| 114 defer func() { | |
| 115 err2 := f.Close() | |
| 116 if err == nil { | |
| 117 err = err2 | |
| 118 } | |
| 119 }() | |
| 120 defer func() { | |
| 121 err2 := bw.Flush() | |
| 122 if err == nil { | |
| 123 err = err2 | |
| 124 } | |
| 125 }() | |
| 126 defer func() { | |
| 127 err2 := zw.Close() | |
| 128 if err == nil { | |
| 129 err = err2 | |
| 130 } | |
| 131 }() | |
| 132 defer func() { | |
| 133 err2 := tw.Close() | |
| 134 if err == nil { | |
| 135 err = err2 | |
| 136 } | |
| 137 }() | |
| 138 | |
| 139 readme := "Stripped down copy of:\n\n\t" + url + "\n\nGenerated by golan
g.org/x/mobile/cmd/gomobile/release.go." | |
| 140 err = tw.WriteHeader(&tar.Header{ | |
| 141 Name: "README", | |
| 142 Mode: 0644, | |
| 143 Size: int64(len(readme)), | |
| 144 }) | |
| 145 if err != nil { | |
| 146 return err | |
| 147 } | |
| 148 _, err = tw.Write([]byte(readme)) | |
| 149 if err != nil { | |
| 150 return err | |
| 151 } | |
| 152 | |
| 153 return filepath.Walk(dst, func(path string, fi os.FileInfo, err error) e
rror { | |
| 154 defer func() { | |
| 155 if err != nil { | |
| 156 err = fmt.Errorf("%s: %v", path, err) | |
| 157 } | |
| 158 }() | |
| 159 if err != nil { | |
| 160 return err | |
| 161 } | |
| 162 if path == dst { | |
| 163 return nil | |
| 164 } | |
| 165 name := path[len(dst)+1:] | |
| 166 if fi.IsDir() { | |
| 167 return nil | |
| 168 } | |
| 169 if fi.Mode()&os.ModeSymlink != 0 { | |
| 170 dst, err := os.Readlink(path) | |
| 171 if err != nil { | |
| 172 log.Printf("bad symlink: %s", name) | |
| 173 return nil | |
| 174 } | |
| 175 //log.Printf("linking %s to %s", name, dst) | |
| 176 return tw.WriteHeader(&tar.Header{ | |
| 177 Name: name, | |
| 178 Linkname: dst, | |
| 179 Typeflag: tar.TypeSymlink, | |
| 180 }) | |
| 181 } | |
| 182 //log.Printf("writing %s (%d)", name, fi.Size()) | |
| 183 err = tw.WriteHeader(&tar.Header{ | |
| 184 Name: name, | |
| 185 Mode: int64(fi.Mode()), | |
| 186 Size: fi.Size(), | |
| 187 }) | |
| 188 if err != nil { | |
| 189 return err | |
| 190 } | |
| 191 f, err := os.Open(path) | |
| 192 if err != nil { | |
| 193 return err | |
| 194 } | |
| 195 _, err = io.Copy(tw, f) | |
| 196 f.Close() | |
| 197 return err | |
| 198 }) | |
| 199 } | |
| 200 | |
| 201 func fetch(dst, url string) error { | |
| 202 f, err := os.OpenFile(dst, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0755) | |
| 203 if err != nil { | |
| 204 return err | |
| 205 } | |
| 206 resp, err := http.Get(url) | |
| 207 if err != nil { | |
| 208 return err | |
| 209 } | |
| 210 _, err = io.Copy(f, resp.Body) | |
| 211 err2 := resp.Body.Close() | |
| 212 err3 := f.Close() | |
| 213 if err != nil { | |
| 214 return err | |
| 215 } | |
| 216 if err2 != nil { | |
| 217 return err2 | |
| 218 } | |
| 219 return err3 | |
| 220 } | |
| 221 | |
| 222 func inflate(dst, path string) error { | |
| 223 p7zip := "7z" | |
| 224 if runtime.GOOS == "darwin" { | |
| 225 p7zip = "/Applications/Keka.app/Contents/Resources/keka7z" | |
| 226 } | |
| 227 cmd := exec.Command(p7zip, "x", path) | |
| 228 cmd.Dir = dst | |
| 229 out, err := cmd.CombinedOutput() | |
| 230 if err != nil { | |
| 231 os.Stderr.Write(out) | |
| 232 return err | |
| 233 } | |
| 234 return nil | |
| 235 } | |
| 236 | |
| 237 func move(dst, src string, names ...string) error { | |
| 238 for _, name := range names { | |
| 239 if err := os.Rename(src+"/"+name, dst+"/"+name); err != nil { | |
| 240 return err | |
| 241 } | |
| 242 } | |
| 243 return nil | |
| 244 } | |
| OLD | NEW |