Source file src/cmd/cgo/main.go
1
2
3
4
5
6
7
8
9
10
11 package main
12
13 import (
14 "crypto/md5"
15 "flag"
16 "fmt"
17 "go/ast"
18 "go/printer"
19 "go/token"
20 "io"
21 "io/ioutil"
22 "os"
23 "path/filepath"
24 "reflect"
25 "runtime"
26 "sort"
27 "strings"
28
29 "cmd/internal/edit"
30 "cmd/internal/objabi"
31 )
32
33
34 type Package struct {
35 PackageName string
36 PackagePath string
37 PtrSize int64
38 IntSize int64
39 GccOptions []string
40 GccIsClang bool
41 CgoFlags map[string][]string
42 Written map[string]bool
43 Name map[string]*Name
44 ExpFunc []*ExpFunc
45 Decl []ast.Decl
46 GoFiles []string
47 GccFiles []string
48 Preamble string
49 typedefs map[string]bool
50 typedefList []typedefInfo
51 }
52
53
54
55 type typedefInfo struct {
56 typedef string
57 pos token.Pos
58 }
59
60
61 type File struct {
62 AST *ast.File
63 Comments []*ast.CommentGroup
64 Package string
65 Preamble string
66 Ref []*Ref
67 Calls []*Call
68 ExpFunc []*ExpFunc
69 Name map[string]*Name
70 NamePos map[*Name]token.Pos
71 Edit *edit.Buffer
72 }
73
74 func (f *File) offset(p token.Pos) int {
75 return fset.Position(p).Offset
76 }
77
78 func nameKeys(m map[string]*Name) []string {
79 var ks []string
80 for k := range m {
81 ks = append(ks, k)
82 }
83 sort.Strings(ks)
84 return ks
85 }
86
87
88 type Call struct {
89 Call *ast.CallExpr
90 Deferred bool
91 Done bool
92 }
93
94
95 type Ref struct {
96 Name *Name
97 Expr *ast.Expr
98 Context astContext
99 Done bool
100 }
101
102 func (r *Ref) Pos() token.Pos {
103 return (*r.Expr).Pos()
104 }
105
106 var nameKinds = []string{"iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"}
107
108
109 type Name struct {
110 Go string
111 Mangle string
112 C string
113 Define string
114 Kind string
115 Type *Type
116 FuncType *FuncType
117 AddError bool
118 Const string
119 }
120
121
122 func (n *Name) IsVar() bool {
123 return n.Kind == "var" || n.Kind == "fpvar"
124 }
125
126
127 func (n *Name) IsConst() bool {
128 return strings.HasSuffix(n.Kind, "const")
129 }
130
131
132
133
134 type ExpFunc struct {
135 Func *ast.FuncDecl
136 ExpName string
137 Doc string
138 }
139
140
141 type TypeRepr struct {
142 Repr string
143 FormatArgs []interface{}
144 }
145
146
147 type Type struct {
148 Size int64
149 Align int64
150 C *TypeRepr
151 Go ast.Expr
152 EnumValues map[string]int64
153 Typedef string
154 BadPointer bool
155 }
156
157
158 type FuncType struct {
159 Params []*Type
160 Result *Type
161 Go *ast.FuncType
162 }
163
164 func usage() {
165 fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
166 flag.PrintDefaults()
167 os.Exit(2)
168 }
169
170 var ptrSizeMap = map[string]int64{
171 "386": 4,
172 "amd64": 8,
173 "arm": 4,
174 "arm64": 8,
175 "mips": 4,
176 "mipsle": 4,
177 "mips64": 8,
178 "mips64le": 8,
179 "ppc64": 8,
180 "ppc64le": 8,
181 "riscv64": 8,
182 "s390": 4,
183 "s390x": 8,
184 "sparc64": 8,
185 }
186
187 var intSizeMap = map[string]int64{
188 "386": 4,
189 "amd64": 8,
190 "arm": 4,
191 "arm64": 8,
192 "mips": 4,
193 "mipsle": 4,
194 "mips64": 8,
195 "mips64le": 8,
196 "ppc64": 8,
197 "ppc64le": 8,
198 "riscv64": 8,
199 "s390": 4,
200 "s390x": 8,
201 "sparc64": 8,
202 }
203
204 var cPrefix string
205
206 var fset = token.NewFileSet()
207
208 var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
209 var dynout = flag.String("dynout", "", "write -dynimport output to this file")
210 var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimport output")
211 var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
212
213
214
215
216 var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
217
218 var srcDir = flag.String("srcdir", "", "source directory")
219 var objDir = flag.String("objdir", "", "object directory")
220 var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
221 var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
222
223 var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
224 var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
225 var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
226 var gccgoMangleCheckDone bool
227 var gccgoNewmanglingInEffect bool
228 var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
229 var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
230 var goarch, goos string
231
232 func main() {
233 objabi.AddVersionFlag()
234 flag.Usage = usage
235 flag.Parse()
236
237 if *dynobj != "" {
238
239
240
241
242
243
244
245
246 dynimport(*dynobj)
247 return
248 }
249
250 if *godefs {
251
252
253
254 conf.Mode &^= printer.SourcePos
255 }
256
257 args := flag.Args()
258 if len(args) < 1 {
259 usage()
260 }
261
262
263
264 var i int
265 for i = len(args); i > 0; i-- {
266 if !strings.HasSuffix(args[i-1], ".go") {
267 break
268 }
269 }
270 if i == len(args) {
271 usage()
272 }
273
274 goFiles := args[i:]
275
276 for _, arg := range args[:i] {
277 if arg == "-fsanitize=thread" {
278 tsanProlog = yesTsanProlog
279 }
280 if arg == "-fsanitize=memory" {
281 msanProlog = yesMsanProlog
282 }
283 }
284
285 p := newPackage(args[:i])
286
287
288 if ldflags := os.Getenv("CGO_LDFLAGS"); ldflags != "" {
289 args, err := splitQuoted(ldflags)
290 if err != nil {
291 fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags, err)
292 }
293 p.addToFlag("LDFLAGS", args)
294 }
295
296
297
298
299
300
301 h := md5.New()
302 io.WriteString(h, *importPath)
303 fs := make([]*File, len(goFiles))
304 for i, input := range goFiles {
305 if *srcDir != "" {
306 input = filepath.Join(*srcDir, input)
307 }
308
309 b, err := ioutil.ReadFile(input)
310 if err != nil {
311 fatalf("%s", err)
312 }
313 if _, err = h.Write(b); err != nil {
314 fatalf("%s", err)
315 }
316
317 f := new(File)
318 f.Edit = edit.NewBuffer(b)
319 f.ParseGo(input, b)
320 f.DiscardCgoDirectives()
321 fs[i] = f
322 }
323
324 cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])
325
326 if *objDir == "" {
327
328
329 os.Mkdir("_obj", 0777)
330 *objDir = "_obj"
331 }
332 *objDir += string(filepath.Separator)
333
334 for i, input := range goFiles {
335 f := fs[i]
336 p.Translate(f)
337 for _, cref := range f.Ref {
338 switch cref.Context {
339 case ctxCall, ctxCall2:
340 if cref.Name.Kind != "type" {
341 break
342 }
343 old := *cref.Expr
344 *cref.Expr = cref.Name.Type.Go
345 f.Edit.Replace(f.offset(old.Pos()), f.offset(old.End()), gofmt(cref.Name.Type.Go))
346 }
347 }
348 if nerrors > 0 {
349 os.Exit(2)
350 }
351 p.PackagePath = f.Package
352 p.Record(f)
353 if *godefs {
354 os.Stdout.WriteString(p.godefs(f, input))
355 } else {
356 p.writeOutput(f, input)
357 }
358 }
359
360 if !*godefs {
361 p.writeDefs()
362 }
363 if nerrors > 0 {
364 os.Exit(2)
365 }
366 }
367
368
369
370 func newPackage(args []string) *Package {
371 goarch = runtime.GOARCH
372 if s := os.Getenv("GOARCH"); s != "" {
373 goarch = s
374 }
375 goos = runtime.GOOS
376 if s := os.Getenv("GOOS"); s != "" {
377 goos = s
378 }
379 ptrSize := ptrSizeMap[goarch]
380 if ptrSize == 0 {
381 fatalf("unknown ptrSize for $GOARCH %q", goarch)
382 }
383 intSize := intSizeMap[goarch]
384 if intSize == 0 {
385 fatalf("unknown intSize for $GOARCH %q", goarch)
386 }
387
388
389 os.Setenv("LANG", "en_US.UTF-8")
390 os.Setenv("LC_ALL", "C")
391
392 p := &Package{
393 PtrSize: ptrSize,
394 IntSize: intSize,
395 CgoFlags: make(map[string][]string),
396 Written: make(map[string]bool),
397 }
398 p.addToFlag("CFLAGS", args)
399 return p
400 }
401
402
403 func (p *Package) Record(f *File) {
404 if p.PackageName == "" {
405 p.PackageName = f.Package
406 } else if p.PackageName != f.Package {
407 error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
408 }
409
410 if p.Name == nil {
411 p.Name = f.Name
412 } else {
413 for k, v := range f.Name {
414 if p.Name[k] == nil {
415 p.Name[k] = v
416 } else if p.incompleteTypedef(p.Name[k].Type) {
417 p.Name[k] = v
418 } else if p.incompleteTypedef(v.Type) {
419
420 } else if _, ok := nameToC[k]; ok {
421
422
423
424 } else if !reflect.DeepEqual(p.Name[k], v) {
425 error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k))
426 }
427 }
428 }
429
430 if f.ExpFunc != nil {
431 p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
432 p.Preamble += "\n" + f.Preamble
433 }
434 p.Decl = append(p.Decl, f.AST.Decls...)
435 }
436
437
438
439 func (p *Package) incompleteTypedef(t *Type) bool {
440 return t == nil || (t.Size == 0 && t.Align == -1)
441 }
442
View as plain text