.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / go / internal / cgo / cgo.go
1 // Copyright 2013 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
5 // Package cgo handles cgo preprocessing of files containing `import "C"`.
6 //
7 // DESIGN
8 //
9 // The approach taken is to run the cgo processor on the package's
10 // CgoFiles and parse the output, faking the filenames of the
11 // resulting ASTs so that the synthetic file containing the C types is
12 // called "C" (e.g. "~/go/src/net/C") and the preprocessed files
13 // have their original names (e.g. "~/go/src/net/cgo_unix.go"),
14 // not the names of the actual temporary files.
15 //
16 // The advantage of this approach is its fidelity to 'go build'.  The
17 // downside is that the token.Position.Offset for each AST node is
18 // incorrect, being an offset within the temporary file.  Line numbers
19 // should still be correct because of the //line comments.
20 //
21 // The logic of this file is mostly plundered from the 'go build'
22 // tool, which also invokes the cgo preprocessor.
23 //
24 //
25 // REJECTED ALTERNATIVE
26 //
27 // An alternative approach that we explored is to extend go/types'
28 // Importer mechanism to provide the identity of the importing package
29 // so that each time `import "C"` appears it resolves to a different
30 // synthetic package containing just the objects needed in that case.
31 // The loader would invoke cgo but parse only the cgo_types.go file
32 // defining the package-level objects, discarding the other files
33 // resulting from preprocessing.
34 //
35 // The benefit of this approach would have been that source-level
36 // syntax information would correspond exactly to the original cgo
37 // file, with no preprocessing involved, making source tools like
38 // godoc, guru, and eg happy.  However, the approach was rejected
39 // due to the additional complexity it would impose on go/types.  (It
40 // made for a beautiful demo, though.)
41 //
42 // cgo files, despite their *.go extension, are not legal Go source
43 // files per the specification since they may refer to unexported
44 // members of package "C" such as C.int.  Also, a function such as
45 // C.getpwent has in effect two types, one matching its C type and one
46 // which additionally returns (errno C.int).  The cgo preprocessor
47 // uses name mangling to distinguish these two functions in the
48 // processed code, but go/types would need to duplicate this logic in
49 // its handling of function calls, analogous to the treatment of map
50 // lookups in which y=m[k] and y,ok=m[k] are both legal.
51
52 package cgo
53
54 import (
55         "fmt"
56         "go/ast"
57         "go/build"
58         "go/parser"
59         "go/token"
60         "io/ioutil"
61         "log"
62         "os"
63         "path/filepath"
64         "regexp"
65         "strings"
66
67         exec "golang.org/x/sys/execabs"
68 )
69
70 // ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses
71 // the output and returns the resulting ASTs.
72 //
73 func ProcessFiles(bp *build.Package, fset *token.FileSet, DisplayPath func(path string) string, mode parser.Mode) ([]*ast.File, error) {
74         tmpdir, err := ioutil.TempDir("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C")
75         if err != nil {
76                 return nil, err
77         }
78         defer os.RemoveAll(tmpdir)
79
80         pkgdir := bp.Dir
81         if DisplayPath != nil {
82                 pkgdir = DisplayPath(pkgdir)
83         }
84
85         cgoFiles, cgoDisplayFiles, err := Run(bp, pkgdir, tmpdir, false)
86         if err != nil {
87                 return nil, err
88         }
89         var files []*ast.File
90         for i := range cgoFiles {
91                 rd, err := os.Open(cgoFiles[i])
92                 if err != nil {
93                         return nil, err
94                 }
95                 display := filepath.Join(bp.Dir, cgoDisplayFiles[i])
96                 f, err := parser.ParseFile(fset, display, rd, mode)
97                 rd.Close()
98                 if err != nil {
99                         return nil, err
100                 }
101                 files = append(files, f)
102         }
103         return files, nil
104 }
105
106 var cgoRe = regexp.MustCompile(`[/\\:]`)
107
108 // Run invokes the cgo preprocessor on bp.CgoFiles and returns two
109 // lists of files: the resulting processed files (in temporary
110 // directory tmpdir) and the corresponding names of the unprocessed files.
111 //
112 // Run is adapted from (*builder).cgo in
113 // $GOROOT/src/cmd/go/build.go, but these features are unsupported:
114 // Objective C, CGOPKGPATH, CGO_FLAGS.
115 //
116 // If useabs is set to true, absolute paths of the bp.CgoFiles will be passed in
117 // to the cgo preprocessor. This in turn will set the // line comments
118 // referring to those files to use absolute paths. This is needed for
119 // go/packages using the legacy go list support so it is able to find
120 // the original files.
121 func Run(bp *build.Package, pkgdir, tmpdir string, useabs bool) (files, displayFiles []string, err error) {
122         cgoCPPFLAGS, _, _, _ := cflags(bp, true)
123         _, cgoexeCFLAGS, _, _ := cflags(bp, false)
124
125         if len(bp.CgoPkgConfig) > 0 {
126                 pcCFLAGS, err := pkgConfigFlags(bp)
127                 if err != nil {
128                         return nil, nil, err
129                 }
130                 cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
131         }
132
133         // Allows including _cgo_export.h from .[ch] files in the package.
134         cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", tmpdir)
135
136         // _cgo_gotypes.go (displayed "C") contains the type definitions.
137         files = append(files, filepath.Join(tmpdir, "_cgo_gotypes.go"))
138         displayFiles = append(displayFiles, "C")
139         for _, fn := range bp.CgoFiles {
140                 // "foo.cgo1.go" (displayed "foo.go") is the processed Go source.
141                 f := cgoRe.ReplaceAllString(fn[:len(fn)-len("go")], "_")
142                 files = append(files, filepath.Join(tmpdir, f+"cgo1.go"))
143                 displayFiles = append(displayFiles, fn)
144         }
145
146         var cgoflags []string
147         if bp.Goroot && bp.ImportPath == "runtime/cgo" {
148                 cgoflags = append(cgoflags, "-import_runtime_cgo=false")
149         }
150         if bp.Goroot && bp.ImportPath == "runtime/race" || bp.ImportPath == "runtime/cgo" {
151                 cgoflags = append(cgoflags, "-import_syscall=false")
152         }
153
154         var cgoFiles []string = bp.CgoFiles
155         if useabs {
156                 cgoFiles = make([]string, len(bp.CgoFiles))
157                 for i := range cgoFiles {
158                         cgoFiles[i] = filepath.Join(pkgdir, bp.CgoFiles[i])
159                 }
160         }
161
162         args := stringList(
163                 "go", "tool", "cgo", "-srcdir", pkgdir, "-objdir", tmpdir, cgoflags, "--",
164                 cgoCPPFLAGS, cgoexeCFLAGS, cgoFiles,
165         )
166         if false {
167                 log.Printf("Running cgo for package %q: %s", bp.ImportPath, args)
168         }
169         cmd := exec.Command(args[0], args[1:]...)
170         cmd.Stdout = os.Stderr
171         cmd.Stderr = os.Stderr
172         if err := cmd.Run(); err != nil {
173                 return nil, nil, fmt.Errorf("cgo failed: %s: %s", args, err)
174         }
175
176         return files, displayFiles, nil
177 }
178
179 // -- unmodified from 'go build' ---------------------------------------
180
181 // Return the flags to use when invoking the C or C++ compilers, or cgo.
182 func cflags(p *build.Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
183         var defaults string
184         if def {
185                 defaults = "-g -O2"
186         }
187
188         cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
189         cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
190         cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
191         ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
192         return
193 }
194
195 // envList returns the value of the given environment variable broken
196 // into fields, using the default value when the variable is empty.
197 func envList(key, def string) []string {
198         v := os.Getenv(key)
199         if v == "" {
200                 v = def
201         }
202         return strings.Fields(v)
203 }
204
205 // stringList's arguments should be a sequence of string or []string values.
206 // stringList flattens them into a single []string.
207 func stringList(args ...interface{}) []string {
208         var x []string
209         for _, arg := range args {
210                 switch arg := arg.(type) {
211                 case []string:
212                         x = append(x, arg...)
213                 case string:
214                         x = append(x, arg)
215                 default:
216                         panic("stringList: invalid argument")
217                 }
218         }
219         return x
220 }