@@ -32,19 +32,23 @@ type cgoPackage struct {
3232 errors []error
3333 currentDir string // current working directory
3434 packageDir string // full path to the package to process
35+ importPath string
3536 fset * token.FileSet
3637 tokenFiles map [string ]* token.File
3738 definedGlobally map [string ]ast.Node
3839 anonDecls map [interface {}]string
3940 cflags []string // CFlags from #cgo lines
4041 ldflags []string // LDFlags from #cgo lines
4142 visitedFiles map [string ][]byte
43+ cgoHeaders []string
4244}
4345
4446// cgoFile holds information only for a single Go file (with one or more
4547// `import "C"` statements).
4648type cgoFile struct {
4749 * cgoPackage
50+ file * ast.File
51+ index int
4852 defined map [string ]ast.Node
4953 names map [string ]clangCursor
5054}
@@ -158,9 +162,10 @@ func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
158162// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
159163// hashes of the accessed C header files. If there is one or more error, it
160164// returns these in the []error slice but still modifies the AST.
161- func Process (files []* ast.File , dir string , fset * token.FileSet , cflags []string , clangHeaders string ) (* ast.File , []string , []string , []string , map [string ][]byte , []error ) {
165+ func Process (files []* ast.File , dir , importPath string , fset * token.FileSet , cflags []string , clangHeaders string ) (* ast.File , []string , []string , []string , map [string ][]byte , []error ) {
162166 p := & cgoPackage {
163167 currentDir : dir ,
168+ importPath : importPath ,
164169 fset : fset ,
165170 tokenFiles : map [string ]* token.File {},
166171 definedGlobally : map [string ]ast.Node {},
@@ -210,13 +215,13 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
210215 }
211216 }
212217 // Patch some types, for example *C.char in C.CString.
213- cf := p .newCGoFile ()
218+ cf := p .newCGoFile (nil , - 1 )
214219 astutil .Apply (p .generated , func (cursor * astutil.Cursor ) bool {
215220 return cf .walker (cursor , nil )
216221 }, nil )
217222
218223 // Find `import "C"` C fragments in the file.
219- cgoHeaders : = make ([]string , len (files )) // combined CGo header fragment for each file
224+ p . cgoHeaders = make ([]string , len (files )) // combined CGo header fragment for each file
220225 for i , f := range files {
221226 var cgoHeader string
222227 for i := 0 ; i < len (f .Decls ); i ++ {
@@ -275,7 +280,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
275280 cgoHeader += fragment
276281 }
277282
278- cgoHeaders [i ] = cgoHeader
283+ p . cgoHeaders [i ] = cgoHeader
279284 }
280285
281286 // Define CFlags that will be used while parsing the package.
@@ -289,7 +294,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
289294 }
290295
291296 // Retrieve types such as C.int, C.longlong, etc from C.
292- p .newCGoFile ().readNames (builtinAliasTypedefs , cflagsForCGo , "" , func (names map [string ]clangCursor ) {
297+ p .newCGoFile (nil , - 1 ).readNames (builtinAliasTypedefs , cflagsForCGo , "" , func (names map [string ]clangCursor ) {
293298 gen := & ast.GenDecl {
294299 TokPos : token .NoPos ,
295300 Tok : token .TYPE ,
@@ -303,8 +308,8 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
303308
304309 // Process CGo imports for each file.
305310 for i , f := range files {
306- cf := p .newCGoFile ()
307- cf .readNames (cgoHeaders [i ], cflagsForCGo , filepath .Base (fset .File (f .Pos ()).Name ()), func (names map [string ]clangCursor ) {
311+ cf := p .newCGoFile (f , i )
312+ cf .readNames (p . cgoHeaders [i ], cflagsForCGo , filepath .Base (fset .File (f .Pos ()).Name ()), func (names map [string ]clangCursor ) {
308313 for _ , name := range builtinAliases {
309314 // Names such as C.int should not be obtained from C.
310315 // This works around an issue in picolibc that has `#define int`
@@ -320,12 +325,14 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
320325 // Print the newly generated in-memory AST, for debugging.
321326 //ast.Print(fset, p.generated)
322327
323- return p .generated , cgoHeaders , p .cflags , p .ldflags , p .visitedFiles , p .errors
328+ return p .generated , p . cgoHeaders , p .cflags , p .ldflags , p .visitedFiles , p .errors
324329}
325330
326- func (p * cgoPackage ) newCGoFile () * cgoFile {
331+ func (p * cgoPackage ) newCGoFile (file * ast. File , index int ) * cgoFile {
327332 return & cgoFile {
328333 cgoPackage : p ,
334+ file : file ,
335+ index : index ,
329336 defined : make (map [string ]ast.Node ),
330337 names : make (map [string ]clangCursor ),
331338 }
@@ -1117,8 +1124,11 @@ func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) st
11171124 return alias
11181125 }
11191126 node := f .getASTDeclNode (name , found , iscall )
1120- if _ , ok := node .(* ast.FuncDecl ); ok && ! iscall {
1121- return "C." + name + "$funcaddr"
1127+ if node , ok := node .(* ast.FuncDecl ); ok {
1128+ if ! iscall {
1129+ return node .Name .Name + "$funcaddr"
1130+ }
1131+ return node .Name .Name
11221132 }
11231133 return "C." + name
11241134}
@@ -1142,7 +1152,7 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
11421152 // Original cgo reports an error like
11431153 // cgo: inconsistent definitions for C.myint
11441154 // which is far less helpful.
1145- f .addError (getPos (node ), " defined previously at "+ f .fset .Position (getPos (newNode )).String ()+ " with a different type" )
1155+ f .addError (getPos (node ), name + " defined previously at "+ f .fset .Position (getPos (newNode )).String ()+ " with a different type" )
11461156 }
11471157 f .defined [name ] = node
11481158 return node
@@ -1152,17 +1162,33 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
11521162 f .defined [name ] = nil
11531163 node , elaboratedType := f .createASTNode (name , found )
11541164 f .defined [name ] = node
1155- f .definedGlobally [name ] = node
11561165 switch node := node .(type ) {
11571166 case * ast.FuncDecl :
1167+ if strings .HasPrefix (node .Doc .List [0 ].Text , "//export _Cgo_static_" ) {
1168+ // Static function. Only accessible in the current Go file.
1169+ globalName := strings .TrimPrefix (node .Doc .List [0 ].Text , "//export " )
1170+ aliasDeclaration := fmt .Sprintf (`
1171+ #ifdef __APPLE__
1172+ __asm__(".globl __%s");
1173+ __asm__(".set __%s, _%s");
1174+ extern __typeof(%s) %s;
1175+ #else
1176+ extern __typeof(%s) %s __attribute__((alias(%#v)));
1177+ #endif
1178+ ` , globalName , globalName , name , name , globalName , name , globalName , name )
1179+ f .cgoHeaders [f .index ] += "\n \n " + aliasDeclaration
1180+ } else {
1181+ // Regular (non-static) function.
1182+ f .definedGlobally [name ] = node
1183+ }
11581184 f .generated .Decls = append (f .generated .Decls , node )
11591185 // Also add a declaration like the following:
11601186 // var C.foo$funcaddr unsafe.Pointer
11611187 f .generated .Decls = append (f .generated .Decls , & ast.GenDecl {
11621188 Tok : token .VAR ,
11631189 Specs : []ast.Spec {
11641190 & ast.ValueSpec {
1165- Names : []* ast.Ident {{Name : "C." + name + "$funcaddr" }},
1191+ Names : []* ast.Ident {{Name : node . Name . Name + "$funcaddr" }},
11661192 Type : & ast.SelectorExpr {
11671193 X : & ast.Ident {Name : "unsafe" },
11681194 Sel : & ast.Ident {Name : "Pointer" },
@@ -1171,8 +1197,10 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
11711197 },
11721198 })
11731199 case * ast.GenDecl :
1200+ f .definedGlobally [name ] = node
11741201 f .generated .Decls = append (f .generated .Decls , node )
11751202 case * ast.TypeSpec :
1203+ f .definedGlobally [name ] = node
11761204 f .generated .Decls = append (f .generated .Decls , & ast.GenDecl {
11771205 Tok : token .TYPE ,
11781206 Specs : []ast.Spec {node },
0 commit comments