godefs.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. package main
  5. import (
  6. "bytes"
  7. "fmt"
  8. "go/ast"
  9. "go/printer"
  10. "go/token"
  11. "os"
  12. "strings"
  13. )
  14. // godefs returns the output for -godefs mode.
  15. func (p *Package) godefs(f *File, srcfile string) string {
  16. var buf bytes.Buffer
  17. fmt.Fprintf(&buf, "// Created by cgo -godefs - DO NOT EDIT\n")
  18. fmt.Fprintf(&buf, "// %s\n", strings.Join(os.Args, " "))
  19. fmt.Fprintf(&buf, "\n")
  20. override := make(map[string]string)
  21. // Allow source file to specify override mappings.
  22. // For example, the socket data structures refer
  23. // to in_addr and in_addr6 structs but we want to be
  24. // able to treat them as byte arrays, so the godefs
  25. // inputs in package syscall say
  26. //
  27. // // +godefs map struct_in_addr [4]byte
  28. // // +godefs map struct_in_addr6 [16]byte
  29. //
  30. for _, g := range f.Comments {
  31. for _, c := range g.List {
  32. i := strings.Index(c.Text, "+godefs map")
  33. if i < 0 {
  34. continue
  35. }
  36. s := strings.TrimSpace(c.Text[i+len("+godefs map"):])
  37. i = strings.Index(s, " ")
  38. if i < 0 {
  39. fmt.Fprintf(os.Stderr, "invalid +godefs map comment: %s\n", c.Text)
  40. continue
  41. }
  42. override["_Ctype_"+strings.TrimSpace(s[:i])] = strings.TrimSpace(s[i:])
  43. }
  44. }
  45. for _, n := range f.Name {
  46. if s := override[n.Go]; s != "" {
  47. override[n.Mangle] = s
  48. }
  49. }
  50. // Otherwise, if the source file says type T C.whatever,
  51. // use "T" as the mangling of C.whatever,
  52. // except in the definition (handled at end of function).
  53. refName := make(map[*ast.Expr]*Name)
  54. for _, r := range f.Ref {
  55. refName[r.Expr] = r.Name
  56. }
  57. for _, d := range f.AST.Decls {
  58. d, ok := d.(*ast.GenDecl)
  59. if !ok || d.Tok != token.TYPE {
  60. continue
  61. }
  62. for _, s := range d.Specs {
  63. s := s.(*ast.TypeSpec)
  64. n := refName[&s.Type]
  65. if n != nil && n.Mangle != "" {
  66. override[n.Mangle] = s.Name.Name
  67. }
  68. }
  69. }
  70. // Extend overrides using typedefs:
  71. // If we know that C.xxx should format as T
  72. // and xxx is a typedef for yyy, make C.yyy format as T.
  73. for typ, def := range typedef {
  74. if new := override[typ]; new != "" {
  75. if id, ok := def.Go.(*ast.Ident); ok {
  76. override[id.Name] = new
  77. }
  78. }
  79. }
  80. // Apply overrides.
  81. for old, new := range override {
  82. if id := goIdent[old]; id != nil {
  83. id.Name = new
  84. }
  85. }
  86. // Any names still using the _C syntax are not going to compile,
  87. // although in general we don't know whether they all made it
  88. // into the file, so we can't warn here.
  89. //
  90. // The most common case is union types, which begin with
  91. // _Ctype_union and for which typedef[name] is a Go byte
  92. // array of the appropriate size (such as [4]byte).
  93. // Substitute those union types with byte arrays.
  94. for name, id := range goIdent {
  95. if id.Name == name && strings.Contains(name, "_Ctype_union") {
  96. if def := typedef[name]; def != nil {
  97. id.Name = gofmt(def)
  98. }
  99. }
  100. }
  101. conf.Fprint(&buf, fset, f.AST)
  102. return buf.String()
  103. }
  104. // cdefs returns the output for -cdefs mode.
  105. // The easiest way to do this is to translate the godefs Go to C.
  106. func (p *Package) cdefs(f *File, srcfile string) string {
  107. godefsOutput := p.godefs(f, srcfile)
  108. lines := strings.Split(godefsOutput, "\n")
  109. lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
  110. for i, line := range lines {
  111. lines[i] = strings.TrimSpace(line)
  112. }
  113. var out bytes.Buffer
  114. printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
  115. didTypedef := false
  116. for i := 0; i < len(lines); i++ {
  117. line := lines[i]
  118. // Delete
  119. // package x
  120. if strings.HasPrefix(line, "package ") {
  121. continue
  122. }
  123. // Convert
  124. // const (
  125. // A = 1
  126. // B = 2
  127. // )
  128. //
  129. // to
  130. //
  131. // enum {
  132. // A = 1,
  133. // B = 2,
  134. // };
  135. if line == "const (" {
  136. printf("enum {\n")
  137. for i++; i < len(lines) && lines[i] != ")"; i++ {
  138. line = lines[i]
  139. if line != "" {
  140. printf("\t%s,", line)
  141. }
  142. printf("\n")
  143. }
  144. printf("};\n")
  145. continue
  146. }
  147. // Convert
  148. // const A = 1
  149. // to
  150. // enum { A = 1 };
  151. if strings.HasPrefix(line, "const ") {
  152. printf("enum { %s };\n", line[len("const "):])
  153. continue
  154. }
  155. // On first type definition, typedef all the structs
  156. // in case there are dependencies between them.
  157. if !didTypedef && strings.HasPrefix(line, "type ") {
  158. didTypedef = true
  159. for _, line := range lines {
  160. line = strings.TrimSpace(line)
  161. if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
  162. s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
  163. printf("typedef struct %s %s;\n", s, s)
  164. }
  165. }
  166. printf("\n")
  167. printf("#pragma pack on\n")
  168. printf("\n")
  169. }
  170. // Convert
  171. // type T struct {
  172. // X int64
  173. // Y *int32
  174. // Z [4]byte
  175. // }
  176. //
  177. // to
  178. //
  179. // struct T {
  180. // int64 X;
  181. // int32 *Y;
  182. // byte Z[4];
  183. // }
  184. if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
  185. if len(lines) > i+1 && lines[i+1] == "}" {
  186. // do not output empty struct
  187. i++
  188. continue
  189. }
  190. s := line[len("type ") : len(line)-len(" struct {")]
  191. printf("struct %s {\n", s)
  192. for i++; i < len(lines) && lines[i] != "}"; i++ {
  193. line := lines[i]
  194. if line != "" {
  195. f := strings.Fields(line)
  196. if len(f) != 2 {
  197. fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
  198. nerrors++
  199. continue
  200. }
  201. printf("\t%s;", cdecl(f[0], f[1]))
  202. }
  203. printf("\n")
  204. }
  205. printf("};\n")
  206. continue
  207. }
  208. // Convert
  209. // type T int
  210. // to
  211. // typedef int T;
  212. if strings.HasPrefix(line, "type ") {
  213. f := strings.Fields(line[len("type "):])
  214. if len(f) != 2 {
  215. fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
  216. nerrors++
  217. continue
  218. }
  219. printf("typedef\t%s;\n", cdecl(f[0], f[1]))
  220. continue
  221. }
  222. printf("%s\n", line)
  223. }
  224. if didTypedef {
  225. printf("\n")
  226. printf("#pragma pack off\n")
  227. }
  228. return out.String()
  229. }
  230. // cdecl returns the C declaration for the given Go name and type.
  231. // It only handles the specific cases necessary for converting godefs output.
  232. func cdecl(name, typ string) string {
  233. // X *[0]byte -> X *void
  234. if strings.HasPrefix(typ, "*[0]") {
  235. typ = "*void"
  236. }
  237. // X [4]byte -> X[4] byte
  238. for strings.HasPrefix(typ, "[") {
  239. i := strings.Index(typ, "]") + 1
  240. name = name + typ[:i]
  241. typ = typ[i:]
  242. }
  243. // X *byte -> *X byte
  244. for strings.HasPrefix(typ, "*") {
  245. name = "*" + name
  246. typ = typ[1:]
  247. }
  248. // X T -> T X
  249. // Handle the special case: 'unsafe.Pointer' is 'void *'
  250. if typ == "unsafe.Pointer" {
  251. typ = "void"
  252. name = "*" + name
  253. }
  254. return typ + "\t" + name
  255. }
  256. var gofmtBuf bytes.Buffer
  257. // gofmt returns the gofmt-formatted string for an AST node.
  258. func gofmt(n interface{}) string {
  259. gofmtBuf.Reset()
  260. err := printer.Fprint(&gofmtBuf, fset, n)
  261. if err != nil {
  262. return "<" + err.Error() + ">"
  263. }
  264. return gofmtBuf.String()
  265. }