github.com/kooksee/kchain@v0.0.0-20180613035215-4aef51c04906/src/golang.org/x/sys/unix/linux/mkall.go (about) 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 }