OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / sys / unix / linux / mkall.go
1 // Copyright 2017 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 // linux/mkall.go - Generates all Linux zsysnum, zsyscall, zerror, and ztype
6 // files for all 11 linux architectures supported by the go compiler. See
7 // README.md for more information about the build system.
8
9 // To run it you must have a git checkout of the Linux kernel and glibc. Once
10 // the appropriate sources are ready, the program is run as:
11 //     go run linux/mkall.go <linux_dir> <glibc_dir>
12
13 // +build ignore
14
15 package main
16
17 import (
18         "fmt"
19         "os"
20         "os/exec"
21         "path/filepath"
22         "runtime"
23         "strings"
24 )
25
26 // These will be paths to the appropriate source directories.
27 var LinuxDir string
28 var GlibcDir string
29
30 const TempDir = "/tmp"
31 const IncludeDir = TempDir + "/include" // To hold our C headers
32 const BuildDir = TempDir + "/build"     // To hold intermediate build files
33
34 const GOOS = "linux"       // Only for Linux targets
35 const BuildArch = "amd64"  // Must be built on this architecture
36 const MinKernel = "2.6.23" // https://golang.org/doc/install#requirements
37
38 type target struct {
39         GoArch     string // Architecture name according to Go
40         LinuxArch  string // Architecture name according to the Linux Kernel
41         GNUArch    string // Architecture name according to GNU tools (https://wiki.debian.org/Multiarch/Tuples)
42         BigEndian  bool   // Default Little Endian
43         SignedChar bool   // Is -fsigned-char needed (default no)
44         Bits       int
45 }
46
47 // List of the 11 Linux targets supported by the go compiler. sparc64 is not
48 // currently supported, though a port is in progress.
49 var targets = []target{
50         {
51                 GoArch:    "386",
52                 LinuxArch: "x86",
53                 GNUArch:   "i686-linux-gnu", // Note "i686" not "i386"
54                 Bits:      32,
55         },
56         {
57                 GoArch:    "amd64",
58                 LinuxArch: "x86",
59                 GNUArch:   "x86_64-linux-gnu",
60                 Bits:      64,
61         },
62         {
63                 GoArch:     "arm64",
64                 LinuxArch:  "arm64",
65                 GNUArch:    "aarch64-linux-gnu",
66                 SignedChar: true,
67                 Bits:       64,
68         },
69         {
70                 GoArch:    "arm",
71                 LinuxArch: "arm",
72                 GNUArch:   "arm-linux-gnueabi",
73                 Bits:      32,
74         },
75         {
76                 GoArch:    "mips",
77                 LinuxArch: "mips",
78                 GNUArch:   "mips-linux-gnu",
79                 BigEndian: true,
80                 Bits:      32,
81         },
82         {
83                 GoArch:    "mipsle",
84                 LinuxArch: "mips",
85                 GNUArch:   "mipsel-linux-gnu",
86                 Bits:      32,
87         },
88         {
89                 GoArch:    "mips64",
90                 LinuxArch: "mips",
91                 GNUArch:   "mips64-linux-gnuabi64",
92                 BigEndian: true,
93                 Bits:      64,
94         },
95         {
96                 GoArch:    "mips64le",
97                 LinuxArch: "mips",
98                 GNUArch:   "mips64el-linux-gnuabi64",
99                 Bits:      64,
100         },
101         {
102                 GoArch:    "ppc64",
103                 LinuxArch: "powerpc",
104                 GNUArch:   "powerpc64-linux-gnu",
105                 BigEndian: true,
106                 Bits:      64,
107         },
108         {
109                 GoArch:    "ppc64le",
110                 LinuxArch: "powerpc",
111                 GNUArch:   "powerpc64le-linux-gnu",
112                 Bits:      64,
113         },
114         {
115                 GoArch:     "s390x",
116                 LinuxArch:  "s390",
117                 GNUArch:    "s390x-linux-gnu",
118                 BigEndian:  true,
119                 SignedChar: true,
120                 Bits:       64,
121         },
122         // {
123         //      GoArch:    "sparc64",
124         //      LinuxArch: "sparc",
125         //      GNUArch:   "sparc64-linux-gnu",
126         //      BigEndian: true,
127         //      Bits:      64,
128         // },
129 }
130
131 func main() {
132         if runtime.GOOS != GOOS || runtime.GOARCH != BuildArch {
133                 fmt.Printf("Build system has GOOS_GOARCH = %s_%s, need %s_%s\n",
134                         runtime.GOOS, runtime.GOARCH, GOOS, BuildArch)
135                 return
136         }
137
138         // Check that we are using the new build system if we should
139         if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
140                 fmt.Println("In the new build system, mkall.go should not be called directly.")
141                 fmt.Println("See README.md")
142                 return
143         }
144
145         // Parse the command line options
146         if len(os.Args) != 3 {
147                 fmt.Println("USAGE: go run linux/mkall.go <linux_dir> <glibc_dir>")
148                 return
149         }
150         LinuxDir = os.Args[1]
151         GlibcDir = os.Args[2]
152
153         for _, t := range targets {
154                 fmt.Printf("----- GENERATING: %s -----\n", t.GoArch)
155                 if err := t.generateFiles(); err != nil {
156                         fmt.Printf("%v\n***** FAILURE:    %s *****\n\n", err, t.GoArch)
157                 } else {
158                         fmt.Printf("----- SUCCESS:    %s -----\n\n", t.GoArch)
159                 }
160         }
161 }
162
163 // Makes an exec.Cmd with Stderr attached to os.Stderr
164 func makeCommand(name string, args ...string) *exec.Cmd {
165         cmd := exec.Command(name, args...)
166         cmd.Stderr = os.Stderr
167         return cmd
168 }
169
170 // Runs the command, pipes output to a formatter, pipes that to an output file.
171 func (t *target) commandFormatOutput(formatter string, outputFile string,
172         name string, args ...string) (err error) {
173         mainCmd := makeCommand(name, args...)
174
175         fmtCmd := makeCommand(formatter)
176         if formatter == "mkpost" {
177                 fmtCmd = makeCommand("go", "run", "mkpost.go")
178                 // Set GOARCH_TARGET so mkpost knows what GOARCH is..
179                 fmtCmd.Env = append(os.Environ(), "GOARCH_TARGET="+t.GoArch)
180                 // Set GOARCH to host arch for mkpost, so it can run natively.
181                 for i, s := range fmtCmd.Env {
182                         if strings.HasPrefix(s, "GOARCH=") {
183                                 fmtCmd.Env[i] = "GOARCH=" + BuildArch
184                         }
185                 }
186         }
187
188         // mainCmd | fmtCmd > outputFile
189         if fmtCmd.Stdin, err = mainCmd.StdoutPipe(); err != nil {
190                 return
191         }
192         if fmtCmd.Stdout, err = os.Create(outputFile); err != nil {
193                 return
194         }
195
196         // Make sure the formatter eventually closes
197         if err = fmtCmd.Start(); err != nil {
198                 return
199         }
200         defer func() {
201                 fmtErr := fmtCmd.Wait()
202                 if err == nil {
203                         err = fmtErr
204                 }
205         }()
206
207         return mainCmd.Run()
208 }
209
210 // Generates all the files for a Linux target
211 func (t *target) generateFiles() error {
212         // Setup environment variables
213         os.Setenv("GOOS", GOOS)
214         os.Setenv("GOARCH", t.GoArch)
215
216         // Get appropriate compiler and emulator (unless on x86)
217         if t.LinuxArch != "x86" {
218                 // Check/Setup cross compiler
219                 compiler := t.GNUArch + "-gcc"
220                 if _, err := exec.LookPath(compiler); err != nil {
221                         return err
222                 }
223                 os.Setenv("CC", compiler)
224
225                 // Check/Setup emulator (usually first component of GNUArch)
226                 qemuArchName := t.GNUArch[:strings.Index(t.GNUArch, "-")]
227                 if t.LinuxArch == "powerpc" {
228                         qemuArchName = t.GoArch
229                 }
230                 os.Setenv("GORUN", "qemu-"+qemuArchName)
231         } else {
232                 os.Setenv("CC", "gcc")
233         }
234
235         // Make the include directory and fill it with headers
236         if err := os.MkdirAll(IncludeDir, os.ModePerm); err != nil {
237                 return err
238         }
239         defer os.RemoveAll(IncludeDir)
240         if err := t.makeHeaders(); err != nil {
241                 return fmt.Errorf("could not make header files: %v", err)
242         }
243         fmt.Println("header files generated")
244
245         // Make each of the four files
246         if err := t.makeZSysnumFile(); err != nil {
247                 return fmt.Errorf("could not make zsysnum file: %v", err)
248         }
249         fmt.Println("zsysnum file generated")
250
251         if err := t.makeZSyscallFile(); err != nil {
252                 return fmt.Errorf("could not make zsyscall file: %v", err)
253         }
254         fmt.Println("zsyscall file generated")
255
256         if err := t.makeZTypesFile(); err != nil {
257                 return fmt.Errorf("could not make ztypes file: %v", err)
258         }
259         fmt.Println("ztypes file generated")
260
261         if err := t.makeZErrorsFile(); err != nil {
262                 return fmt.Errorf("could not make zerrors file: %v", err)
263         }
264         fmt.Println("zerrors file generated")
265
266         return nil
267 }
268
269 // Create the Linux and glibc headers in the include directory.
270 func (t *target) makeHeaders() error {
271         // Make the Linux headers we need for this architecture
272         linuxMake := makeCommand("make", "headers_install", "ARCH="+t.LinuxArch, "INSTALL_HDR_PATH="+TempDir)
273         linuxMake.Dir = LinuxDir
274         if err := linuxMake.Run(); err != nil {
275                 return err
276         }
277
278         // A Temporary build directory for glibc
279         if err := os.MkdirAll(BuildDir, os.ModePerm); err != nil {
280                 return err
281         }
282         defer os.RemoveAll(BuildDir)
283
284         // Make the glibc headers we need for this architecture
285         confScript := filepath.Join(GlibcDir, "configure")
286         glibcConf := makeCommand(confScript, "--prefix="+TempDir, "--host="+t.GNUArch, "--enable-kernel="+MinKernel)
287         glibcConf.Dir = BuildDir
288         if err := glibcConf.Run(); err != nil {
289                 return err
290         }
291         glibcMake := makeCommand("make", "install-headers")
292         glibcMake.Dir = BuildDir
293         if err := glibcMake.Run(); err != nil {
294                 return err
295         }
296         // We only need an empty stubs file
297         stubsFile := filepath.Join(IncludeDir, "gnu/stubs.h")
298         if file, err := os.Create(stubsFile); err != nil {
299                 return err
300         } else {
301                 file.Close()
302         }
303
304         return nil
305 }
306
307 // makes the zsysnum_linux_$GOARCH.go file
308 func (t *target) makeZSysnumFile() error {
309         zsysnumFile := fmt.Sprintf("zsysnum_linux_%s.go", t.GoArch)
310         unistdFile := filepath.Join(IncludeDir, "asm/unistd.h")
311
312         args := append(t.cFlags(), unistdFile)
313         return t.commandFormatOutput("gofmt", zsysnumFile, "linux/mksysnum.pl", args...)
314 }
315
316 // makes the zsyscall_linux_$GOARCH.go file
317 func (t *target) makeZSyscallFile() error {
318         zsyscallFile := fmt.Sprintf("zsyscall_linux_%s.go", t.GoArch)
319         // Find the correct architecture syscall file (might end with x.go)
320         archSyscallFile := fmt.Sprintf("syscall_linux_%s.go", t.GoArch)
321         if _, err := os.Stat(archSyscallFile); os.IsNotExist(err) {
322                 shortArch := strings.TrimSuffix(t.GoArch, "le")
323                 archSyscallFile = fmt.Sprintf("syscall_linux_%sx.go", shortArch)
324         }
325
326         args := append(t.mksyscallFlags(), "-tags", "linux,"+t.GoArch,
327                 "syscall_linux.go", archSyscallFile)
328         return t.commandFormatOutput("gofmt", zsyscallFile, "./mksyscall.pl", args...)
329 }
330
331 // makes the zerrors_linux_$GOARCH.go file
332 func (t *target) makeZErrorsFile() error {
333         zerrorsFile := fmt.Sprintf("zerrors_linux_%s.go", t.GoArch)
334
335         return t.commandFormatOutput("gofmt", zerrorsFile, "./mkerrors.sh", t.cFlags()...)
336 }
337
338 // makes the ztypes_linux_$GOARCH.go file
339 func (t *target) makeZTypesFile() error {
340         ztypesFile := fmt.Sprintf("ztypes_linux_%s.go", t.GoArch)
341
342         args := []string{"tool", "cgo", "-godefs", "--"}
343         args = append(args, t.cFlags()...)
344         args = append(args, "linux/types.go")
345         return t.commandFormatOutput("mkpost", ztypesFile, "go", args...)
346 }
347
348 // Flags that should be given to gcc and cgo for this target
349 func (t *target) cFlags() []string {
350         // Compile statically to avoid cross-architecture dynamic linking.
351         flags := []string{"-Wall", "-Werror", "-static", "-I" + IncludeDir}
352
353         // Architecture-specific flags
354         if t.SignedChar {
355                 flags = append(flags, "-fsigned-char")
356         }
357         if t.LinuxArch == "x86" {
358                 flags = append(flags, fmt.Sprintf("-m%d", t.Bits))
359         }
360
361         return flags
362 }
363
364 // Flags that should be given to mksyscall for this target
365 func (t *target) mksyscallFlags() (flags []string) {
366         if t.Bits == 32 {
367                 if t.BigEndian {
368                         flags = append(flags, "-b32")
369                 } else {
370                         flags = append(flags, "-l32")
371                 }
372         }
373
374         // This flag menas a 64-bit value should use (even, odd)-pair.
375         if t.GoArch == "arm" || (t.LinuxArch == "mips" && t.Bits == 32) {
376                 flags = append(flags, "-arm")
377         }
378         return
379 }