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 gmp.go for an overview.
8 // Emit correct line number annotations.
9 // Make gc understand the annotations.
32 // A Package collects information about the package we're going to write.
34 PackageName
string // name of package
40 CgoFlags
map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
41 Written
map[string]bool
42 Name
map[string]*Name
// accumulated Name from Files
43 ExpFunc
[]*ExpFunc
// accumulated ExpFunc from Files
45 GoFiles
[]string // list of Go files
46 GccFiles
[]string // list of gcc output files
47 Preamble
string // collected preamble for _cgo_export.h
50 // A File collects information about a single Go input file.
52 AST
*ast
.File
// parsed AST
53 Comments
[]*ast
.CommentGroup
// comments from file
54 Package
string // Package name
55 Preamble
string // C preamble (doc comment on import "C")
56 Ref
[]*Ref
// all references to C.xxx in AST
57 Calls
[]*Call
// all calls to C.xxx in AST
58 ExpFunc
[]*ExpFunc
// exported functions for this file
59 Name
map[string]*Name
// map from Go name to Name
60 NamePos
map[*Name
]token
.Pos
// map from Name to position of the first reference
64 func (f
*File
) offset(p token
.Pos
) int {
65 return fset
.Position(p
).Offset
68 func nameKeys(m
map[string]*Name
) []string {
77 // A Call refers to a call of a C.xxx function in the AST.
83 // A Ref refers to an expression of the form C.xxx in the AST.
90 func (r
*Ref
) Pos() token
.Pos
{
91 return (*r
.Expr
).Pos()
94 // A Name collects information about C.xxx.
96 Go
string // name used in Go referring to package C
97 Mangle
string // name used in generated Go
98 C
string // name used in C
99 Define
string // #define expansion
100 Kind
string // "iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"
101 Type
*Type
// the type of xxx
104 Const
string // constant definition
107 // IsVar reports whether Kind is either "var" or "fpvar"
108 func (n
*Name
) IsVar() bool {
109 return n
.Kind
== "var" || n
.Kind
== "fpvar"
112 // IsConst reports whether Kind is either "iconst", "fconst" or "sconst"
113 func (n
*Name
) IsConst() bool {
114 return strings
.HasSuffix(n
.Kind
, "const")
117 // An ExpFunc is an exported function, callable from C.
118 // Such functions are identified in the Go input file
119 // by doc comments containing the line //export ExpName
120 type ExpFunc
struct {
122 ExpName
string // name to use from C
126 // A TypeRepr contains the string representation of a type.
127 type TypeRepr
struct {
129 FormatArgs
[]interface{}
132 // A Type collects information about a type in both the C and Go worlds.
138 EnumValues
map[string]int64
142 // A FuncType collects information about a function type in both the C and Go worlds.
143 type FuncType
struct {
150 fmt
.Fprint(os
.Stderr
, "usage: cgo -- [compiler options] file.go ...\n")
155 var ptrSizeMap
= map[string]int64{
179 var intSizeMap
= map[string]int64{
205 var fset
= token
.NewFileSet()
207 var dynobj
= flag
.String("dynimport", "", "if non-empty, print dynamic import data for that file")
208 var dynout
= flag
.String("dynout", "", "write -dynimport output to this file")
209 var dynpackage
= flag
.String("dynpackage", "main", "set Go package for -dynimport output")
210 var dynlinker
= flag
.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
212 // This flag is for bootstrapping a new Go implementation,
213 // to generate Go types that match the data layout and
214 // constant values used in the host's C libraries and system calls.
215 var godefs
= flag
.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
217 var srcDir
= flag
.String("srcdir", "", "source directory")
218 var objDir
= flag
.String("objdir", "", "object directory")
219 var importPath
= flag
.String("importpath", "", "import path of package being built (for comments in generated files)")
220 var exportHeader
= flag
.String("exportheader", "", "where to write export header if any exported functions")
222 var gccgo
= flag
.Bool("gccgo", false, "generate files for use with gccgo")
223 var gccgoprefix
= flag
.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
224 var gccgopkgpath
= flag
.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
225 var importRuntimeCgo
= flag
.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
226 var importSyscall
= flag
.Bool("import_syscall", true, "import syscall in generated code")
227 var goarch
, goos
string
230 objabi
.AddVersionFlag() // -V
235 // cgo -dynimport is essentially a separate helper command
236 // built into the cgo binary. It scans a gcc-produced executable
237 // and dumps information about the imported symbols and the
238 // imported libraries. The 'go build' rules for cgo prepare an
239 // appropriate executable and then use its import information
240 // instead of needing to make the linkers duplicate all the
241 // specialized knowledge gcc has about where to look for imported
242 // symbols and which ones to use.
248 // Generating definitions pulled from header files,
249 // to be checked into Go repositories.
250 // Line numbers are just noise.
251 conf
.Mode
&^= printer
.SourcePos
259 // Find first arg that looks like a go file and assume everything before
260 // that are options to pass to gcc.
262 for i
= len(args
); i
> 0; i
-- {
263 if !strings
.HasSuffix(args
[i
-1], ".go") {
273 for _
, arg
:= range args
[:i
] {
274 if arg
== "-fsanitize=thread" {
275 tsanProlog
= yesTsanProlog
279 p
:= newPackage(args
[:i
])
281 // Record CGO_LDFLAGS from the environment for external linking.
282 if ldflags
:= os
.Getenv("CGO_LDFLAGS"); ldflags
!= "" {
283 args
, err
:= splitQuoted(ldflags
)
285 fatalf("bad CGO_LDFLAGS: %q (%s)", ldflags
, err
)
287 p
.addToFlag("LDFLAGS", args
)
290 // Need a unique prefix for the global C symbols that
291 // we use to coordinate between gcc and ourselves.
292 // We already put _cgo_ at the beginning, so the main
293 // concern is other cgo wrappers for the same functions.
294 // Use the beginning of the md5 of the input to disambiguate.
296 fs
:= make([]*File
, len(goFiles
))
297 for i
, input
:= range goFiles
{
299 input
= filepath
.Join(*srcDir
, input
)
302 b
, err
:= ioutil
.ReadFile(input
)
306 if _
, err
= h
.Write(b
); err
!= nil {
311 f
.Edit
= edit
.NewBuffer(b
)
313 f
.DiscardCgoDirectives()
317 cPrefix
= fmt
.Sprintf("_%x", h
.Sum(nil)[0:6])
320 // make sure that _obj directory exists, so that we can write
321 // all the output files there.
322 os
.Mkdir("_obj", 0777)
325 *objDir
+= string(filepath
.Separator
)
327 for i
, input
:= range goFiles
{
330 for _
, cref
:= range f
.Ref
{
331 switch cref
.Context
{
332 case ctxCall
, ctxCall2
:
333 if cref
.Name
.Kind
!= "type" {
337 *cref
.Expr
= cref
.Name
.Type
.Go
338 f
.Edit
.Replace(f
.offset(old
.Pos()), f
.offset(old
.End()), gofmt(cref
.Name
.Type
.Go
))
344 p
.PackagePath
= f
.Package
347 os
.Stdout
.WriteString(p
.godefs(f
, input
))
349 p
.writeOutput(f
, input
)
361 // newPackage returns a new Package that will invoke
362 // gcc with the additional arguments specified in args.
363 func newPackage(args
[]string) *Package
{
364 goarch
= runtime
.GOARCH
365 if s
:= os
.Getenv("GOARCH"); s
!= "" {
369 if s
:= os
.Getenv("GOOS"); s
!= "" {
372 ptrSize
:= ptrSizeMap
[goarch
]
374 fatalf("unknown ptrSize for $GOARCH %q", goarch
)
376 intSize
:= intSizeMap
[goarch
]
378 fatalf("unknown intSize for $GOARCH %q", goarch
)
381 // Reset locale variables so gcc emits English errors [sic].
382 os
.Setenv("LANG", "en_US.UTF-8")
383 os
.Setenv("LC_ALL", "C")
388 CgoFlags
: make(map[string][]string),
389 Written
: make(map[string]bool),
391 p
.addToFlag("CFLAGS", args
)
395 // Record what needs to be recorded about f.
396 func (p
*Package
) Record(f
*File
) {
397 if p
.PackageName
== "" {
398 p
.PackageName
= f
.Package
399 } else if p
.PackageName
!= f
.Package
{
400 error_(token
.NoPos
, "inconsistent package names: %s, %s", p
.PackageName
, f
.Package
)
406 for k
, v
:= range f
.Name
{
407 if p
.Name
[k
] == nil {
409 } else if !reflect
.DeepEqual(p
.Name
[k
], v
) {
410 error_(token
.NoPos
, "inconsistent definitions for C.%s", fixGo(k
))
415 if f
.ExpFunc
!= nil {
416 p
.ExpFunc
= append(p
.ExpFunc
, f
.ExpFunc
...)
417 p
.Preamble
+= "\n" + f
.Preamble
419 p
.Decl
= append(p
.Decl
, f
.AST
.Decls
...)