Scott Baker | f579f13 | 2019-10-24 14:31:41 -0700 | [diff] [blame] | 1 | // Copyright 2016 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 | // +build ignore |
| 6 | |
| 7 | // mkpost processes the output of cgo -godefs to |
| 8 | // modify the generated types. It is used to clean up |
| 9 | // the sys API in an architecture specific manner. |
| 10 | // |
| 11 | // mkpost is run after cgo -godefs; see README.md. |
| 12 | package main |
| 13 | |
| 14 | import ( |
| 15 | "bytes" |
| 16 | "fmt" |
| 17 | "go/format" |
| 18 | "io/ioutil" |
| 19 | "log" |
| 20 | "os" |
| 21 | "regexp" |
| 22 | ) |
| 23 | |
| 24 | func main() { |
| 25 | // Get the OS and architecture (using GOARCH_TARGET if it exists) |
| 26 | goos := os.Getenv("GOOS") |
| 27 | goarch := os.Getenv("GOARCH_TARGET") |
| 28 | if goarch == "" { |
| 29 | goarch = os.Getenv("GOARCH") |
| 30 | } |
| 31 | // Check that we are using the Docker-based build system if we should be. |
| 32 | if goos == "linux" { |
| 33 | if os.Getenv("GOLANG_SYS_BUILD") != "docker" { |
| 34 | os.Stderr.WriteString("In the Docker-based build system, mkpost should not be called directly.\n") |
| 35 | os.Stderr.WriteString("See README.md\n") |
| 36 | os.Exit(1) |
| 37 | } |
| 38 | } |
| 39 | |
| 40 | b, err := ioutil.ReadAll(os.Stdin) |
| 41 | if err != nil { |
| 42 | log.Fatal(err) |
| 43 | } |
| 44 | |
| 45 | if goos == "aix" { |
| 46 | // Replace type of Atim, Mtim and Ctim by Timespec in Stat_t |
| 47 | // to avoid having both StTimespec and Timespec. |
| 48 | sttimespec := regexp.MustCompile(`_Ctype_struct_st_timespec`) |
| 49 | b = sttimespec.ReplaceAll(b, []byte("Timespec")) |
| 50 | } |
| 51 | |
| 52 | // Intentionally export __val fields in Fsid and Sigset_t |
| 53 | valRegex := regexp.MustCompile(`type (Fsid|Sigset_t) struct {(\s+)X__(bits|val)(\s+\S+\s+)}`) |
| 54 | b = valRegex.ReplaceAll(b, []byte("type $1 struct {${2}Val$4}")) |
| 55 | |
| 56 | // Intentionally export __fds_bits field in FdSet |
| 57 | fdSetRegex := regexp.MustCompile(`type (FdSet) struct {(\s+)X__fds_bits(\s+\S+\s+)}`) |
| 58 | b = fdSetRegex.ReplaceAll(b, []byte("type $1 struct {${2}Bits$3}")) |
| 59 | |
| 60 | // If we have empty Ptrace structs, we should delete them. Only s390x emits |
| 61 | // nonempty Ptrace structs. |
| 62 | ptraceRexexp := regexp.MustCompile(`type Ptrace((Psw|Fpregs|Per) struct {\s*})`) |
| 63 | b = ptraceRexexp.ReplaceAll(b, nil) |
| 64 | |
| 65 | // Replace the control_regs union with a blank identifier for now. |
| 66 | controlRegsRegex := regexp.MustCompile(`(Control_regs)\s+\[0\]uint64`) |
| 67 | b = controlRegsRegex.ReplaceAll(b, []byte("_ [0]uint64")) |
| 68 | |
| 69 | // Remove fields that are added by glibc |
| 70 | // Note that this is unstable as the identifers are private. |
| 71 | removeFieldsRegex := regexp.MustCompile(`X__glibc\S*`) |
| 72 | b = removeFieldsRegex.ReplaceAll(b, []byte("_")) |
| 73 | |
| 74 | // Convert [65]int8 to [65]byte in Utsname members to simplify |
| 75 | // conversion to string; see golang.org/issue/20753 |
| 76 | convertUtsnameRegex := regexp.MustCompile(`((Sys|Node|Domain)name|Release|Version|Machine)(\s+)\[(\d+)\]u?int8`) |
| 77 | b = convertUtsnameRegex.ReplaceAll(b, []byte("$1$3[$4]byte")) |
| 78 | |
| 79 | // Convert [1024]int8 to [1024]byte in Ptmget members |
| 80 | convertPtmget := regexp.MustCompile(`([SC]n)(\s+)\[(\d+)\]u?int8`) |
| 81 | b = convertPtmget.ReplaceAll(b, []byte("$1[$3]byte")) |
| 82 | |
| 83 | // Remove spare fields (e.g. in Statx_t) |
| 84 | spareFieldsRegex := regexp.MustCompile(`X__spare\S*`) |
| 85 | b = spareFieldsRegex.ReplaceAll(b, []byte("_")) |
| 86 | |
| 87 | // Remove cgo padding fields |
| 88 | removePaddingFieldsRegex := regexp.MustCompile(`Pad_cgo_\d+`) |
| 89 | b = removePaddingFieldsRegex.ReplaceAll(b, []byte("_")) |
| 90 | |
| 91 | // Remove padding, hidden, or unused fields |
| 92 | removeFieldsRegex = regexp.MustCompile(`\b(X_\S+|Padding)`) |
| 93 | b = removeFieldsRegex.ReplaceAll(b, []byte("_")) |
| 94 | |
| 95 | // Remove the first line of warning from cgo |
| 96 | b = b[bytes.IndexByte(b, '\n')+1:] |
| 97 | // Modify the command in the header to include: |
| 98 | // mkpost, our own warning, and a build tag. |
| 99 | replacement := fmt.Sprintf(`$1 | go run mkpost.go |
| 100 | // Code generated by the command above; see README.md. DO NOT EDIT. |
| 101 | |
| 102 | // +build %s,%s`, goarch, goos) |
| 103 | cgoCommandRegex := regexp.MustCompile(`(cgo -godefs .*)`) |
| 104 | b = cgoCommandRegex.ReplaceAll(b, []byte(replacement)) |
| 105 | |
| 106 | // Rename Stat_t time fields |
| 107 | if goos == "freebsd" && goarch == "386" { |
| 108 | // Hide Stat_t.[AMCB]tim_ext fields |
| 109 | renameStatTimeExtFieldsRegex := regexp.MustCompile(`[AMCB]tim_ext`) |
| 110 | b = renameStatTimeExtFieldsRegex.ReplaceAll(b, []byte("_")) |
| 111 | } |
| 112 | renameStatTimeFieldsRegex := regexp.MustCompile(`([AMCB])(?:irth)?time?(?:spec)?\s+(Timespec|StTimespec)`) |
| 113 | b = renameStatTimeFieldsRegex.ReplaceAll(b, []byte("${1}tim ${2}")) |
| 114 | |
| 115 | // gofmt |
| 116 | b, err = format.Source(b) |
| 117 | if err != nil { |
| 118 | log.Fatal(err) |
| 119 | } |
| 120 | |
| 121 | os.Stdout.Write(b) |
| 122 | } |