@@ -51,8 +51,8 @@ func run(args ...string) string {
51
51
}
52
52
53
53
const (
54
- deviceGoroot = "/data/local/tmp/goroot "
55
- deviceGopath = "/data/local/tmp/gopath "
54
+ deviceRoot = "/data/local/tmp/go_exec_android "
55
+ deviceGoroot = deviceRoot + "/goroot "
56
56
)
57
57
58
58
func main () {
@@ -77,35 +77,44 @@ func main() {
77
77
// wait for sys.boot_completed.
78
78
run ("wait-for-device" , "exec-out" , "while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done;" )
79
79
80
+ // Done once per make.bash.
81
+ adbCopyGoroot ()
82
+
80
83
// Prepare a temporary directory that will be cleaned up at the end.
81
- deviceGotmp := fmt .Sprintf ("/data/local/tmp/%s-%d" ,
82
- filepath .Base (os .Args [1 ]), os .Getpid ())
83
- run ("exec-out" , "mkdir" , "-p" , deviceGotmp )
84
+ // Binary names can conflict.
85
+ // E.g. template.test from the {html,text}/template packages.
86
+ binName := filepath .Base (os .Args [1 ])
87
+ deviceGotmp := fmt .Sprintf (deviceRoot + "/%s-%d" , binName , os .Getpid ())
88
+ deviceGopath := deviceGotmp + "/gopath"
89
+ defer run ("exec-out" , "rm" , "-rf" , deviceGotmp ) // Clean up.
84
90
85
91
// Determine the package by examining the current working
86
92
// directory, which will look something like
87
93
// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
88
94
// We extract everything after the $GOROOT or $GOPATH to run on the
89
95
// same relative directory on the target device.
90
96
subdir , inGoRoot := subdir ()
91
- deviceCwd := filepath .Join (deviceGoroot , subdir )
92
- if ! inGoRoot {
93
- deviceCwd = filepath .Join (deviceGopath , subdir )
97
+ deviceCwd := filepath .Join (deviceGopath , subdir )
98
+ if inGoRoot {
99
+ deviceCwd = filepath .Join (deviceGoroot , subdir )
94
100
} else {
95
- adbSyncGoroot ()
101
+ run ("exec-out" , "mkdir" , "-p" , deviceCwd )
102
+ adbCopyTestdata (deviceCwd , subdir )
103
+
104
+ // Copy .go files from the package.
105
+ goFiles , err := filepath .Glob ("*.go" )
106
+ if err != nil {
107
+ log .Fatal (err )
108
+ }
109
+ if len (goFiles ) > 0 {
110
+ args := append (append ([]string {"push" }, goFiles ... ), deviceCwd )
111
+ run (args ... )
112
+ }
96
113
}
97
- run ("exec-out" , "mkdir" , "-p" , deviceCwd )
98
114
99
- // Binary names can conflict.
100
- // E.g. template.test from the {html,text}/template packages.
101
- binName := fmt .Sprintf ("%s-%d" , filepath .Base (os .Args [1 ]), os .Getpid ())
102
115
deviceBin := fmt .Sprintf ("%s/%s" , deviceGotmp , binName )
103
116
run ("push" , os .Args [1 ], deviceBin )
104
117
105
- if _ , err := os .Stat ("testdata" ); err == nil {
106
- run ("push" , "--sync" , "testdata" , deviceCwd )
107
- }
108
-
109
118
// Forward SIGQUIT from the go command to show backtraces from
110
119
// the binary instead of from this wrapper.
111
120
quit := make (chan os.Signal , 1 )
@@ -125,15 +134,16 @@ func main() {
125
134
cmd := `export TMPDIR="` + deviceGotmp + `"` +
126
135
`; export GOROOT="` + deviceGoroot + `"` +
127
136
`; export GOPATH="` + deviceGopath + `"` +
137
+ `; export CGO_ENABLED=0` +
138
+ `; export GOCACHE="` + deviceRoot + `/gocache"` +
139
+ `; export PATH=$PATH:"` + deviceGoroot + `/bin"` +
128
140
`; cd "` + deviceCwd + `"` +
129
141
"; '" + deviceBin + "' " + strings .Join (os .Args [2 :], " " ) +
130
142
"; echo -n " + exitstr + "$?"
131
143
output := run ("exec-out" , cmd )
132
144
signal .Reset (syscall .SIGQUIT )
133
145
close (quit )
134
146
135
- run ("exec-out" , "rm" , "-rf" , deviceGotmp ) // Clean up.
136
-
137
147
exitIdx := strings .LastIndex (output , exitstr )
138
148
if exitIdx == - 1 {
139
149
log .Fatalf ("no exit code: %q" , output )
@@ -186,17 +196,42 @@ func subdir() (pkgpath string, underGoRoot bool) {
186
196
return "" , false
187
197
}
188
198
189
- // adbSyncGoroot ensures that files necessary for testing the Go standard
190
- // packages are present on the attached device.
191
- func adbSyncGoroot () {
199
+ // adbCopyTestdata copies testdata directories from subdir to deviceCwd
200
+ // on the device.
201
+ // It is common for tests to reach out into testdata from parent
202
+ // packages, so copy testdata directories all the way up to the root
203
+ // of subdir.
204
+ func adbCopyTestdata (deviceCwd , subdir string ) {
205
+ dir := ""
206
+ for {
207
+ testdata := filepath .Join (dir , "testdata" )
208
+ if _ , err := os .Stat (testdata ); err == nil {
209
+ devicePath := filepath .Join (deviceCwd , dir )
210
+ run ("exec-out" , "mkdir" , "-p" , devicePath )
211
+ run ("push" , testdata , devicePath )
212
+ }
213
+ if subdir == "." {
214
+ break
215
+ }
216
+ subdir = filepath .Dir (subdir )
217
+ dir = filepath .Join (dir , ".." )
218
+ }
219
+ }
220
+
221
+ // adbCopyGoroot clears deviceRoot for previous versions of GOROOT, GOPATH
222
+ // and temporary data. Then, it copies relevant parts of GOROOT to the device,
223
+ // including the go tool built for android.
224
+ // A lock file ensures this only happens once, even with concurrent exec
225
+ // wrappers.
226
+ func adbCopyGoroot () {
192
227
// Also known by cmd/dist. The bootstrap command deletes the file.
193
228
statPath := filepath .Join (os .TempDir (), "go_android_exec-adb-sync-status" )
194
229
stat , err := os .OpenFile (statPath , os .O_CREATE | os .O_RDWR , 0666 )
195
230
if err != nil {
196
231
log .Fatal (err )
197
232
}
198
233
defer stat .Close ()
199
- // Serialize check and syncing .
234
+ // Serialize check and copying .
200
235
if err := syscall .Flock (int (stat .Fd ()), syscall .LOCK_EX ); err != nil {
201
236
log .Fatal (err )
202
237
}
@@ -207,23 +242,29 @@ func adbSyncGoroot() {
207
242
if string (s ) == "done" {
208
243
return
209
244
}
210
- devRoot := "/data/local/tmp/goroot"
211
- run ("exec-out" , "rm" , "-rf" , devRoot )
212
- run ("exec-out" , "mkdir" , "-p" , devRoot + "/pkg" )
245
+ // Delete GOROOT, GOPATH and any leftover test data.
246
+ run ("exec-out" , "rm" , "-rf" , deviceRoot )
247
+ deviceBin := filepath .Join (deviceGoroot , "bin" )
248
+ run ("exec-out" , "mkdir" , "-p" , deviceBin )
213
249
goroot := runtime .GOROOT ()
250
+ // Build go for android.
214
251
goCmd := filepath .Join (goroot , "bin" , "go" )
215
- runtimea , err := exec . Command ( goCmd , "list " , "-f" , "{{.Target}}" , "runtime" ). Output ( )
252
+ tmpGo , err := ioutil . TempFile ( " " , "go_android_exec-cmd-go-*" )
216
253
if err != nil {
217
254
log .Fatal (err )
218
255
}
219
- pkgdir := filepath .Dir (string (runtimea ))
220
- if pkgdir == "" {
221
- log .Fatal ("could not find android pkg dir" )
256
+ tmpGo .Close ()
257
+ defer os .Remove (tmpGo .Name ())
258
+
259
+ if out , err := exec .Command (goCmd , "build" , "-o" , tmpGo .Name (), "cmd/go" ).CombinedOutput (); err != nil {
260
+ log .Fatalf ("failed to build go tool for device: %s\n %v" , out , err )
222
261
}
223
- for _ , dir := range []string {"src" , "test" , "lib" } {
224
- run ("push" , filepath .Join (goroot , dir ), filepath .Join (devRoot ))
262
+ deviceGo := filepath .Join (deviceBin , "go" )
263
+ run ("push" , tmpGo .Name (), deviceGo )
264
+ for _ , dir := range []string {"pkg" , "src" , "test" , "lib" , "api" } {
265
+ run ("push" , filepath .Join (goroot , dir ), filepath .Join (deviceGoroot ))
225
266
}
226
- run ( "push" , filepath . Join ( pkgdir ), filepath . Join ( devRoot , "pkg/" ))
267
+
227
268
if _ , err := stat .Write ([]byte ("done" )); err != nil {
228
269
log .Fatal (err )
229
270
}
0 commit comments