Source file src/cmd/dist/buildgo.go

     1  // Copyright 2012 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  package main
     6  
     7  import (
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"path/filepath"
    12  	"sort"
    13  	"strings"
    14  )
    15  
    16  /*
    17   * Helpers for building cmd/go and cmd/cgo.
    18   */
    19  
    20  // generatedHeader is the string that all source files generated by dist start with.
    21  //
    22  // DO NOT CHANGE THIS STRING. If this string is changed then during
    23  //
    24  //	./make.bash
    25  //	git checkout other-rev
    26  //	./make.bash
    27  //
    28  // the second make.bash will not find the files generated by the first make.bash
    29  // and will not clean up properly.
    30  const generatedHeader = "// Code generated by go tool dist; DO NOT EDIT.\n\n"
    31  
    32  // writeHeader emits the standard "generated by" header for all files generated
    33  // by dist.
    34  func writeHeader(w io.Writer) {
    35  	fmt.Fprint(w, generatedHeader)
    36  }
    37  
    38  // mkzdefaultcc writes zdefaultcc.go:
    39  //
    40  //	package main
    41  //	const defaultCC = <defaultcc>
    42  //	const defaultCXX = <defaultcxx>
    43  //	const defaultPkgConfig = <defaultpkgconfig>
    44  //
    45  // It is invoked to write cmd/go/internal/cfg/zdefaultcc.go
    46  // but we also write cmd/cgo/zdefaultcc.go
    47  func mkzdefaultcc(dir, file string) {
    48  	if strings.Contains(file, filepath.FromSlash("go/internal/cfg")) {
    49  		var buf strings.Builder
    50  		writeHeader(&buf)
    51  		fmt.Fprintf(&buf, "package cfg\n")
    52  		fmt.Fprintln(&buf)
    53  		fmt.Fprintf(&buf, "const DefaultPkgConfig = `%s`\n", defaultpkgconfig)
    54  		buf.WriteString(defaultCCFunc("DefaultCC", defaultcc))
    55  		buf.WriteString(defaultCCFunc("DefaultCXX", defaultcxx))
    56  		writefile(buf.String(), file, writeSkipSame)
    57  		return
    58  	}
    59  
    60  	var buf strings.Builder
    61  	writeHeader(&buf)
    62  	fmt.Fprintf(&buf, "package main\n")
    63  	fmt.Fprintln(&buf)
    64  	fmt.Fprintf(&buf, "const defaultPkgConfig = `%s`\n", defaultpkgconfig)
    65  	buf.WriteString(defaultCCFunc("defaultCC", defaultcc))
    66  	buf.WriteString(defaultCCFunc("defaultCXX", defaultcxx))
    67  	writefile(buf.String(), file, writeSkipSame)
    68  }
    69  
    70  func defaultCCFunc(name string, defaultcc map[string]string) string {
    71  	var buf strings.Builder
    72  
    73  	fmt.Fprintf(&buf, "func %s(goos, goarch string) string {\n", name)
    74  	fmt.Fprintf(&buf, "\tswitch goos+`/`+goarch {\n")
    75  	var keys []string
    76  	for k := range defaultcc {
    77  		if k != "" {
    78  			keys = append(keys, k)
    79  		}
    80  	}
    81  	sort.Strings(keys)
    82  	for _, k := range keys {
    83  		fmt.Fprintf(&buf, "\tcase %s:\n\t\treturn %s\n", quote(k), quote(defaultcc[k]))
    84  	}
    85  	fmt.Fprintf(&buf, "\t}\n")
    86  	if cc := defaultcc[""]; cc != "" {
    87  		fmt.Fprintf(&buf, "\treturn %s\n", quote(cc))
    88  	} else {
    89  		clang, gcc := "clang", "gcc"
    90  		if strings.HasSuffix(name, "CXX") {
    91  			clang, gcc = "clang++", "g++"
    92  		}
    93  		fmt.Fprintf(&buf, "\tswitch goos {\n")
    94  		fmt.Fprintf(&buf, "\tcase ")
    95  		for i, os := range clangos {
    96  			if i > 0 {
    97  				fmt.Fprintf(&buf, ", ")
    98  			}
    99  			fmt.Fprintf(&buf, "%s", quote(os))
   100  		}
   101  		fmt.Fprintf(&buf, ":\n")
   102  		fmt.Fprintf(&buf, "\t\treturn %s\n", quote(clang))
   103  		fmt.Fprintf(&buf, "\t}\n")
   104  		fmt.Fprintf(&buf, "\treturn %s\n", quote(gcc))
   105  	}
   106  	fmt.Fprintf(&buf, "}\n")
   107  
   108  	return buf.String()
   109  }
   110  
   111  // mkzcgo writes zcgo.go for the go/build package:
   112  //
   113  //	package build
   114  //	const defaultCGO_ENABLED = <CGO_ENABLED>
   115  //
   116  // It is invoked to write go/build/zcgo.go.
   117  func mkzcgo(dir, file string) {
   118  	var buf strings.Builder
   119  	writeHeader(&buf)
   120  	fmt.Fprintf(&buf, "package build\n")
   121  	fmt.Fprintln(&buf)
   122  	fmt.Fprintf(&buf, "const defaultCGO_ENABLED = %s\n", quote(os.Getenv("CGO_ENABLED")))
   123  
   124  	writefile(buf.String(), file, writeSkipSame)
   125  }
   126  
   127  // mktzdata src/time/tzdata/zzipdata.go:
   128  //
   129  //	package tzdata
   130  //	const zipdata = "PK..."
   131  func mktzdata(dir, file string) {
   132  	zip := readfile(filepath.Join(dir, "../../../lib/time/zoneinfo.zip"))
   133  
   134  	var buf strings.Builder
   135  	writeHeader(&buf)
   136  	fmt.Fprintf(&buf, "package tzdata\n")
   137  	fmt.Fprintln(&buf)
   138  	fmt.Fprintf(&buf, "const zipdata = %s\n", quote(zip))
   139  
   140  	writefile(buf.String(), file, writeSkipSame)
   141  }
   142  
   143  // quote is like strconv.Quote but simpler and has output
   144  // that does not depend on the exact Go bootstrap version.
   145  func quote(s string) string {
   146  	const hex = "0123456789abcdef"
   147  	var out strings.Builder
   148  	out.WriteByte('"')
   149  	for i := 0; i < len(s); i++ {
   150  		c := s[i]
   151  		if 0x20 <= c && c <= 0x7E && c != '"' && c != '\\' {
   152  			out.WriteByte(c)
   153  		} else {
   154  			out.WriteByte('\\')
   155  			out.WriteByte('x')
   156  			out.WriteByte(hex[c>>4])
   157  			out.WriteByte(hex[c&0xf])
   158  		}
   159  	}
   160  	out.WriteByte('"')
   161  	return out.String()
   162  }
   163  

View as plain text