Merge lp:~mwhudson/ubuntu/utopic/gccgo-go/build-cgo into lp:ubuntu/utopic/gccgo-go
- Utopic (14.10)
- build-cgo
- Merge into utopic
Proposed by
Michael Hudson-Doyle
Status: | Work in progress |
---|---|
Proposed branch: | lp:~mwhudson/ubuntu/utopic/gccgo-go/build-cgo |
Merge into: | lp:ubuntu/utopic/gccgo-go |
Diff against target: |
1972 lines (+1870/-1) 12 files modified
.pc/applied-patches (+1/-0) .pc/build-cgo.diff/src/cmd/cgo/gcc.go (+1633/-0) .pc/build-cgo.diff/src/cmd/go/tool.go (+156/-0) debian/changelog (+6/-0) debian/install (+1/-0) debian/lintian-overrides (+1/-0) debian/patches/build-cgo.diff (+49/-0) debian/patches/series (+1/-0) debian/rules (+2/-0) src/cmd/cgo/Makefile (+16/-0) src/cmd/cgo/gcc.go (+1/-1) src/cmd/go/tool.go (+3/-0) |
To merge this branch: | bzr merge lp:~mwhudson/ubuntu/utopic/gccgo-go/build-cgo |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Page | Pending | ||
Review via email: mp+230739@code.launchpad.net |
Commit message
Description of the change
This branch builds and installs cgo. It also makes things so that "go tool cgo" works. It's probably all horrible but it's a start :)
To post a comment you must log in.
Unmerged revisions
- 15. By Michael Hudson-Doyle <mwhudson@narsil>
-
lintian overrides
- 14. By Michael Hudson-Doyle <mwhudson@narsil>
-
install cgo
- 13. By Michael Hudson-Doyle <mwhudson@narsil>
-
updates
- 12. By Michael Hudson-Doyle <mwhudson@narsil>
-
quilt updates
- 11. By Michael Hudson-Doyle <mwhudson@narsil>
-
update version
- 10. By Michael Hudson-Doyle <mwhudson@narsil>
-
Build cgo too
- 9. By Michael Hudson-Doyle <mwhudson@narsil>
-
Add broken Makefile for cgo
- 8. By Michael Hudson-Doyle <mwhudson@narsil>
-
set ToolDir to something more sensible
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file '.pc/applied-patches' |
2 | --- .pc/applied-patches 2014-03-26 10:50:18 +0000 |
3 | +++ .pc/applied-patches 2014-08-14 02:29:21 +0000 |
4 | @@ -5,3 +5,4 @@ |
5 | issue28050043_60001_70001.diff |
6 | issue61970044_80001.diff |
7 | issue80300043_60001.diff |
8 | +build-cgo.diff |
9 | |
10 | === added directory '.pc/build-cgo.diff' |
11 | === added file '.pc/build-cgo.diff/.timestamp' |
12 | === added directory '.pc/build-cgo.diff/src' |
13 | === added directory '.pc/build-cgo.diff/src/cmd' |
14 | === added directory '.pc/build-cgo.diff/src/cmd/cgo' |
15 | === added file '.pc/build-cgo.diff/src/cmd/cgo/Makefile' |
16 | === added file '.pc/build-cgo.diff/src/cmd/cgo/gcc.go' |
17 | --- .pc/build-cgo.diff/src/cmd/cgo/gcc.go 1970-01-01 00:00:00 +0000 |
18 | +++ .pc/build-cgo.diff/src/cmd/cgo/gcc.go 2014-08-14 02:29:21 +0000 |
19 | @@ -0,0 +1,1633 @@ |
20 | +// Copyright 2009 The Go Authors. All rights reserved. |
21 | +// Use of this source code is governed by a BSD-style |
22 | +// license that can be found in the LICENSE file. |
23 | + |
24 | +// Annotate Ref in Prog with C types by parsing gcc debug output. |
25 | +// Conversion of debug output to Go types. |
26 | + |
27 | +package main |
28 | + |
29 | +import ( |
30 | + "bytes" |
31 | + "debug/dwarf" |
32 | + "debug/elf" |
33 | + "debug/macho" |
34 | + "debug/pe" |
35 | + "encoding/binary" |
36 | + "errors" |
37 | + "flag" |
38 | + "fmt" |
39 | + "go/ast" |
40 | + "go/parser" |
41 | + "go/token" |
42 | + "os" |
43 | + "strconv" |
44 | + "strings" |
45 | + "unicode" |
46 | + "unicode/utf8" |
47 | +) |
48 | + |
49 | +var debugDefine = flag.Bool("debug-define", false, "print relevant #defines") |
50 | +var debugGcc = flag.Bool("debug-gcc", false, "print gcc invocations") |
51 | + |
52 | +var nameToC = map[string]string{ |
53 | + "schar": "signed char", |
54 | + "uchar": "unsigned char", |
55 | + "ushort": "unsigned short", |
56 | + "uint": "unsigned int", |
57 | + "ulong": "unsigned long", |
58 | + "longlong": "long long", |
59 | + "ulonglong": "unsigned long long", |
60 | + "complexfloat": "float complex", |
61 | + "complexdouble": "double complex", |
62 | +} |
63 | + |
64 | +// cname returns the C name to use for C.s. |
65 | +// The expansions are listed in nameToC and also |
66 | +// struct_foo becomes "struct foo", and similarly for |
67 | +// union and enum. |
68 | +func cname(s string) string { |
69 | + if t, ok := nameToC[s]; ok { |
70 | + return t |
71 | + } |
72 | + |
73 | + if strings.HasPrefix(s, "struct_") { |
74 | + return "struct " + s[len("struct_"):] |
75 | + } |
76 | + if strings.HasPrefix(s, "union_") { |
77 | + return "union " + s[len("union_"):] |
78 | + } |
79 | + if strings.HasPrefix(s, "enum_") { |
80 | + return "enum " + s[len("enum_"):] |
81 | + } |
82 | + if strings.HasPrefix(s, "sizeof_") { |
83 | + return "sizeof(" + cname(s[len("sizeof_"):]) + ")" |
84 | + } |
85 | + return s |
86 | +} |
87 | + |
88 | +// DiscardCgoDirectives processes the import C preamble, and discards |
89 | +// all #cgo CFLAGS and LDFLAGS directives, so they don't make their |
90 | +// way into _cgo_export.h. |
91 | +func (f *File) DiscardCgoDirectives() { |
92 | + linesIn := strings.Split(f.Preamble, "\n") |
93 | + linesOut := make([]string, 0, len(linesIn)) |
94 | + for _, line := range linesIn { |
95 | + l := strings.TrimSpace(line) |
96 | + if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) { |
97 | + linesOut = append(linesOut, line) |
98 | + } else { |
99 | + linesOut = append(linesOut, "") |
100 | + } |
101 | + } |
102 | + f.Preamble = strings.Join(linesOut, "\n") |
103 | +} |
104 | + |
105 | +// addToFlag appends args to flag. All flags are later written out onto the |
106 | +// _cgo_flags file for the build system to use. |
107 | +func (p *Package) addToFlag(flag string, args []string) { |
108 | + p.CgoFlags[flag] = append(p.CgoFlags[flag], args...) |
109 | + if flag == "CFLAGS" { |
110 | + // We'll also need these when preprocessing for dwarf information. |
111 | + p.GccOptions = append(p.GccOptions, args...) |
112 | + } |
113 | +} |
114 | + |
115 | +// splitQuoted splits the string s around each instance of one or more consecutive |
116 | +// white space characters while taking into account quotes and escaping, and |
117 | +// returns an array of substrings of s or an empty list if s contains only white space. |
118 | +// Single quotes and double quotes are recognized to prevent splitting within the |
119 | +// quoted region, and are removed from the resulting substrings. If a quote in s |
120 | +// isn't closed err will be set and r will have the unclosed argument as the |
121 | +// last element. The backslash is used for escaping. |
122 | +// |
123 | +// For example, the following string: |
124 | +// |
125 | +// `a b:"c d" 'e''f' "g\""` |
126 | +// |
127 | +// Would be parsed as: |
128 | +// |
129 | +// []string{"a", "b:c d", "ef", `g"`} |
130 | +// |
131 | +func splitQuoted(s string) (r []string, err error) { |
132 | + var args []string |
133 | + arg := make([]rune, len(s)) |
134 | + escaped := false |
135 | + quoted := false |
136 | + quote := '\x00' |
137 | + i := 0 |
138 | + for _, r := range s { |
139 | + switch { |
140 | + case escaped: |
141 | + escaped = false |
142 | + case r == '\\': |
143 | + escaped = true |
144 | + continue |
145 | + case quote != 0: |
146 | + if r == quote { |
147 | + quote = 0 |
148 | + continue |
149 | + } |
150 | + case r == '"' || r == '\'': |
151 | + quoted = true |
152 | + quote = r |
153 | + continue |
154 | + case unicode.IsSpace(r): |
155 | + if quoted || i > 0 { |
156 | + quoted = false |
157 | + args = append(args, string(arg[:i])) |
158 | + i = 0 |
159 | + } |
160 | + continue |
161 | + } |
162 | + arg[i] = r |
163 | + i++ |
164 | + } |
165 | + if quoted || i > 0 { |
166 | + args = append(args, string(arg[:i])) |
167 | + } |
168 | + if quote != 0 { |
169 | + err = errors.New("unclosed quote") |
170 | + } else if escaped { |
171 | + err = errors.New("unfinished escaping") |
172 | + } |
173 | + return args, err |
174 | +} |
175 | + |
176 | +var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`) |
177 | + |
178 | +func safeName(s string) bool { |
179 | + if s == "" { |
180 | + return false |
181 | + } |
182 | + for i := 0; i < len(s); i++ { |
183 | + if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 { |
184 | + return false |
185 | + } |
186 | + } |
187 | + return true |
188 | +} |
189 | + |
190 | +// Translate rewrites f.AST, the original Go input, to remove |
191 | +// references to the imported package C, replacing them with |
192 | +// references to the equivalent Go types, functions, and variables. |
193 | +func (p *Package) Translate(f *File) { |
194 | + for _, cref := range f.Ref { |
195 | + // Convert C.ulong to C.unsigned long, etc. |
196 | + cref.Name.C = cname(cref.Name.Go) |
197 | + } |
198 | + p.loadDefines(f) |
199 | + needType := p.guessKinds(f) |
200 | + if len(needType) > 0 { |
201 | + p.loadDWARF(f, needType) |
202 | + } |
203 | + p.rewriteRef(f) |
204 | +} |
205 | + |
206 | +// loadDefines coerces gcc into spitting out the #defines in use |
207 | +// in the file f and saves relevant renamings in f.Name[name].Define. |
208 | +func (p *Package) loadDefines(f *File) { |
209 | + var b bytes.Buffer |
210 | + b.WriteString(f.Preamble) |
211 | + b.WriteString(builtinProlog) |
212 | + stdout := p.gccDefines(b.Bytes()) |
213 | + |
214 | + for _, line := range strings.Split(stdout, "\n") { |
215 | + if len(line) < 9 || line[0:7] != "#define" { |
216 | + continue |
217 | + } |
218 | + |
219 | + line = strings.TrimSpace(line[8:]) |
220 | + |
221 | + var key, val string |
222 | + spaceIndex := strings.Index(line, " ") |
223 | + tabIndex := strings.Index(line, "\t") |
224 | + |
225 | + if spaceIndex == -1 && tabIndex == -1 { |
226 | + continue |
227 | + } else if tabIndex == -1 || (spaceIndex != -1 && spaceIndex < tabIndex) { |
228 | + key = line[0:spaceIndex] |
229 | + val = strings.TrimSpace(line[spaceIndex:]) |
230 | + } else { |
231 | + key = line[0:tabIndex] |
232 | + val = strings.TrimSpace(line[tabIndex:]) |
233 | + } |
234 | + |
235 | + if n := f.Name[key]; n != nil { |
236 | + if *debugDefine { |
237 | + fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val) |
238 | + } |
239 | + n.Define = val |
240 | + } |
241 | + } |
242 | +} |
243 | + |
244 | +// guessKinds tricks gcc into revealing the kind of each |
245 | +// name xxx for the references C.xxx in the Go input. |
246 | +// The kind is either a constant, type, or variable. |
247 | +func (p *Package) guessKinds(f *File) []*Name { |
248 | + // Determine kinds for names we already know about, |
249 | + // like #defines or 'struct foo', before bothering with gcc. |
250 | + var names, needType []*Name |
251 | + for _, n := range f.Name { |
252 | + // If we've already found this name as a #define |
253 | + // and we can translate it as a constant value, do so. |
254 | + if n.Define != "" { |
255 | + isConst := false |
256 | + if _, err := strconv.Atoi(n.Define); err == nil { |
257 | + isConst = true |
258 | + } else if n.Define[0] == '"' || n.Define[0] == '\'' { |
259 | + if _, err := parser.ParseExpr(n.Define); err == nil { |
260 | + isConst = true |
261 | + } |
262 | + } |
263 | + if isConst { |
264 | + n.Kind = "const" |
265 | + // Turn decimal into hex, just for consistency |
266 | + // with enum-derived constants. Otherwise |
267 | + // in the cgo -godefs output half the constants |
268 | + // are in hex and half are in whatever the #define used. |
269 | + i, err := strconv.ParseInt(n.Define, 0, 64) |
270 | + if err == nil { |
271 | + n.Const = fmt.Sprintf("%#x", i) |
272 | + } else { |
273 | + n.Const = n.Define |
274 | + } |
275 | + continue |
276 | + } |
277 | + |
278 | + if isName(n.Define) { |
279 | + n.C = n.Define |
280 | + } |
281 | + } |
282 | + |
283 | + needType = append(needType, n) |
284 | + |
285 | + // If this is a struct, union, or enum type name, no need to guess the kind. |
286 | + if strings.HasPrefix(n.C, "struct ") || strings.HasPrefix(n.C, "union ") || strings.HasPrefix(n.C, "enum ") { |
287 | + n.Kind = "type" |
288 | + continue |
289 | + } |
290 | + |
291 | + // Otherwise, we'll need to find out from gcc. |
292 | + names = append(names, n) |
293 | + } |
294 | + |
295 | + // Bypass gcc if there's nothing left to find out. |
296 | + if len(names) == 0 { |
297 | + return needType |
298 | + } |
299 | + |
300 | + // Coerce gcc into telling us whether each name is a type, a value, or undeclared. |
301 | + // For names, find out whether they are integer constants. |
302 | + // We used to look at specific warning or error messages here, but that tied the |
303 | + // behavior too closely to specific versions of the compilers. |
304 | + // Instead, arrange that we can infer what we need from only the presence or absence |
305 | + // of an error on a specific line. |
306 | + // |
307 | + // For each name, we generate these lines, where xxx is the index in toSniff plus one. |
308 | + // |
309 | + // #line xxx "not-declared" |
310 | + // void __cgo_f_xxx_1(void) { __typeof__(name) *__cgo_undefined__; } |
311 | + // #line xxx "not-type" |
312 | + // void __cgo_f_xxx_2(void) { name *__cgo_undefined__; } |
313 | + // #line xxx "not-const" |
314 | + // void __cgo_f_xxx_3(void) { enum { __cgo_undefined__ = (name)*1 }; } |
315 | + // |
316 | + // If we see an error at not-declared:xxx, the corresponding name is not declared. |
317 | + // If we see an error at not-type:xxx, the corresponding name is a type. |
318 | + // If we see an error at not-const:xxx, the corresponding name is not an integer constant. |
319 | + // If we see no errors, we assume the name is an expression but not a constant |
320 | + // (so a variable or a function). |
321 | + // |
322 | + // The specific input forms are chosen so that they are valid C syntax regardless of |
323 | + // whether name denotes a type or an expression. |
324 | + |
325 | + var b bytes.Buffer |
326 | + b.WriteString(f.Preamble) |
327 | + b.WriteString(builtinProlog) |
328 | + |
329 | + for i, n := range names { |
330 | + fmt.Fprintf(&b, "#line %d \"not-declared\"\n"+ |
331 | + "void __cgo_f_%d_1(void) { __typeof__(%s) *__cgo_undefined__; }\n"+ |
332 | + "#line %d \"not-type\"\n"+ |
333 | + "void __cgo_f_%d_2(void) { %s *__cgo_undefined__; }\n"+ |
334 | + "#line %d \"not-const\"\n"+ |
335 | + "void __cgo_f_%d_3(void) { enum { __cgo__undefined__ = (%s)*1 }; }\n", |
336 | + i+1, i+1, n.C, |
337 | + i+1, i+1, n.C, |
338 | + i+1, i+1, n.C) |
339 | + } |
340 | + fmt.Fprintf(&b, "#line 1 \"completed\"\n"+ |
341 | + "int __cgo__1 = __cgo__2;\n") |
342 | + |
343 | + stderr := p.gccErrors(b.Bytes()) |
344 | + if stderr == "" { |
345 | + fatalf("%s produced no output\non input:\n%s", p.gccBaseCmd()[0], b.Bytes()) |
346 | + } |
347 | + |
348 | + completed := false |
349 | + sniff := make([]int, len(names)) |
350 | + const ( |
351 | + notType = 1 << iota |
352 | + notConst |
353 | + ) |
354 | + for _, line := range strings.Split(stderr, "\n") { |
355 | + if !strings.Contains(line, ": error:") { |
356 | + // we only care about errors. |
357 | + // we tried to turn off warnings on the command line, but one never knows. |
358 | + continue |
359 | + } |
360 | + |
361 | + c1 := strings.Index(line, ":") |
362 | + if c1 < 0 { |
363 | + continue |
364 | + } |
365 | + c2 := strings.Index(line[c1+1:], ":") |
366 | + if c2 < 0 { |
367 | + continue |
368 | + } |
369 | + c2 += c1 + 1 |
370 | + |
371 | + filename := line[:c1] |
372 | + i, _ := strconv.Atoi(line[c1+1 : c2]) |
373 | + i-- |
374 | + if i < 0 || i >= len(names) { |
375 | + continue |
376 | + } |
377 | + |
378 | + switch filename { |
379 | + case "completed": |
380 | + // Strictly speaking, there is no guarantee that seeing the error at completed:1 |
381 | + // (at the end of the file) means we've seen all the errors from earlier in the file, |
382 | + // but usually it does. Certainly if we don't see the completed:1 error, we did |
383 | + // not get all the errors we expected. |
384 | + completed = true |
385 | + |
386 | + case "not-declared": |
387 | + error_(token.NoPos, "%s", strings.TrimSpace(line[c2+1:])) |
388 | + case "not-type": |
389 | + sniff[i] |= notType |
390 | + case "not-const": |
391 | + sniff[i] |= notConst |
392 | + } |
393 | + } |
394 | + |
395 | + if !completed { |
396 | + fatalf("%s did not produce error at completed:1\non input:\n%s", p.gccBaseCmd()[0], b.Bytes()) |
397 | + } |
398 | + |
399 | + for i, n := range names { |
400 | + switch sniff[i] { |
401 | + case 0: |
402 | + error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go)) |
403 | + case notType: |
404 | + n.Kind = "const" |
405 | + case notConst: |
406 | + n.Kind = "type" |
407 | + case notConst | notType: |
408 | + n.Kind = "not-type" |
409 | + } |
410 | + } |
411 | + if nerrors > 0 { |
412 | + fatalf("unresolved names") |
413 | + } |
414 | + |
415 | + needType = append(needType, names...) |
416 | + return needType |
417 | +} |
418 | + |
419 | +// loadDWARF parses the DWARF debug information generated |
420 | +// by gcc to learn the details of the constants, variables, and types |
421 | +// being referred to as C.xxx. |
422 | +func (p *Package) loadDWARF(f *File, names []*Name) { |
423 | + // Extract the types from the DWARF section of an object |
424 | + // from a well-formed C program. Gcc only generates DWARF info |
425 | + // for symbols in the object file, so it is not enough to print the |
426 | + // preamble and hope the symbols we care about will be there. |
427 | + // Instead, emit |
428 | + // __typeof__(names[i]) *__cgo__i; |
429 | + // for each entry in names and then dereference the type we |
430 | + // learn for __cgo__i. |
431 | + var b bytes.Buffer |
432 | + b.WriteString(f.Preamble) |
433 | + b.WriteString(builtinProlog) |
434 | + for i, n := range names { |
435 | + fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i) |
436 | + if n.Kind == "const" { |
437 | + fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C) |
438 | + } |
439 | + } |
440 | + |
441 | + // Apple's LLVM-based gcc does not include the enumeration |
442 | + // names and values in its DWARF debug output. In case we're |
443 | + // using such a gcc, create a data block initialized with the values. |
444 | + // We can read them out of the object file. |
445 | + fmt.Fprintf(&b, "long long __cgodebug_data[] = {\n") |
446 | + for _, n := range names { |
447 | + if n.Kind == "const" { |
448 | + fmt.Fprintf(&b, "\t%s,\n", n.C) |
449 | + } else { |
450 | + fmt.Fprintf(&b, "\t0,\n") |
451 | + } |
452 | + } |
453 | + // for the last entry, we can not use 0, otherwise |
454 | + // in case all __cgodebug_data is zero initialized, |
455 | + // LLVM-based gcc will place the it in the __DATA.__common |
456 | + // zero-filled section (our debug/macho doesn't support |
457 | + // this) |
458 | + fmt.Fprintf(&b, "\t1\n") |
459 | + fmt.Fprintf(&b, "};\n") |
460 | + |
461 | + d, bo, debugData := p.gccDebug(b.Bytes()) |
462 | + enumVal := make([]int64, len(debugData)/8) |
463 | + for i := range enumVal { |
464 | + enumVal[i] = int64(bo.Uint64(debugData[i*8:])) |
465 | + } |
466 | + |
467 | + // Scan DWARF info for top-level TagVariable entries with AttrName __cgo__i. |
468 | + types := make([]dwarf.Type, len(names)) |
469 | + enums := make([]dwarf.Offset, len(names)) |
470 | + nameToIndex := make(map[*Name]int) |
471 | + for i, n := range names { |
472 | + nameToIndex[n] = i |
473 | + } |
474 | + nameToRef := make(map[*Name]*Ref) |
475 | + for _, ref := range f.Ref { |
476 | + nameToRef[ref.Name] = ref |
477 | + } |
478 | + r := d.Reader() |
479 | + for { |
480 | + e, err := r.Next() |
481 | + if err != nil { |
482 | + fatalf("reading DWARF entry: %s", err) |
483 | + } |
484 | + if e == nil { |
485 | + break |
486 | + } |
487 | + switch e.Tag { |
488 | + case dwarf.TagEnumerationType: |
489 | + offset := e.Offset |
490 | + for { |
491 | + e, err := r.Next() |
492 | + if err != nil { |
493 | + fatalf("reading DWARF entry: %s", err) |
494 | + } |
495 | + if e.Tag == 0 { |
496 | + break |
497 | + } |
498 | + if e.Tag == dwarf.TagEnumerator { |
499 | + entryName := e.Val(dwarf.AttrName).(string) |
500 | + if strings.HasPrefix(entryName, "__cgo_enum__") { |
501 | + n, _ := strconv.Atoi(entryName[len("__cgo_enum__"):]) |
502 | + if 0 <= n && n < len(names) { |
503 | + enums[n] = offset |
504 | + } |
505 | + } |
506 | + } |
507 | + } |
508 | + case dwarf.TagVariable: |
509 | + name, _ := e.Val(dwarf.AttrName).(string) |
510 | + typOff, _ := e.Val(dwarf.AttrType).(dwarf.Offset) |
511 | + if name == "" || typOff == 0 { |
512 | + fatalf("malformed DWARF TagVariable entry") |
513 | + } |
514 | + if !strings.HasPrefix(name, "__cgo__") { |
515 | + break |
516 | + } |
517 | + typ, err := d.Type(typOff) |
518 | + if err != nil { |
519 | + fatalf("loading DWARF type: %s", err) |
520 | + } |
521 | + t, ok := typ.(*dwarf.PtrType) |
522 | + if !ok || t == nil { |
523 | + fatalf("internal error: %s has non-pointer type", name) |
524 | + } |
525 | + i, err := strconv.Atoi(name[7:]) |
526 | + if err != nil { |
527 | + fatalf("malformed __cgo__ name: %s", name) |
528 | + } |
529 | + if enums[i] != 0 { |
530 | + t, err := d.Type(enums[i]) |
531 | + if err != nil { |
532 | + fatalf("loading DWARF type: %s", err) |
533 | + } |
534 | + types[i] = t |
535 | + } else { |
536 | + types[i] = t.Type |
537 | + } |
538 | + } |
539 | + if e.Tag != dwarf.TagCompileUnit { |
540 | + r.SkipChildren() |
541 | + } |
542 | + } |
543 | + |
544 | + // Record types and typedef information. |
545 | + var conv typeConv |
546 | + conv.Init(p.PtrSize, p.IntSize) |
547 | + for i, n := range names { |
548 | + if types[i] == nil { |
549 | + continue |
550 | + } |
551 | + pos := token.NoPos |
552 | + if ref, ok := nameToRef[n]; ok { |
553 | + pos = ref.Pos() |
554 | + } |
555 | + f, fok := types[i].(*dwarf.FuncType) |
556 | + if n.Kind != "type" && fok { |
557 | + n.Kind = "func" |
558 | + n.FuncType = conv.FuncType(f, pos) |
559 | + } else { |
560 | + n.Type = conv.Type(types[i], pos) |
561 | + if enums[i] != 0 && n.Type.EnumValues != nil { |
562 | + k := fmt.Sprintf("__cgo_enum__%d", i) |
563 | + n.Kind = "const" |
564 | + n.Const = fmt.Sprintf("%#x", n.Type.EnumValues[k]) |
565 | + // Remove injected enum to ensure the value will deep-compare |
566 | + // equally in future loads of the same constant. |
567 | + delete(n.Type.EnumValues, k) |
568 | + } |
569 | + // Prefer debug data over DWARF debug output, if we have it. |
570 | + if n.Kind == "const" && i < len(enumVal) { |
571 | + n.Const = fmt.Sprintf("%#x", enumVal[i]) |
572 | + } |
573 | + } |
574 | + } |
575 | + |
576 | +} |
577 | + |
578 | +// mangleName does name mangling to translate names |
579 | +// from the original Go source files to the names |
580 | +// used in the final Go files generated by cgo. |
581 | +func (p *Package) mangleName(n *Name) { |
582 | + // When using gccgo variables have to be |
583 | + // exported so that they become global symbols |
584 | + // that the C code can refer to. |
585 | + prefix := "_C" |
586 | + if *gccgo && n.IsVar() { |
587 | + prefix = "C" |
588 | + } |
589 | + n.Mangle = prefix + n.Kind + "_" + n.Go |
590 | +} |
591 | + |
592 | +// rewriteRef rewrites all the C.xxx references in f.AST to refer to the |
593 | +// Go equivalents, now that we have figured out the meaning of all |
594 | +// the xxx. In *godefs or *cdefs mode, rewriteRef replaces the names |
595 | +// with full definitions instead of mangled names. |
596 | +func (p *Package) rewriteRef(f *File) { |
597 | + // Keep a list of all the functions, to remove the ones |
598 | + // only used as expressions and avoid generating bridge |
599 | + // code for them. |
600 | + functions := make(map[string]bool) |
601 | + |
602 | + // Assign mangled names. |
603 | + for _, n := range f.Name { |
604 | + if n.Kind == "not-type" { |
605 | + n.Kind = "var" |
606 | + } |
607 | + if n.Mangle == "" { |
608 | + p.mangleName(n) |
609 | + } |
610 | + if n.Kind == "func" { |
611 | + functions[n.Go] = false |
612 | + } |
613 | + } |
614 | + |
615 | + // Now that we have all the name types filled in, |
616 | + // scan through the Refs to identify the ones that |
617 | + // are trying to do a ,err call. Also check that |
618 | + // functions are only used in calls. |
619 | + for _, r := range f.Ref { |
620 | + if r.Name.Kind == "const" && r.Name.Const == "" { |
621 | + error_(r.Pos(), "unable to find value of constant C.%s", fixGo(r.Name.Go)) |
622 | + } |
623 | + var expr ast.Expr = ast.NewIdent(r.Name.Mangle) // default |
624 | + switch r.Context { |
625 | + case "call", "call2": |
626 | + if r.Name.Kind != "func" { |
627 | + if r.Name.Kind == "type" { |
628 | + r.Context = "type" |
629 | + expr = r.Name.Type.Go |
630 | + break |
631 | + } |
632 | + error_(r.Pos(), "call of non-function C.%s", fixGo(r.Name.Go)) |
633 | + break |
634 | + } |
635 | + functions[r.Name.Go] = true |
636 | + if r.Context == "call2" { |
637 | + if r.Name.Go == "_CMalloc" { |
638 | + error_(r.Pos(), "no two-result form for C.malloc") |
639 | + break |
640 | + } |
641 | + // Invent new Name for the two-result function. |
642 | + n := f.Name["2"+r.Name.Go] |
643 | + if n == nil { |
644 | + n = new(Name) |
645 | + *n = *r.Name |
646 | + n.AddError = true |
647 | + n.Mangle = "_C2func_" + n.Go |
648 | + f.Name["2"+r.Name.Go] = n |
649 | + } |
650 | + expr = ast.NewIdent(n.Mangle) |
651 | + r.Name = n |
652 | + break |
653 | + } |
654 | + case "expr": |
655 | + if r.Name.Kind == "func" { |
656 | + // Function is being used in an expression, to e.g. pass around a C function pointer. |
657 | + // Create a new Name for this Ref which causes the variable to be declared in Go land. |
658 | + fpName := "fp_" + r.Name.Go |
659 | + name := f.Name[fpName] |
660 | + if name == nil { |
661 | + name = &Name{ |
662 | + Go: fpName, |
663 | + C: r.Name.C, |
664 | + Kind: "fpvar", |
665 | + Type: &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("void*"), Go: ast.NewIdent("unsafe.Pointer")}, |
666 | + } |
667 | + p.mangleName(name) |
668 | + f.Name[fpName] = name |
669 | + } |
670 | + r.Name = name |
671 | + expr = ast.NewIdent(name.Mangle) |
672 | + } else if r.Name.Kind == "type" { |
673 | + // Okay - might be new(T) |
674 | + expr = r.Name.Type.Go |
675 | + } else if r.Name.Kind == "var" { |
676 | + expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} |
677 | + } |
678 | + |
679 | + case "type": |
680 | + if r.Name.Kind != "type" { |
681 | + error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go)) |
682 | + } else if r.Name.Type == nil { |
683 | + // Use of C.enum_x, C.struct_x or C.union_x without C definition. |
684 | + // GCC won't raise an error when using pointers to such unknown types. |
685 | + error_(r.Pos(), "type C.%s: undefined C type '%s'", fixGo(r.Name.Go), r.Name.C) |
686 | + } else { |
687 | + expr = r.Name.Type.Go |
688 | + } |
689 | + default: |
690 | + if r.Name.Kind == "func" { |
691 | + error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go)) |
692 | + } |
693 | + } |
694 | + if *godefs || *cdefs { |
695 | + // Substitute definition for mangled type name. |
696 | + if id, ok := expr.(*ast.Ident); ok { |
697 | + if t := typedef[id.Name]; t != nil { |
698 | + expr = t.Go |
699 | + } |
700 | + if id.Name == r.Name.Mangle && r.Name.Const != "" { |
701 | + expr = ast.NewIdent(r.Name.Const) |
702 | + } |
703 | + } |
704 | + } |
705 | + |
706 | + // Copy position information from old expr into new expr, |
707 | + // in case expression being replaced is first on line. |
708 | + // See golang.org/issue/6563. |
709 | + pos := (*r.Expr).Pos() |
710 | + switch x := expr.(type) { |
711 | + case *ast.Ident: |
712 | + expr = &ast.Ident{NamePos: pos, Name: x.Name} |
713 | + } |
714 | + |
715 | + *r.Expr = expr |
716 | + } |
717 | + |
718 | + // Remove functions only used as expressions, so their respective |
719 | + // bridge functions are not generated. |
720 | + for name, used := range functions { |
721 | + if !used { |
722 | + delete(f.Name, name) |
723 | + } |
724 | + } |
725 | +} |
726 | + |
727 | +// gccBaseCmd returns the start of the compiler command line. |
728 | +// It uses $CC if set, or else $GCC, or else the compiler recorded |
729 | +// during the initial build as defaultCC. |
730 | +// defaultCC is defined in zdefaultcc.go, written by cmd/dist. |
731 | +func (p *Package) gccBaseCmd() []string { |
732 | + // Use $CC if set, since that's what the build uses. |
733 | + if ret := strings.Fields(os.Getenv("CC")); len(ret) > 0 { |
734 | + return ret |
735 | + } |
736 | + // Try $GCC if set, since that's what we used to use. |
737 | + if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { |
738 | + return ret |
739 | + } |
740 | + return strings.Fields(defaultCC) |
741 | +} |
742 | + |
743 | +// gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". |
744 | +func (p *Package) gccMachine() []string { |
745 | + switch goarch { |
746 | + case "amd64": |
747 | + return []string{"-m64"} |
748 | + case "386": |
749 | + return []string{"-m32"} |
750 | + case "arm": |
751 | + return []string{"-marm"} // not thumb |
752 | + } |
753 | + return nil |
754 | +} |
755 | + |
756 | +func gccTmp() string { |
757 | + return *objDir + "_cgo_.o" |
758 | +} |
759 | + |
760 | +// gccCmd returns the gcc command line to use for compiling |
761 | +// the input. |
762 | +func (p *Package) gccCmd() []string { |
763 | + c := append(p.gccBaseCmd(), |
764 | + "-w", // no warnings |
765 | + "-Wno-error", // warnings are not errors |
766 | + "-o"+gccTmp(), // write object to tmp |
767 | + "-gdwarf-2", // generate DWARF v2 debugging symbols |
768 | + "-c", // do not link |
769 | + "-xc", // input language is C |
770 | + ) |
771 | + if strings.Contains(c[0], "clang") { |
772 | + c = append(c, |
773 | + "-ferror-limit=0", |
774 | + // Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn) |
775 | + // doesn't have -Wno-unneeded-internal-declaration, so we need yet another |
776 | + // flag to disable the warning. Yes, really good diagnostics, clang. |
777 | + "-Wno-unknown-warning-option", |
778 | + "-Wno-unneeded-internal-declaration", |
779 | + "-Wno-unused-function", |
780 | + "-Qunused-arguments", |
781 | + // Clang embeds prototypes for some builtin functions, |
782 | + // like malloc and calloc, but all size_t parameters are |
783 | + // incorrectly typed unsigned long. We work around that |
784 | + // by disabling the builtin functions (this is safe as |
785 | + // it won't affect the actual compilation of the C code). |
786 | + // See: http://golang.org/issue/6506. |
787 | + "-fno-builtin", |
788 | + ) |
789 | + } |
790 | + |
791 | + c = append(c, p.GccOptions...) |
792 | + c = append(c, p.gccMachine()...) |
793 | + c = append(c, "-") //read input from standard input |
794 | + return c |
795 | +} |
796 | + |
797 | +// gccDebug runs gcc -gdwarf-2 over the C program stdin and |
798 | +// returns the corresponding DWARF data and, if present, debug data block. |
799 | +func (p *Package) gccDebug(stdin []byte) (*dwarf.Data, binary.ByteOrder, []byte) { |
800 | + runGcc(stdin, p.gccCmd()) |
801 | + |
802 | + isDebugData := func(s string) bool { |
803 | + // Some systems use leading _ to denote non-assembly symbols. |
804 | + return s == "__cgodebug_data" || s == "___cgodebug_data" |
805 | + } |
806 | + |
807 | + if f, err := macho.Open(gccTmp()); err == nil { |
808 | + defer f.Close() |
809 | + d, err := f.DWARF() |
810 | + if err != nil { |
811 | + fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) |
812 | + } |
813 | + var data []byte |
814 | + if f.Symtab != nil { |
815 | + for i := range f.Symtab.Syms { |
816 | + s := &f.Symtab.Syms[i] |
817 | + if isDebugData(s.Name) { |
818 | + // Found it. Now find data section. |
819 | + if i := int(s.Sect) - 1; 0 <= i && i < len(f.Sections) { |
820 | + sect := f.Sections[i] |
821 | + if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { |
822 | + if sdat, err := sect.Data(); err == nil { |
823 | + data = sdat[s.Value-sect.Addr:] |
824 | + } |
825 | + } |
826 | + } |
827 | + } |
828 | + } |
829 | + } |
830 | + return d, f.ByteOrder, data |
831 | + } |
832 | + |
833 | + if f, err := elf.Open(gccTmp()); err == nil { |
834 | + defer f.Close() |
835 | + d, err := f.DWARF() |
836 | + if err != nil { |
837 | + fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) |
838 | + } |
839 | + var data []byte |
840 | + symtab, err := f.Symbols() |
841 | + if err == nil { |
842 | + for i := range symtab { |
843 | + s := &symtab[i] |
844 | + if isDebugData(s.Name) { |
845 | + // Found it. Now find data section. |
846 | + if i := int(s.Section); 0 <= i && i < len(f.Sections) { |
847 | + sect := f.Sections[i] |
848 | + if sect.Addr <= s.Value && s.Value < sect.Addr+sect.Size { |
849 | + if sdat, err := sect.Data(); err == nil { |
850 | + data = sdat[s.Value-sect.Addr:] |
851 | + } |
852 | + } |
853 | + } |
854 | + } |
855 | + } |
856 | + } |
857 | + return d, f.ByteOrder, data |
858 | + } |
859 | + |
860 | + if f, err := pe.Open(gccTmp()); err == nil { |
861 | + defer f.Close() |
862 | + d, err := f.DWARF() |
863 | + if err != nil { |
864 | + fatalf("cannot load DWARF output from %s: %v", gccTmp(), err) |
865 | + } |
866 | + var data []byte |
867 | + for _, s := range f.Symbols { |
868 | + if isDebugData(s.Name) { |
869 | + if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) { |
870 | + sect := f.Sections[i] |
871 | + if s.Value < sect.Size { |
872 | + if sdat, err := sect.Data(); err == nil { |
873 | + data = sdat[s.Value:] |
874 | + } |
875 | + } |
876 | + } |
877 | + } |
878 | + } |
879 | + return d, binary.LittleEndian, data |
880 | + } |
881 | + |
882 | + fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp()) |
883 | + panic("not reached") |
884 | +} |
885 | + |
886 | +// gccDefines runs gcc -E -dM -xc - over the C program stdin |
887 | +// and returns the corresponding standard output, which is the |
888 | +// #defines that gcc encountered while processing the input |
889 | +// and its included files. |
890 | +func (p *Package) gccDefines(stdin []byte) string { |
891 | + base := append(p.gccBaseCmd(), "-E", "-dM", "-xc") |
892 | + base = append(base, p.gccMachine()...) |
893 | + stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-")) |
894 | + return stdout |
895 | +} |
896 | + |
897 | +// gccErrors runs gcc over the C program stdin and returns |
898 | +// the errors that gcc prints. That is, this function expects |
899 | +// gcc to fail. |
900 | +func (p *Package) gccErrors(stdin []byte) string { |
901 | + // TODO(rsc): require failure |
902 | + args := p.gccCmd() |
903 | + |
904 | + if *debugGcc { |
905 | + fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) |
906 | + os.Stderr.Write(stdin) |
907 | + fmt.Fprint(os.Stderr, "EOF\n") |
908 | + } |
909 | + stdout, stderr, _ := run(stdin, args) |
910 | + if *debugGcc { |
911 | + os.Stderr.Write(stdout) |
912 | + os.Stderr.Write(stderr) |
913 | + } |
914 | + return string(stderr) |
915 | +} |
916 | + |
917 | +// runGcc runs the gcc command line args with stdin on standard input. |
918 | +// If the command exits with a non-zero exit status, runGcc prints |
919 | +// details about what was run and exits. |
920 | +// Otherwise runGcc returns the data written to standard output and standard error. |
921 | +// Note that for some of the uses we expect useful data back |
922 | +// on standard error, but for those uses gcc must still exit 0. |
923 | +func runGcc(stdin []byte, args []string) (string, string) { |
924 | + if *debugGcc { |
925 | + fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " ")) |
926 | + os.Stderr.Write(stdin) |
927 | + fmt.Fprint(os.Stderr, "EOF\n") |
928 | + } |
929 | + stdout, stderr, ok := run(stdin, args) |
930 | + if *debugGcc { |
931 | + os.Stderr.Write(stdout) |
932 | + os.Stderr.Write(stderr) |
933 | + } |
934 | + if !ok { |
935 | + os.Stderr.Write(stderr) |
936 | + os.Exit(2) |
937 | + } |
938 | + return string(stdout), string(stderr) |
939 | +} |
940 | + |
941 | +// A typeConv is a translator from dwarf types to Go types |
942 | +// with equivalent memory layout. |
943 | +type typeConv struct { |
944 | + // Cache of already-translated or in-progress types. |
945 | + m map[dwarf.Type]*Type |
946 | + typedef map[string]ast.Expr |
947 | + |
948 | + // Predeclared types. |
949 | + bool ast.Expr |
950 | + byte ast.Expr // denotes padding |
951 | + int8, int16, int32, int64 ast.Expr |
952 | + uint8, uint16, uint32, uint64, uintptr ast.Expr |
953 | + float32, float64 ast.Expr |
954 | + complex64, complex128 ast.Expr |
955 | + void ast.Expr |
956 | + unsafePointer ast.Expr |
957 | + string ast.Expr |
958 | + goVoid ast.Expr // _Ctype_void, denotes C's void |
959 | + |
960 | + ptrSize int64 |
961 | + intSize int64 |
962 | +} |
963 | + |
964 | +var tagGen int |
965 | +var typedef = make(map[string]*Type) |
966 | +var goIdent = make(map[string]*ast.Ident) |
967 | + |
968 | +func (c *typeConv) Init(ptrSize, intSize int64) { |
969 | + c.ptrSize = ptrSize |
970 | + c.intSize = intSize |
971 | + c.m = make(map[dwarf.Type]*Type) |
972 | + c.bool = c.Ident("bool") |
973 | + c.byte = c.Ident("byte") |
974 | + c.int8 = c.Ident("int8") |
975 | + c.int16 = c.Ident("int16") |
976 | + c.int32 = c.Ident("int32") |
977 | + c.int64 = c.Ident("int64") |
978 | + c.uint8 = c.Ident("uint8") |
979 | + c.uint16 = c.Ident("uint16") |
980 | + c.uint32 = c.Ident("uint32") |
981 | + c.uint64 = c.Ident("uint64") |
982 | + c.uintptr = c.Ident("uintptr") |
983 | + c.float32 = c.Ident("float32") |
984 | + c.float64 = c.Ident("float64") |
985 | + c.complex64 = c.Ident("complex64") |
986 | + c.complex128 = c.Ident("complex128") |
987 | + c.unsafePointer = c.Ident("unsafe.Pointer") |
988 | + c.void = c.Ident("void") |
989 | + c.string = c.Ident("string") |
990 | + c.goVoid = c.Ident("_Ctype_void") |
991 | +} |
992 | + |
993 | +// base strips away qualifiers and typedefs to get the underlying type |
994 | +func base(dt dwarf.Type) dwarf.Type { |
995 | + for { |
996 | + if d, ok := dt.(*dwarf.QualType); ok { |
997 | + dt = d.Type |
998 | + continue |
999 | + } |
1000 | + if d, ok := dt.(*dwarf.TypedefType); ok { |
1001 | + dt = d.Type |
1002 | + continue |
1003 | + } |
1004 | + break |
1005 | + } |
1006 | + return dt |
1007 | +} |
1008 | + |
1009 | +// Map from dwarf text names to aliases we use in package "C". |
1010 | +var dwarfToName = map[string]string{ |
1011 | + "long int": "long", |
1012 | + "long unsigned int": "ulong", |
1013 | + "unsigned int": "uint", |
1014 | + "short unsigned int": "ushort", |
1015 | + "short int": "short", |
1016 | + "long long int": "longlong", |
1017 | + "long long unsigned int": "ulonglong", |
1018 | + "signed char": "schar", |
1019 | + "float complex": "complexfloat", |
1020 | + "double complex": "complexdouble", |
1021 | +} |
1022 | + |
1023 | +const signedDelta = 64 |
1024 | + |
1025 | +// String returns the current type representation. Format arguments |
1026 | +// are assembled within this method so that any changes in mutable |
1027 | +// values are taken into account. |
1028 | +func (tr *TypeRepr) String() string { |
1029 | + if len(tr.Repr) == 0 { |
1030 | + return "" |
1031 | + } |
1032 | + if len(tr.FormatArgs) == 0 { |
1033 | + return tr.Repr |
1034 | + } |
1035 | + return fmt.Sprintf(tr.Repr, tr.FormatArgs...) |
1036 | +} |
1037 | + |
1038 | +// Empty returns true if the result of String would be "". |
1039 | +func (tr *TypeRepr) Empty() bool { |
1040 | + return len(tr.Repr) == 0 |
1041 | +} |
1042 | + |
1043 | +// Set modifies the type representation. |
1044 | +// If fargs are provided, repr is used as a format for fmt.Sprintf. |
1045 | +// Otherwise, repr is used unprocessed as the type representation. |
1046 | +func (tr *TypeRepr) Set(repr string, fargs ...interface{}) { |
1047 | + tr.Repr = repr |
1048 | + tr.FormatArgs = fargs |
1049 | +} |
1050 | + |
1051 | +// Type returns a *Type with the same memory layout as |
1052 | +// dtype when used as the type of a variable or a struct field. |
1053 | +func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { |
1054 | + if t, ok := c.m[dtype]; ok { |
1055 | + if t.Go == nil { |
1056 | + fatalf("%s: type conversion loop at %s", lineno(pos), dtype) |
1057 | + } |
1058 | + return t |
1059 | + } |
1060 | + |
1061 | + // clang won't generate DW_AT_byte_size for pointer types, |
1062 | + // so we have to fix it here. |
1063 | + if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 { |
1064 | + dt.ByteSize = c.ptrSize |
1065 | + } |
1066 | + |
1067 | + t := new(Type) |
1068 | + t.Size = dtype.Size() // note: wrong for array of pointers, corrected below |
1069 | + t.Align = -1 |
1070 | + t.C = &TypeRepr{Repr: dtype.Common().Name} |
1071 | + c.m[dtype] = t |
1072 | + |
1073 | + switch dt := dtype.(type) { |
1074 | + default: |
1075 | + fatalf("%s: unexpected type: %s", lineno(pos), dtype) |
1076 | + |
1077 | + case *dwarf.AddrType: |
1078 | + if t.Size != c.ptrSize { |
1079 | + fatalf("%s: unexpected: %d-byte address type - %s", lineno(pos), t.Size, dtype) |
1080 | + } |
1081 | + t.Go = c.uintptr |
1082 | + t.Align = t.Size |
1083 | + |
1084 | + case *dwarf.ArrayType: |
1085 | + if dt.StrideBitSize > 0 { |
1086 | + // Cannot represent bit-sized elements in Go. |
1087 | + t.Go = c.Opaque(t.Size) |
1088 | + break |
1089 | + } |
1090 | + gt := &ast.ArrayType{ |
1091 | + Len: c.intExpr(dt.Count), |
1092 | + } |
1093 | + t.Go = gt // publish before recursive call |
1094 | + sub := c.Type(dt.Type, pos) |
1095 | + t.Align = sub.Align |
1096 | + gt.Elt = sub.Go |
1097 | + t.C.Set("__typeof__(%s[%d])", sub.C, dt.Count) |
1098 | + |
1099 | + case *dwarf.BoolType: |
1100 | + t.Go = c.bool |
1101 | + t.Align = 1 |
1102 | + |
1103 | + case *dwarf.CharType: |
1104 | + if t.Size != 1 { |
1105 | + fatalf("%s: unexpected: %d-byte char type - %s", lineno(pos), t.Size, dtype) |
1106 | + } |
1107 | + t.Go = c.int8 |
1108 | + t.Align = 1 |
1109 | + |
1110 | + case *dwarf.EnumType: |
1111 | + if t.Align = t.Size; t.Align >= c.ptrSize { |
1112 | + t.Align = c.ptrSize |
1113 | + } |
1114 | + t.C.Set("enum " + dt.EnumName) |
1115 | + signed := 0 |
1116 | + t.EnumValues = make(map[string]int64) |
1117 | + for _, ev := range dt.Val { |
1118 | + t.EnumValues[ev.Name] = ev.Val |
1119 | + if ev.Val < 0 { |
1120 | + signed = signedDelta |
1121 | + } |
1122 | + } |
1123 | + switch t.Size + int64(signed) { |
1124 | + default: |
1125 | + fatalf("%s: unexpected: %d-byte enum type - %s", lineno(pos), t.Size, dtype) |
1126 | + case 1: |
1127 | + t.Go = c.uint8 |
1128 | + case 2: |
1129 | + t.Go = c.uint16 |
1130 | + case 4: |
1131 | + t.Go = c.uint32 |
1132 | + case 8: |
1133 | + t.Go = c.uint64 |
1134 | + case 1 + signedDelta: |
1135 | + t.Go = c.int8 |
1136 | + case 2 + signedDelta: |
1137 | + t.Go = c.int16 |
1138 | + case 4 + signedDelta: |
1139 | + t.Go = c.int32 |
1140 | + case 8 + signedDelta: |
1141 | + t.Go = c.int64 |
1142 | + } |
1143 | + |
1144 | + case *dwarf.FloatType: |
1145 | + switch t.Size { |
1146 | + default: |
1147 | + fatalf("%s: unexpected: %d-byte float type - %s", lineno(pos), t.Size, dtype) |
1148 | + case 4: |
1149 | + t.Go = c.float32 |
1150 | + case 8: |
1151 | + t.Go = c.float64 |
1152 | + } |
1153 | + if t.Align = t.Size; t.Align >= c.ptrSize { |
1154 | + t.Align = c.ptrSize |
1155 | + } |
1156 | + |
1157 | + case *dwarf.ComplexType: |
1158 | + switch t.Size { |
1159 | + default: |
1160 | + fatalf("%s: unexpected: %d-byte complex type - %s", lineno(pos), t.Size, dtype) |
1161 | + case 8: |
1162 | + t.Go = c.complex64 |
1163 | + case 16: |
1164 | + t.Go = c.complex128 |
1165 | + } |
1166 | + if t.Align = t.Size; t.Align >= c.ptrSize { |
1167 | + t.Align = c.ptrSize |
1168 | + } |
1169 | + |
1170 | + case *dwarf.FuncType: |
1171 | + // No attempt at translation: would enable calls |
1172 | + // directly between worlds, but we need to moderate those. |
1173 | + t.Go = c.uintptr |
1174 | + t.Align = c.ptrSize |
1175 | + |
1176 | + case *dwarf.IntType: |
1177 | + if dt.BitSize > 0 { |
1178 | + fatalf("%s: unexpected: %d-bit int type - %s", lineno(pos), dt.BitSize, dtype) |
1179 | + } |
1180 | + switch t.Size { |
1181 | + default: |
1182 | + fatalf("%s: unexpected: %d-byte int type - %s", lineno(pos), t.Size, dtype) |
1183 | + case 1: |
1184 | + t.Go = c.int8 |
1185 | + case 2: |
1186 | + t.Go = c.int16 |
1187 | + case 4: |
1188 | + t.Go = c.int32 |
1189 | + case 8: |
1190 | + t.Go = c.int64 |
1191 | + } |
1192 | + if t.Align = t.Size; t.Align >= c.ptrSize { |
1193 | + t.Align = c.ptrSize |
1194 | + } |
1195 | + |
1196 | + case *dwarf.PtrType: |
1197 | + t.Align = c.ptrSize |
1198 | + |
1199 | + // Translate void* as unsafe.Pointer |
1200 | + if _, ok := base(dt.Type).(*dwarf.VoidType); ok { |
1201 | + t.Go = c.unsafePointer |
1202 | + t.C.Set("void*") |
1203 | + break |
1204 | + } |
1205 | + |
1206 | + gt := &ast.StarExpr{} |
1207 | + t.Go = gt // publish before recursive call |
1208 | + sub := c.Type(dt.Type, pos) |
1209 | + gt.X = sub.Go |
1210 | + t.C.Set("%s*", sub.C) |
1211 | + |
1212 | + case *dwarf.QualType: |
1213 | + // Ignore qualifier. |
1214 | + t = c.Type(dt.Type, pos) |
1215 | + c.m[dtype] = t |
1216 | + return t |
1217 | + |
1218 | + case *dwarf.StructType: |
1219 | + if dt.ByteSize < 0 { // opaque struct |
1220 | + break |
1221 | + } |
1222 | + // Convert to Go struct, being careful about alignment. |
1223 | + // Have to give it a name to simulate C "struct foo" references. |
1224 | + tag := dt.StructName |
1225 | + if tag == "" { |
1226 | + tag = "__" + strconv.Itoa(tagGen) |
1227 | + tagGen++ |
1228 | + } else if t.C.Empty() { |
1229 | + t.C.Set(dt.Kind + " " + tag) |
1230 | + } |
1231 | + name := c.Ident("_Ctype_" + dt.Kind + "_" + tag) |
1232 | + t.Go = name // publish before recursive calls |
1233 | + goIdent[name.Name] = name |
1234 | + switch dt.Kind { |
1235 | + case "class", "union": |
1236 | + t.Go = c.Opaque(t.Size) |
1237 | + if t.C.Empty() { |
1238 | + t.C.Set("__typeof__(unsigned char[%d])", t.Size) |
1239 | + } |
1240 | + t.Align = 1 // TODO: should probably base this on field alignment. |
1241 | + typedef[name.Name] = t |
1242 | + case "struct": |
1243 | + g, csyntax, align := c.Struct(dt, pos) |
1244 | + if t.C.Empty() { |
1245 | + t.C.Set(csyntax) |
1246 | + } |
1247 | + t.Align = align |
1248 | + tt := *t |
1249 | + if tag != "" { |
1250 | + tt.C = &TypeRepr{"struct %s", []interface{}{tag}} |
1251 | + } |
1252 | + tt.Go = g |
1253 | + typedef[name.Name] = &tt |
1254 | + } |
1255 | + |
1256 | + case *dwarf.TypedefType: |
1257 | + // Record typedef for printing. |
1258 | + if dt.Name == "_GoString_" { |
1259 | + // Special C name for Go string type. |
1260 | + // Knows string layout used by compilers: pointer plus length, |
1261 | + // which rounds up to 2 pointers after alignment. |
1262 | + t.Go = c.string |
1263 | + t.Size = c.ptrSize * 2 |
1264 | + t.Align = c.ptrSize |
1265 | + break |
1266 | + } |
1267 | + if dt.Name == "_GoBytes_" { |
1268 | + // Special C name for Go []byte type. |
1269 | + // Knows slice layout used by compilers: pointer, length, cap. |
1270 | + t.Go = c.Ident("[]byte") |
1271 | + t.Size = c.ptrSize + 4 + 4 |
1272 | + t.Align = c.ptrSize |
1273 | + break |
1274 | + } |
1275 | + name := c.Ident("_Ctype_" + dt.Name) |
1276 | + goIdent[name.Name] = name |
1277 | + t.Go = name // publish before recursive call |
1278 | + sub := c.Type(dt.Type, pos) |
1279 | + t.Size = sub.Size |
1280 | + t.Align = sub.Align |
1281 | + if _, ok := typedef[name.Name]; !ok { |
1282 | + tt := *t |
1283 | + tt.Go = sub.Go |
1284 | + typedef[name.Name] = &tt |
1285 | + } |
1286 | + if *godefs || *cdefs { |
1287 | + t.Go = sub.Go |
1288 | + } |
1289 | + |
1290 | + case *dwarf.UcharType: |
1291 | + if t.Size != 1 { |
1292 | + fatalf("%s: unexpected: %d-byte uchar type - %s", lineno(pos), t.Size, dtype) |
1293 | + } |
1294 | + t.Go = c.uint8 |
1295 | + t.Align = 1 |
1296 | + |
1297 | + case *dwarf.UintType: |
1298 | + if dt.BitSize > 0 { |
1299 | + fatalf("%s: unexpected: %d-bit uint type - %s", lineno(pos), dt.BitSize, dtype) |
1300 | + } |
1301 | + switch t.Size { |
1302 | + default: |
1303 | + fatalf("%s: unexpected: %d-byte uint type - %s", lineno(pos), t.Size, dtype) |
1304 | + case 1: |
1305 | + t.Go = c.uint8 |
1306 | + case 2: |
1307 | + t.Go = c.uint16 |
1308 | + case 4: |
1309 | + t.Go = c.uint32 |
1310 | + case 8: |
1311 | + t.Go = c.uint64 |
1312 | + } |
1313 | + if t.Align = t.Size; t.Align >= c.ptrSize { |
1314 | + t.Align = c.ptrSize |
1315 | + } |
1316 | + |
1317 | + case *dwarf.VoidType: |
1318 | + t.Go = c.goVoid |
1319 | + t.C.Set("void") |
1320 | + t.Align = 1 |
1321 | + } |
1322 | + |
1323 | + switch dtype.(type) { |
1324 | + case *dwarf.AddrType, *dwarf.BoolType, *dwarf.CharType, *dwarf.IntType, *dwarf.FloatType, *dwarf.UcharType, *dwarf.UintType: |
1325 | + s := dtype.Common().Name |
1326 | + if s != "" { |
1327 | + if ss, ok := dwarfToName[s]; ok { |
1328 | + s = ss |
1329 | + } |
1330 | + s = strings.Join(strings.Split(s, " "), "") // strip spaces |
1331 | + name := c.Ident("_Ctype_" + s) |
1332 | + tt := *t |
1333 | + typedef[name.Name] = &tt |
1334 | + if !*godefs && !*cdefs { |
1335 | + t.Go = name |
1336 | + } |
1337 | + } |
1338 | + } |
1339 | + |
1340 | + if t.Size <= 0 { |
1341 | + // Clang does not record the size of a pointer in its DWARF entry, |
1342 | + // so if dtype is an array, the call to dtype.Size at the top of the function |
1343 | + // computed the size as the array length * 0 = 0. |
1344 | + // The type switch called Type (this function) recursively on the pointer |
1345 | + // entry, and the code near the top of the function updated the size to |
1346 | + // be correct, so calling dtype.Size again will produce the correct value. |
1347 | + t.Size = dtype.Size() |
1348 | + if t.Size < 0 { |
1349 | + // Unsized types are [0]byte |
1350 | + t.Size = 0 |
1351 | + t.Go = c.Opaque(0) |
1352 | + if t.C.Empty() { |
1353 | + t.C.Set("void") |
1354 | + } |
1355 | + return t |
1356 | + } |
1357 | + } |
1358 | + |
1359 | + if t.C.Empty() { |
1360 | + fatalf("%s: internal error: did not create C name for %s", lineno(pos), dtype) |
1361 | + } |
1362 | + |
1363 | + return t |
1364 | +} |
1365 | + |
1366 | +// FuncArg returns a Go type with the same memory layout as |
1367 | +// dtype when used as the type of a C function argument. |
1368 | +func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type { |
1369 | + t := c.Type(dtype, pos) |
1370 | + switch dt := dtype.(type) { |
1371 | + case *dwarf.ArrayType: |
1372 | + // Arrays are passed implicitly as pointers in C. |
1373 | + // In Go, we must be explicit. |
1374 | + tr := &TypeRepr{} |
1375 | + tr.Set("%s*", t.C) |
1376 | + return &Type{ |
1377 | + Size: c.ptrSize, |
1378 | + Align: c.ptrSize, |
1379 | + Go: &ast.StarExpr{X: t.Go}, |
1380 | + C: tr, |
1381 | + } |
1382 | + case *dwarf.TypedefType: |
1383 | + // C has much more relaxed rules than Go for |
1384 | + // implicit type conversions. When the parameter |
1385 | + // is type T defined as *X, simulate a little of the |
1386 | + // laxness of C by making the argument *X instead of T. |
1387 | + if ptr, ok := base(dt.Type).(*dwarf.PtrType); ok { |
1388 | + // Unless the typedef happens to point to void* since |
1389 | + // Go has special rules around using unsafe.Pointer. |
1390 | + if _, void := base(ptr.Type).(*dwarf.VoidType); void { |
1391 | + break |
1392 | + } |
1393 | + |
1394 | + t = c.Type(ptr, pos) |
1395 | + if t == nil { |
1396 | + return nil |
1397 | + } |
1398 | + |
1399 | + // Remember the C spelling, in case the struct |
1400 | + // has __attribute__((unavailable)) on it. See issue 2888. |
1401 | + t.Typedef = dt.Name |
1402 | + } |
1403 | + } |
1404 | + return t |
1405 | +} |
1406 | + |
1407 | +// FuncType returns the Go type analogous to dtype. |
1408 | +// There is no guarantee about matching memory layout. |
1409 | +func (c *typeConv) FuncType(dtype *dwarf.FuncType, pos token.Pos) *FuncType { |
1410 | + p := make([]*Type, len(dtype.ParamType)) |
1411 | + gp := make([]*ast.Field, len(dtype.ParamType)) |
1412 | + for i, f := range dtype.ParamType { |
1413 | + // gcc's DWARF generator outputs a single DotDotDotType parameter for |
1414 | + // function pointers that specify no parameters (e.g. void |
1415 | + // (*__cgo_0)()). Treat this special case as void. This case is |
1416 | + // invalid according to ISO C anyway (i.e. void (*__cgo_1)(...) is not |
1417 | + // legal). |
1418 | + if _, ok := f.(*dwarf.DotDotDotType); ok && i == 0 { |
1419 | + p, gp = nil, nil |
1420 | + break |
1421 | + } |
1422 | + p[i] = c.FuncArg(f, pos) |
1423 | + gp[i] = &ast.Field{Type: p[i].Go} |
1424 | + } |
1425 | + var r *Type |
1426 | + var gr []*ast.Field |
1427 | + if _, ok := dtype.ReturnType.(*dwarf.VoidType); ok { |
1428 | + gr = []*ast.Field{{Type: c.goVoid}} |
1429 | + } else if dtype.ReturnType != nil { |
1430 | + r = c.Type(dtype.ReturnType, pos) |
1431 | + gr = []*ast.Field{{Type: r.Go}} |
1432 | + } |
1433 | + return &FuncType{ |
1434 | + Params: p, |
1435 | + Result: r, |
1436 | + Go: &ast.FuncType{ |
1437 | + Params: &ast.FieldList{List: gp}, |
1438 | + Results: &ast.FieldList{List: gr}, |
1439 | + }, |
1440 | + } |
1441 | +} |
1442 | + |
1443 | +// Identifier |
1444 | +func (c *typeConv) Ident(s string) *ast.Ident { |
1445 | + return ast.NewIdent(s) |
1446 | +} |
1447 | + |
1448 | +// Opaque type of n bytes. |
1449 | +func (c *typeConv) Opaque(n int64) ast.Expr { |
1450 | + return &ast.ArrayType{ |
1451 | + Len: c.intExpr(n), |
1452 | + Elt: c.byte, |
1453 | + } |
1454 | +} |
1455 | + |
1456 | +// Expr for integer n. |
1457 | +func (c *typeConv) intExpr(n int64) ast.Expr { |
1458 | + return &ast.BasicLit{ |
1459 | + Kind: token.INT, |
1460 | + Value: strconv.FormatInt(n, 10), |
1461 | + } |
1462 | +} |
1463 | + |
1464 | +// Add padding of given size to fld. |
1465 | +func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field { |
1466 | + n := len(fld) |
1467 | + fld = fld[0 : n+1] |
1468 | + fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)} |
1469 | + return fld |
1470 | +} |
1471 | + |
1472 | +// Struct conversion: return Go and (6g) C syntax for type. |
1473 | +func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) { |
1474 | + var buf bytes.Buffer |
1475 | + buf.WriteString("struct {") |
1476 | + fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field |
1477 | + off := int64(0) |
1478 | + |
1479 | + // Rename struct fields that happen to be named Go keywords into |
1480 | + // _{keyword}. Create a map from C ident -> Go ident. The Go ident will |
1481 | + // be mangled. Any existing identifier that already has the same name on |
1482 | + // the C-side will cause the Go-mangled version to be prefixed with _. |
1483 | + // (e.g. in a struct with fields '_type' and 'type', the latter would be |
1484 | + // rendered as '__type' in Go). |
1485 | + ident := make(map[string]string) |
1486 | + used := make(map[string]bool) |
1487 | + for _, f := range dt.Field { |
1488 | + ident[f.Name] = f.Name |
1489 | + used[f.Name] = true |
1490 | + } |
1491 | + |
1492 | + if !*godefs && !*cdefs { |
1493 | + for cid, goid := range ident { |
1494 | + if token.Lookup(goid).IsKeyword() { |
1495 | + // Avoid keyword |
1496 | + goid = "_" + goid |
1497 | + |
1498 | + // Also avoid existing fields |
1499 | + for _, exist := used[goid]; exist; _, exist = used[goid] { |
1500 | + goid = "_" + goid |
1501 | + } |
1502 | + |
1503 | + used[goid] = true |
1504 | + ident[cid] = goid |
1505 | + } |
1506 | + } |
1507 | + } |
1508 | + |
1509 | + anon := 0 |
1510 | + for _, f := range dt.Field { |
1511 | + if f.ByteOffset > off { |
1512 | + fld = c.pad(fld, f.ByteOffset-off) |
1513 | + off = f.ByteOffset |
1514 | + } |
1515 | + t := c.Type(f.Type, pos) |
1516 | + tgo := t.Go |
1517 | + size := t.Size |
1518 | + |
1519 | + if f.BitSize > 0 { |
1520 | + if f.BitSize%8 != 0 { |
1521 | + continue |
1522 | + } |
1523 | + size = f.BitSize / 8 |
1524 | + name := tgo.(*ast.Ident).String() |
1525 | + if strings.HasPrefix(name, "int") { |
1526 | + name = "int" |
1527 | + } else { |
1528 | + name = "uint" |
1529 | + } |
1530 | + tgo = ast.NewIdent(name + fmt.Sprint(f.BitSize)) |
1531 | + } |
1532 | + |
1533 | + n := len(fld) |
1534 | + fld = fld[0 : n+1] |
1535 | + name := f.Name |
1536 | + if name == "" { |
1537 | + name = fmt.Sprintf("anon%d", anon) |
1538 | + anon++ |
1539 | + ident[name] = name |
1540 | + } |
1541 | + fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo} |
1542 | + off += size |
1543 | + buf.WriteString(t.C.String()) |
1544 | + buf.WriteString(" ") |
1545 | + buf.WriteString(name) |
1546 | + buf.WriteString("; ") |
1547 | + if t.Align > align { |
1548 | + align = t.Align |
1549 | + } |
1550 | + } |
1551 | + if off < dt.ByteSize { |
1552 | + fld = c.pad(fld, dt.ByteSize-off) |
1553 | + off = dt.ByteSize |
1554 | + } |
1555 | + if off != dt.ByteSize { |
1556 | + fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize) |
1557 | + } |
1558 | + buf.WriteString("}") |
1559 | + csyntax = buf.String() |
1560 | + |
1561 | + if *godefs || *cdefs { |
1562 | + godefsFields(fld) |
1563 | + } |
1564 | + expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} |
1565 | + return |
1566 | +} |
1567 | + |
1568 | +func upper(s string) string { |
1569 | + if s == "" { |
1570 | + return "" |
1571 | + } |
1572 | + r, size := utf8.DecodeRuneInString(s) |
1573 | + if r == '_' { |
1574 | + return "X" + s |
1575 | + } |
1576 | + return string(unicode.ToUpper(r)) + s[size:] |
1577 | +} |
1578 | + |
1579 | +// godefsFields rewrites field names for use in Go or C definitions. |
1580 | +// It strips leading common prefixes (like tv_ in tv_sec, tv_usec) |
1581 | +// converts names to upper case, and rewrites _ into Pad_godefs_n, |
1582 | +// so that all fields are exported. |
1583 | +func godefsFields(fld []*ast.Field) { |
1584 | + prefix := fieldPrefix(fld) |
1585 | + npad := 0 |
1586 | + for _, f := range fld { |
1587 | + for _, n := range f.Names { |
1588 | + if n.Name != prefix { |
1589 | + n.Name = strings.TrimPrefix(n.Name, prefix) |
1590 | + } |
1591 | + if n.Name == "_" { |
1592 | + // Use exported name instead. |
1593 | + n.Name = "Pad_cgo_" + strconv.Itoa(npad) |
1594 | + npad++ |
1595 | + } |
1596 | + if !*cdefs { |
1597 | + n.Name = upper(n.Name) |
1598 | + } |
1599 | + } |
1600 | + p := &f.Type |
1601 | + t := *p |
1602 | + if star, ok := t.(*ast.StarExpr); ok { |
1603 | + star = &ast.StarExpr{X: star.X} |
1604 | + *p = star |
1605 | + p = &star.X |
1606 | + t = *p |
1607 | + } |
1608 | + if id, ok := t.(*ast.Ident); ok { |
1609 | + if id.Name == "unsafe.Pointer" { |
1610 | + *p = ast.NewIdent("*byte") |
1611 | + } |
1612 | + } |
1613 | + } |
1614 | +} |
1615 | + |
1616 | +// fieldPrefix returns the prefix that should be removed from all the |
1617 | +// field names when generating the C or Go code. For generated |
1618 | +// C, we leave the names as is (tv_sec, tv_usec), since that's what |
1619 | +// people are used to seeing in C. For generated Go code, such as |
1620 | +// package syscall's data structures, we drop a common prefix |
1621 | +// (so sec, usec, which will get turned into Sec, Usec for exporting). |
1622 | +func fieldPrefix(fld []*ast.Field) string { |
1623 | + if *cdefs { |
1624 | + return "" |
1625 | + } |
1626 | + prefix := "" |
1627 | + for _, f := range fld { |
1628 | + for _, n := range f.Names { |
1629 | + // Ignore field names that don't have the prefix we're |
1630 | + // looking for. It is common in C headers to have fields |
1631 | + // named, say, _pad in an otherwise prefixed header. |
1632 | + // If the struct has 3 fields tv_sec, tv_usec, _pad1, then we |
1633 | + // still want to remove the tv_ prefix. |
1634 | + // The check for "orig_" here handles orig_eax in the |
1635 | + // x86 ptrace register sets, which otherwise have all fields |
1636 | + // with reg_ prefixes. |
1637 | + if strings.HasPrefix(n.Name, "orig_") || strings.HasPrefix(n.Name, "_") { |
1638 | + continue |
1639 | + } |
1640 | + i := strings.Index(n.Name, "_") |
1641 | + if i < 0 { |
1642 | + continue |
1643 | + } |
1644 | + if prefix == "" { |
1645 | + prefix = n.Name[:i+1] |
1646 | + } else if prefix != n.Name[:i+1] { |
1647 | + return "" |
1648 | + } |
1649 | + } |
1650 | + } |
1651 | + return prefix |
1652 | +} |
1653 | |
1654 | === added directory '.pc/build-cgo.diff/src/cmd/go' |
1655 | === added file '.pc/build-cgo.diff/src/cmd/go/tool.go' |
1656 | --- .pc/build-cgo.diff/src/cmd/go/tool.go 1970-01-01 00:00:00 +0000 |
1657 | +++ .pc/build-cgo.diff/src/cmd/go/tool.go 2014-08-14 02:29:21 +0000 |
1658 | @@ -0,0 +1,156 @@ |
1659 | +// Copyright 2011 The Go Authors. All rights reserved. |
1660 | +// Use of this source code is governed by a BSD-style |
1661 | +// license that can be found in the LICENSE file. |
1662 | + |
1663 | +package main |
1664 | + |
1665 | +import ( |
1666 | + "fmt" |
1667 | + "go/build" |
1668 | + "os" |
1669 | + "os/exec" |
1670 | + "path/filepath" |
1671 | + "runtime" |
1672 | + "sort" |
1673 | + "strings" |
1674 | +) |
1675 | + |
1676 | +var cmdTool = &Command{ |
1677 | + Run: runTool, |
1678 | + UsageLine: "tool [-n] command [args...]", |
1679 | + Short: "run specified go tool", |
1680 | + Long: ` |
1681 | +Tool runs the go tool command identified by the arguments. |
1682 | +With no arguments it prints the list of known tools. |
1683 | + |
1684 | +The -n flag causes tool to print the command that would be |
1685 | +executed but not execute it. |
1686 | + |
1687 | +For more about each tool command, see 'go tool command -h'. |
1688 | +`, |
1689 | +} |
1690 | + |
1691 | +var ( |
1692 | + toolGOOS = runtime.GOOS |
1693 | + toolGOARCH = runtime.GOARCH |
1694 | + toolIsWindows = toolGOOS == "windows" |
1695 | + toolDir = build.ToolDir |
1696 | + |
1697 | + toolN bool |
1698 | +) |
1699 | + |
1700 | +func init() { |
1701 | + cmdTool.Flag.BoolVar(&toolN, "n", false, "") |
1702 | +} |
1703 | + |
1704 | +const toolWindowsExtension = ".exe" |
1705 | + |
1706 | +func tool(toolName string) string { |
1707 | + toolPath := filepath.Join(toolDir, toolName) |
1708 | + if toolIsWindows && toolName != "pprof" { |
1709 | + toolPath += toolWindowsExtension |
1710 | + } |
1711 | + // Give a nice message if there is no tool with that name. |
1712 | + if _, err := os.Stat(toolPath); err != nil { |
1713 | + if isInGoToolsRepo(toolName) { |
1714 | + fmt.Fprintf(os.Stderr, "go tool: no such tool %q; to install:\n\tgo get code.google.com/p/go.tools/cmd/%s\n", toolName, toolName) |
1715 | + } else { |
1716 | + fmt.Fprintf(os.Stderr, "go tool: no such tool %q\n", toolName) |
1717 | + } |
1718 | + setExitStatus(3) |
1719 | + exit() |
1720 | + } |
1721 | + return toolPath |
1722 | +} |
1723 | + |
1724 | +func isInGoToolsRepo(toolName string) bool { |
1725 | + switch toolName { |
1726 | + case "cover", "vet": |
1727 | + return true |
1728 | + } |
1729 | + return false |
1730 | +} |
1731 | + |
1732 | +func runTool(cmd *Command, args []string) { |
1733 | + if len(args) == 0 { |
1734 | + listTools() |
1735 | + return |
1736 | + } |
1737 | + toolName := args[0] |
1738 | + // The tool name must be lower-case letters, numbers or underscores. |
1739 | + for _, c := range toolName { |
1740 | + switch { |
1741 | + case 'a' <= c && c <= 'z', '0' <= c && c <= '9', c == '_': |
1742 | + default: |
1743 | + fmt.Fprintf(os.Stderr, "go tool: bad tool name %q\n", toolName) |
1744 | + setExitStatus(2) |
1745 | + return |
1746 | + } |
1747 | + } |
1748 | + toolPath := tool(toolName) |
1749 | + if toolPath == "" { |
1750 | + return |
1751 | + } |
1752 | + if toolIsWindows && toolName == "pprof" { |
1753 | + args = append([]string{"perl", toolPath}, args[1:]...) |
1754 | + var err error |
1755 | + toolPath, err = exec.LookPath("perl") |
1756 | + if err != nil { |
1757 | + fmt.Fprintf(os.Stderr, "go tool: perl not found\n") |
1758 | + setExitStatus(3) |
1759 | + return |
1760 | + } |
1761 | + } |
1762 | + if toolN { |
1763 | + fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " ")) |
1764 | + return |
1765 | + } |
1766 | + toolCmd := &exec.Cmd{ |
1767 | + Path: toolPath, |
1768 | + Args: args, |
1769 | + Stdin: os.Stdin, |
1770 | + Stdout: os.Stdout, |
1771 | + Stderr: os.Stderr, |
1772 | + } |
1773 | + err := toolCmd.Run() |
1774 | + if err != nil { |
1775 | + // Only print about the exit status if the command |
1776 | + // didn't even run (not an ExitError) or it didn't exit cleanly |
1777 | + // or we're printing command lines too (-x mode). |
1778 | + // Assume if command exited cleanly (even with non-zero status) |
1779 | + // it printed any messages it wanted to print. |
1780 | + if e, ok := err.(*exec.ExitError); !ok || !e.Exited() || buildX { |
1781 | + fmt.Fprintf(os.Stderr, "go tool %s: %s\n", toolName, err) |
1782 | + } |
1783 | + setExitStatus(1) |
1784 | + return |
1785 | + } |
1786 | +} |
1787 | + |
1788 | +// listTools prints a list of the available tools in the tools directory. |
1789 | +func listTools() { |
1790 | + f, err := os.Open(toolDir) |
1791 | + if err != nil { |
1792 | + fmt.Fprintf(os.Stderr, "go tool: no tool directory: %s\n", err) |
1793 | + setExitStatus(2) |
1794 | + return |
1795 | + } |
1796 | + defer f.Close() |
1797 | + names, err := f.Readdirnames(-1) |
1798 | + if err != nil { |
1799 | + fmt.Fprintf(os.Stderr, "go tool: can't read directory: %s\n", err) |
1800 | + setExitStatus(2) |
1801 | + return |
1802 | + } |
1803 | + |
1804 | + sort.Strings(names) |
1805 | + for _, name := range names { |
1806 | + // Unify presentation by going to lower case. |
1807 | + name = strings.ToLower(name) |
1808 | + // If it's windows, don't show the .exe suffix. |
1809 | + if toolIsWindows && strings.HasSuffix(name, toolWindowsExtension) { |
1810 | + name = name[:len(name)-len(toolWindowsExtension)] |
1811 | + } |
1812 | + fmt.Println(name) |
1813 | + } |
1814 | +} |
1815 | |
1816 | === modified file 'debian/changelog' |
1817 | --- debian/changelog 2014-03-26 10:50:18 +0000 |
1818 | +++ debian/changelog 2014-08-14 02:29:21 +0000 |
1819 | @@ -1,3 +1,9 @@ |
1820 | +gccgo-go (1.2.1-0ubuntu2) UNRELEASED; urgency=medium |
1821 | + |
1822 | + * Build and install cgo too. |
1823 | + |
1824 | + -- Michael Hudson-Doyle <michael.hudson@linaro.org> Thu, 14 Aug 2014 14:01:51 +1200 |
1825 | + |
1826 | gccgo-go (1.2.1-0ubuntu1) trusty; urgency=medium |
1827 | |
1828 | * New upstream point release. |
1829 | |
1830 | === modified file 'debian/install' |
1831 | --- debian/install 2014-01-28 12:32:46 +0000 |
1832 | +++ debian/install 2014-08-14 02:29:21 +0000 |
1833 | @@ -1,1 +1,2 @@ |
1834 | src/cmd/go/gccgo-go /usr/bin |
1835 | +src/cmd/cgo/cgo /usr/lib/gccgo/tool |
1836 | \ No newline at end of file |
1837 | |
1838 | === modified file 'debian/lintian-overrides' |
1839 | --- debian/lintian-overrides 2014-01-27 09:18:55 +0000 |
1840 | +++ debian/lintian-overrides 2014-08-14 02:29:21 +0000 |
1841 | @@ -1,2 +1,3 @@ |
1842 | # go binaries should never be stripped |
1843 | gccgo-go: unstripped-binary-or-object usr/bin/gccgo-go |
1844 | +gccgo-go: unstripped-binary-or-object usr/lib/gccgo/tool/cgo |
1845 | |
1846 | === added file 'debian/patches/build-cgo.diff' |
1847 | --- debian/patches/build-cgo.diff 1970-01-01 00:00:00 +0000 |
1848 | +++ debian/patches/build-cgo.diff 2014-08-14 02:29:21 +0000 |
1849 | @@ -0,0 +1,49 @@ |
1850 | +=== added file 'src/cmd/cgo/Makefile' |
1851 | +Index: gccgo-go/src/cmd/cgo/Makefile |
1852 | +=================================================================== |
1853 | +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 |
1854 | ++++ gccgo-go/src/cmd/cgo/Makefile 2014-08-14 14:13:14.620783230 +1200 |
1855 | +@@ -0,0 +1,16 @@ |
1856 | ++TARG=cgo |
1857 | ++GOFILES=\ |
1858 | ++ ast.go\ |
1859 | ++ doc.go\ |
1860 | ++ gcc.go\ |
1861 | ++ godefs.go\ |
1862 | ++ main.go\ |
1863 | ++ out.go\ |
1864 | ++ util.go |
1865 | ++ |
1866 | ++build: |
1867 | ++ gccgo -o _$(TARG)_ -c $(GOFLAGS) $(GOFILES) |
1868 | ++ gccgo -o $(TARG) _$(TARG)_ $(LDFLAGS) |
1869 | ++ |
1870 | ++clean: |
1871 | ++ rm -f _$(TARG)_ $(TARG) |
1872 | +Index: gccgo-go/src/cmd/go/tool.go |
1873 | +=================================================================== |
1874 | +--- gccgo-go.orig/src/cmd/go/tool.go 2014-08-14 14:11:25.772787121 +1200 |
1875 | ++++ gccgo-go/src/cmd/go/tool.go 2014-08-14 14:20:57.504766684 +1200 |
1876 | +@@ -41,6 +41,9 @@ |
1877 | + |
1878 | + func init() { |
1879 | + cmdTool.Flag.BoolVar(&toolN, "n", false, "") |
1880 | ++ if (runtime.Compiler == "gccgo") { |
1881 | ++ toolDir = filepath.Join(runtime.GOROOT(), "lib/gccgo/tool") |
1882 | ++ } |
1883 | + } |
1884 | + |
1885 | + const toolWindowsExtension = ".exe" |
1886 | +Index: gccgo-go/src/cmd/cgo/gcc.go |
1887 | +=================================================================== |
1888 | +--- gccgo-go.orig/src/cmd/cgo/gcc.go 2014-08-12 15:34:03.612461000 +1200 |
1889 | ++++ gccgo-go/src/cmd/cgo/gcc.go 2014-08-14 14:14:30.380780522 +1200 |
1890 | +@@ -718,7 +718,7 @@ |
1891 | + if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { |
1892 | + return ret |
1893 | + } |
1894 | +- return strings.Fields(defaultCC) |
1895 | ++ return strings.Fields("gcc") |
1896 | + } |
1897 | + |
1898 | + // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". |
1899 | |
1900 | === modified file 'debian/patches/series' |
1901 | --- debian/patches/series 2014-03-26 10:50:18 +0000 |
1902 | +++ debian/patches/series 2014-08-14 02:29:21 +0000 |
1903 | @@ -5,3 +5,4 @@ |
1904 | issue28050043_60001_70001.diff |
1905 | issue61970044_80001.diff |
1906 | issue80300043_60001.diff |
1907 | +build-cgo.diff |
1908 | |
1909 | === modified file 'debian/rules' |
1910 | --- debian/rules 2014-02-15 22:18:45 +0000 |
1911 | +++ debian/rules 2014-08-14 02:29:21 +0000 |
1912 | @@ -10,6 +10,7 @@ |
1913 | |
1914 | override_dh_auto_clean: |
1915 | dh_auto_clean -D src/cmd/go |
1916 | + dh_auto_clean -D src/cmd/cgo |
1917 | |
1918 | override_dh_strip: |
1919 | # strip disabled as golang upstream doesn't support it and it makes go |
1920 | @@ -20,3 +21,4 @@ |
1921 | |
1922 | override_dh_auto_build: |
1923 | dh_auto_build -D src/cmd/go |
1924 | + dh_auto_build -D src/cmd/cgo |
1925 | |
1926 | === added file 'src/cmd/cgo/Makefile' |
1927 | --- src/cmd/cgo/Makefile 1970-01-01 00:00:00 +0000 |
1928 | +++ src/cmd/cgo/Makefile 2014-08-14 02:29:21 +0000 |
1929 | @@ -0,0 +1,16 @@ |
1930 | +TARG=cgo |
1931 | +GOFILES=\ |
1932 | + ast.go\ |
1933 | + doc.go\ |
1934 | + gcc.go\ |
1935 | + godefs.go\ |
1936 | + main.go\ |
1937 | + out.go\ |
1938 | + util.go |
1939 | + |
1940 | +build: |
1941 | + gccgo -o _$(TARG)_ -c $(GOFLAGS) $(GOFILES) |
1942 | + gccgo -o $(TARG) _$(TARG)_ $(LDFLAGS) |
1943 | + |
1944 | +clean: |
1945 | + rm -f _$(TARG)_ $(TARG) |
1946 | |
1947 | === modified file 'src/cmd/cgo/gcc.go' |
1948 | --- src/cmd/cgo/gcc.go 2014-01-27 09:18:55 +0000 |
1949 | +++ src/cmd/cgo/gcc.go 2014-08-14 02:29:21 +0000 |
1950 | @@ -718,7 +718,7 @@ |
1951 | if ret := strings.Fields(os.Getenv("GCC")); len(ret) > 0 { |
1952 | return ret |
1953 | } |
1954 | - return strings.Fields(defaultCC) |
1955 | + return strings.Fields("gcc") |
1956 | } |
1957 | |
1958 | // gccMachine returns the gcc -m flag to use, either "-m32", "-m64" or "-marm". |
1959 | |
1960 | === modified file 'src/cmd/go/tool.go' |
1961 | --- src/cmd/go/tool.go 2014-01-27 09:18:55 +0000 |
1962 | +++ src/cmd/go/tool.go 2014-08-14 02:29:21 +0000 |
1963 | @@ -41,6 +41,9 @@ |
1964 | |
1965 | func init() { |
1966 | cmdTool.Flag.BoolVar(&toolN, "n", false, "") |
1967 | + if (runtime.Compiler == "gccgo") { |
1968 | + toolDir = filepath.Join(runtime.GOROOT(), "lib/gccgo/tool") |
1969 | + } |
1970 | } |
1971 | |
1972 | const toolWindowsExtension = ".exe" |
Bah the diff is certainly horrible. Here's a debdiff: http:// paste.ubuntu. com/8041422/