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
5package main
6
7import (
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.
30const 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.
34func 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
47func 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
70func 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.
117func 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..."
131func 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.
145func 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