github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/internal/imports/mkstdlib.go (about) 1 // Copyright 2019 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 //go:build ignore 6 // +build ignore 7 8 // mkstdlib generates the zstdlib.go file, containing the Go standard 9 // library API symbols. It's baked into the binary to avoid scanning 10 // GOPATH in the common case. 11 package main 12 13 import ( 14 "bufio" 15 "bytes" 16 "fmt" 17 "go/format" 18 "go/token" 19 "io" 20 "io/ioutil" 21 "log" 22 "os" 23 "path/filepath" 24 "regexp" 25 "runtime" 26 "sort" 27 "strings" 28 29 "golang.org/x/tools/go/packages" 30 ) 31 32 func mustOpen(name string) io.Reader { 33 f, err := os.Open(name) 34 if err != nil { 35 log.Fatal(err) 36 } 37 return f 38 } 39 40 func api(base string) string { 41 return filepath.Join(runtime.GOROOT(), "api", base) 42 } 43 44 var sym = regexp.MustCompile(`^pkg (\S+).*?, (?:var|func|type|const) ([A-Z]\w*)`) 45 46 func main() { 47 var buf bytes.Buffer 48 outf := func(format string, args ...interface{}) { 49 fmt.Fprintf(&buf, format, args...) 50 } 51 outf(`// Copyright 2022 The Go Authors. All rights reserved. 52 // Use of this source code is governed by a BSD-style 53 // license that can be found in the LICENSE file. 54 55 `) 56 outf("// Code generated by mkstdlib.go. DO NOT EDIT.\n\n") 57 outf("package imports\n") 58 outf("var stdlib = map[string][]string{\n") 59 f := readAPI() 60 sc := bufio.NewScanner(f) 61 62 // The APIs of the syscall/js and unsafe packages need to be computed explicitly, 63 // because they're not included in the GOROOT/api/go1.*.txt files at this time. 64 pkgs := map[string]map[string]bool{ 65 "syscall/js": syms("syscall/js", "GOOS=js", "GOARCH=wasm"), 66 "unsafe": syms("unsafe"), 67 } 68 paths := []string{"syscall/js", "unsafe"} 69 70 for sc.Scan() { 71 l := sc.Text() 72 if m := sym.FindStringSubmatch(l); m != nil { 73 path, sym := m[1], m[2] 74 75 if _, ok := pkgs[path]; !ok { 76 pkgs[path] = map[string]bool{} 77 paths = append(paths, path) 78 } 79 pkgs[path][sym] = true 80 } 81 } 82 if err := sc.Err(); err != nil { 83 log.Fatal(err) 84 } 85 sort.Strings(paths) 86 for _, path := range paths { 87 outf("\t%q: {\n", path) 88 pkg := pkgs[path] 89 var syms []string 90 for sym := range pkg { 91 syms = append(syms, sym) 92 } 93 sort.Strings(syms) 94 for _, sym := range syms { 95 outf("\t\t%q,\n", sym) 96 } 97 outf("},\n") 98 } 99 outf("}\n") 100 fmtbuf, err := format.Source(buf.Bytes()) 101 if err != nil { 102 log.Fatal(err) 103 } 104 err = ioutil.WriteFile("zstdlib.go", fmtbuf, 0666) 105 if err != nil { 106 log.Fatal(err) 107 } 108 } 109 110 // readAPI opens an io.Reader that reads all stdlib API content. 111 func readAPI() io.Reader { 112 entries, err := os.ReadDir(filepath.Join(runtime.GOROOT(), "api")) 113 if err != nil { 114 log.Fatal(err) 115 } 116 var readers []io.Reader 117 for _, entry := range entries { 118 name := entry.Name() 119 if strings.HasPrefix(name, "go") && strings.HasSuffix(name, ".txt") { 120 readers = append(readers, mustOpen(api(name))) 121 } 122 } 123 return io.MultiReader(readers...) 124 } 125 126 // syms computes the exported symbols in the specified package. 127 func syms(pkg string, extraEnv ...string) map[string]bool { 128 var env []string 129 if len(extraEnv) != 0 { 130 env = append(os.Environ(), extraEnv...) 131 } 132 pkgs, err := packages.Load(&packages.Config{Mode: packages.NeedTypes, Env: env}, pkg) 133 if err != nil { 134 log.Fatalln(err) 135 } else if len(pkgs) != 1 { 136 log.Fatalf("got %d packages, want one package %q", len(pkgs), pkg) 137 } 138 syms := make(map[string]bool) 139 for _, name := range pkgs[0].Types.Scope().Names() { 140 if token.IsExported(name) { 141 syms[name] = true 142 } 143 } 144 return syms 145 }