Merge lp:~mwhudson/ubuntu/utopic/gccgo-go/build-cgo into lp:ubuntu/utopic/gccgo-go

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
Reviewer Review Type Date Requested Status
James Page Pending
Review via email: mp+230739@code.launchpad.net

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.
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Bah the diff is certainly horrible. Here's a debdiff: http://paste.ubuntu.com/8041422/

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

Subscribers

People subscribed via source and target branches