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.
5 // Cgo; see doc.go for an overview.
8 // Emit correct line number annotations.
9 // Make gc understand the annotations.
34 // A Package collects information about the package we're going to write.
36 PackageName
string // name of package
42 CgoFlags
map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
43 Written
map[string]bool
44 Name
map[string]*Name
// accumulated Name from Files
45 ExpFunc
[]*ExpFunc
// accumulated ExpFunc from Files
47 GoFiles
[]string // list of Go files
48 GccFiles
[]string // list of gcc output files
49 Preamble
string // collected preamble for _cgo_export.h
50 typedefs
map[string]bool // type names that appear in the types of the objects we're interested in
51 typedefList
[]typedefInfo
54 // A typedefInfo is an element on Package.typedefList: a typedef name
55 // and the position where it was required.
56 type typedefInfo
struct {
61 // A File collects information about a single Go input file.
63 AST
*ast
.File
// parsed AST
64 Comments
[]*ast
.CommentGroup
// comments from file
65 Package
string // Package name
66 Preamble
string // C preamble (doc comment on import "C")
67 Ref
[]*Ref
// all references to C.xxx in AST
68 Calls
[]*Call
// all calls to C.xxx in AST
69 ExpFunc
[]*ExpFunc
// exported functions for this file
70 Name
map[string]*Name
// map from Go name to Name
71 NamePos
map[*Name
]token
.Pos
// map from Name to position of the first reference
75 func (f
*File
) offset(p token
.Pos
) int {
76 return fset
.Position(p
).Offset
79 func nameKeys(m
map[string]*Name
) []string {
88 // A Call refers to a call of a C.xxx function in the AST.
95 // A Ref refers to an expression of the form C.xxx in the AST.
103 func (r
*Ref
) Pos() token
.Pos
{
104 return (*r
.Expr
).Pos()
107 var nameKinds
= []string{"iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"}
109 // A Name collects information about C.xxx.
111 Go
string // name used in Go referring to package C
112 Mangle
string // name used in generated Go
113 C
string // name used in C
114 Define
string // #define expansion
115 Kind
string // one of the nameKinds
116 Type
*Type
// the type of xxx
119 Const
string // constant definition
122 // IsVar reports whether Kind is either "var" or "fpvar"
123 func (n
*Name
) IsVar() bool {
124 return n
.Kind
== "var" || n
.Kind
== "fpvar"
127 // IsConst reports whether Kind is either "iconst", "fconst" or "sconst"
128 func (n
*Name
) IsConst() bool {
129 return strings
.HasSuffix(n
.Kind
, "const")
132 // An ExpFunc is an exported function, callable from C.
133 // Such functions are identified in the Go input file
134 // by doc comments containing the line //export ExpName
135 type ExpFunc
struct {
137 ExpName
string // name to use from C
141 // A TypeRepr contains the string representation of a type.
142 type TypeRepr
struct {
144 FormatArgs
[]interface{}
147 // A Type collects information about a type in both the C and Go worlds.
153 EnumValues
map[string]int64
155 BadPointer
bool // this pointer type should be represented as a uintptr (deprecated)
158 // A FuncType collects information about a function type in both the C and Go worlds.
159 type FuncType
struct {
166 fmt
.Fprint(os
.Stderr
, "usage: cgo -- [compiler options] file.go ...\n")
171 var ptrSizeMap
= map[string]int64{
198 var intSizeMap
= map[string]int64{
227 var fset
= token
.NewFileSet()
229 var dynobj
= flag
.String("dynimport", "", "if non-empty, print dynamic import data for that file")
230 var dynout
= flag
.String("dynout", "", "write -dynimport output to this file")
231 var dynpackage
= flag
.String("dynpackage", "main", "set Go package for -dynimport output")
232 var dynlinker
= flag
.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
234 // This flag is for bootstrapping a new Go implementation,
235 // to generate Go types that match the data layout and
236 // constant values used in the host's C libraries and system calls.
237 var godefs
= flag
.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
239 var srcDir
= flag
.String("srcdir", "", "source directory")
240 var objDir
= flag
.String("objdir", "", "object directory")
241 var importPath
= flag
.String("importpath", "", "import path of package being built (for comments in generated files)")
242 var exportHeader
= flag
.String("exportheader", "", "where to write export header if any exported functions")
244 var gccgo
= flag
.Bool("gccgo", false, "generate files for use with gccgo")
245 var gccgoprefix
= flag
.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
246 var gccgopkgpath
= flag
.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
247 var gccgoMangler
func(string) string
248 var importRuntimeCgo
= flag
.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
249 var importSyscall
= flag
.Bool("import_syscall", true, "import syscall in generated code")
250 var trimpath
= flag
.String("trimpath", "", "applies supplied rewrites or trims prefixes to recorded source file paths")
252 var goarch
, goos
, gomips
, gomips64
string
253 var gccBaseCmd
[]string
256 objabi
.AddVersionFlag() // -V
261 // cgo -dynimport is essentially a separate helper command
262 // built into the cgo binary. It scans a gcc-produced executable
263 // and dumps information about the imported symbols and the
264 // imported libraries. The 'go build' rules for cgo prepare an
265 // appropriate executable and then use its import information
266 // instead of needing to make the linkers duplicate all the
267 // specialized knowledge gcc has about where to look for imported
268 // symbols and which ones to use.
274 // Generating definitions pulled from header files,
275 // to be checked into Go repositories.
276 // Line numbers are just noise.
277 conf
.Mode
&^= printer
.SourcePos
285 // Find first arg that looks like a go file and assume everything before
286 // that are options to pass to gcc.
288 for i
= len(args
); i
> 0; i
-- {
289 if !strings
.HasSuffix(args
[i
-1], ".go") {
299 for _
, arg
:= range args
[:i
] {
300 if arg
== "-fsanitize=thread" {
301 tsanProlog
= yesTsanProlog
303 if arg
== "-fsanitize=memory" {
304 msanProlog
= yesMsanProlog
308 p
:= newPackage(args
[:i
])
310 // We need a C compiler to be available. Check this.
312 gccBaseCmd
, err
= checkGCCBaseCmd()
318 // Record CGO_LDFLAGS from the environment for external linking.
319 if ldflags
:= os
.Getenv("CGO_LDFLAGS"); ldflags
!= "" {
320 args
, err
:= splitQuoted(ldflags
)
322 fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags
, err
)
324 p
.addToFlag("LDFLAGS", args
)
327 // Need a unique prefix for the global C symbols that
328 // we use to coordinate between gcc and ourselves.
329 // We already put _cgo_ at the beginning, so the main
330 // concern is other cgo wrappers for the same functions.
331 // Use the beginning of the md5 of the input to disambiguate.
333 io
.WriteString(h
, *importPath
)
334 fs
:= make([]*File
, len(goFiles
))
335 for i
, input
:= range goFiles
{
337 input
= filepath
.Join(*srcDir
, input
)
340 // Create absolute path for file, so that it will be used in error
341 // messages and recorded in debug line number information.
342 // This matches the rest of the toolchain. See golang.org/issue/5122.
343 if aname
, err
:= filepath
.Abs(input
); err
== nil {
347 b
, err
:= ioutil
.ReadFile(input
)
351 if _
, err
= h
.Write(b
); err
!= nil {
355 // Apply trimpath to the file path. The path won't be read from after this point.
356 input
, _
= objabi
.ApplyRewrites(input
, *trimpath
)
360 f
.Edit
= edit
.NewBuffer(b
)
362 f
.DiscardCgoDirectives()
366 cPrefix
= fmt
.Sprintf("_%x", h
.Sum(nil)[0:6])
369 // make sure that _obj directory exists, so that we can write
370 // all the output files there.
371 os
.Mkdir("_obj", 0777)
374 *objDir
+= string(filepath
.Separator
)
376 for i
, input
:= range goFiles
{
379 for _
, cref
:= range f
.Ref
{
380 switch cref
.Context
{
381 case ctxCall
, ctxCall2
:
382 if cref
.Name
.Kind
!= "type" {
386 *cref
.Expr
= cref
.Name
.Type
.Go
387 f
.Edit
.Replace(f
.offset(old
.Pos()), f
.offset(old
.End()), gofmt(cref
.Name
.Type
.Go
))
393 p
.PackagePath
= f
.Package
396 os
.Stdout
.WriteString(p
.godefs(f
))
398 p
.writeOutput(f
, input
)
410 // newPackage returns a new Package that will invoke
411 // gcc with the additional arguments specified in args.
412 func newPackage(args
[]string) *Package
{
413 goarch
= runtime
.GOARCH
414 if s
:= os
.Getenv("GOARCH"); s
!= "" {
418 if s
:= os
.Getenv("GOOS"); s
!= "" {
422 gomips
= buildcfg
.GOMIPS
423 gomips64
= buildcfg
.GOMIPS64
424 ptrSize
:= ptrSizeMap
[goarch
]
426 fatalf("unknown ptrSize for $GOARCH %q", goarch
)
428 intSize
:= intSizeMap
[goarch
]
430 fatalf("unknown intSize for $GOARCH %q", goarch
)
433 // Reset locale variables so gcc emits English errors [sic].
434 os
.Setenv("LANG", "en_US.UTF-8")
435 os
.Setenv("LC_ALL", "C")
440 CgoFlags
: make(map[string][]string),
441 Written
: make(map[string]bool),
443 p
.addToFlag("CFLAGS", args
)
447 // Record what needs to be recorded about f.
448 func (p
*Package
) Record(f
*File
) {
449 if p
.PackageName
== "" {
450 p
.PackageName
= f
.Package
451 } else if p
.PackageName
!= f
.Package
{
452 error_(token
.NoPos
, "inconsistent package names: %s, %s", p
.PackageName
, f
.Package
)
458 for k
, v
:= range f
.Name
{
459 if p
.Name
[k
] == nil {
461 } else if p
.incompleteTypedef(p
.Name
[k
].Type
) {
463 } else if p
.incompleteTypedef(v
.Type
) {
465 } else if _
, ok
:= nameToC
[k
]; ok
{
466 // Names we predefine may appear inconsistent
467 // if some files typedef them and some don't.
469 } else if !reflect
.DeepEqual(p
.Name
[k
], v
) {
470 error_(token
.NoPos
, "inconsistent definitions for C.%s", fixGo(k
))
475 if f
.ExpFunc
!= nil {
476 p
.ExpFunc
= append(p
.ExpFunc
, f
.ExpFunc
...)
477 p
.Preamble
+= "\n" + f
.Preamble
479 p
.Decl
= append(p
.Decl
, f
.AST
.Decls
...)
482 // incompleteTypedef reports whether t appears to be an incomplete
483 // typedef definition.
484 func (p
*Package
) incompleteTypedef(t
*Type
) bool {
485 return t
== nil ||
(t
.Size
== 0 && t
.Align
== -1)