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  }