xref: /aosp_15_r20/external/bazelbuild-rules_go/go/tools/builders/stdlib.go (revision 9bb1b549b6a84214c53be0924760be030e66b93a)
1*9bb1b549SSpandan Das// Copyright 2018 The Bazel Authors. All rights reserved.
2*9bb1b549SSpandan Das//
3*9bb1b549SSpandan Das// Licensed under the Apache License, Version 2.0 (the "License");
4*9bb1b549SSpandan Das// you may not use this file except in compliance with the License.
5*9bb1b549SSpandan Das// You may obtain a copy of the License at
6*9bb1b549SSpandan Das//
7*9bb1b549SSpandan Das//    http://www.apache.org/licenses/LICENSE-2.0
8*9bb1b549SSpandan Das//
9*9bb1b549SSpandan Das// Unless required by applicable law or agreed to in writing, software
10*9bb1b549SSpandan Das// distributed under the License is distributed on an "AS IS" BASIS,
11*9bb1b549SSpandan Das// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9bb1b549SSpandan Das// See the License for the specific language governing permissions and
13*9bb1b549SSpandan Das// limitations under the License.
14*9bb1b549SSpandan Das
15*9bb1b549SSpandan Daspackage main
16*9bb1b549SSpandan Das
17*9bb1b549SSpandan Dasimport (
18*9bb1b549SSpandan Das	"flag"
19*9bb1b549SSpandan Das	"fmt"
20*9bb1b549SSpandan Das	"go/build"
21*9bb1b549SSpandan Das	"os"
22*9bb1b549SSpandan Das	"path/filepath"
23*9bb1b549SSpandan Das	"regexp"
24*9bb1b549SSpandan Das	"strings"
25*9bb1b549SSpandan Das)
26*9bb1b549SSpandan Das
27*9bb1b549SSpandan Das// stdlib builds the standard library in the appropriate mode into a new goroot.
28*9bb1b549SSpandan Dasfunc stdlib(args []string) error {
29*9bb1b549SSpandan Das	// process the args
30*9bb1b549SSpandan Das	flags := flag.NewFlagSet("stdlib", flag.ExitOnError)
31*9bb1b549SSpandan Das	goenv := envFlags(flags)
32*9bb1b549SSpandan Das	out := flags.String("out", "", "Path to output go root")
33*9bb1b549SSpandan Das	race := flags.Bool("race", false, "Build in race mode")
34*9bb1b549SSpandan Das	shared := flags.Bool("shared", false, "Build in shared mode")
35*9bb1b549SSpandan Das	dynlink := flags.Bool("dynlink", false, "Build in dynlink mode")
36*9bb1b549SSpandan Das	var packages multiFlag
37*9bb1b549SSpandan Das	flags.Var(&packages, "package", "Packages to build")
38*9bb1b549SSpandan Das	var gcflags quoteMultiFlag
39*9bb1b549SSpandan Das	flags.Var(&gcflags, "gcflags", "Go compiler flags")
40*9bb1b549SSpandan Das	if err := flags.Parse(args); err != nil {
41*9bb1b549SSpandan Das		return err
42*9bb1b549SSpandan Das	}
43*9bb1b549SSpandan Das	if err := goenv.checkFlags(); err != nil {
44*9bb1b549SSpandan Das		return err
45*9bb1b549SSpandan Das	}
46*9bb1b549SSpandan Das	goroot := os.Getenv("GOROOT")
47*9bb1b549SSpandan Das	if goroot == "" {
48*9bb1b549SSpandan Das		return fmt.Errorf("GOROOT not set")
49*9bb1b549SSpandan Das	}
50*9bb1b549SSpandan Das	output := abs(*out)
51*9bb1b549SSpandan Das
52*9bb1b549SSpandan Das	// Fail fast if cgo is required but a toolchain is not configured.
53*9bb1b549SSpandan Das	if os.Getenv("CGO_ENABLED") == "1" && filepath.Base(os.Getenv("CC")) == "vc_installation_error.bat" {
54*9bb1b549SSpandan Das		return fmt.Errorf(`cgo is required, but a C toolchain has not been configured.
55*9bb1b549SSpandan DasYou may need to use the flags --cpu=x64_windows --compiler=mingw-gcc.`)
56*9bb1b549SSpandan Das	}
57*9bb1b549SSpandan Das
58*9bb1b549SSpandan Das	// Link in the bare minimum needed to the new GOROOT
59*9bb1b549SSpandan Das	if err := replicate(goroot, output, replicatePaths("src", "pkg/tool", "pkg/include")); err != nil {
60*9bb1b549SSpandan Das		return err
61*9bb1b549SSpandan Das	}
62*9bb1b549SSpandan Das
63*9bb1b549SSpandan Das	output, err := processPath(output)
64*9bb1b549SSpandan Das	if err != nil {
65*9bb1b549SSpandan Das		return err
66*9bb1b549SSpandan Das	}
67*9bb1b549SSpandan Das
68*9bb1b549SSpandan Das	// Now switch to the newly created GOROOT
69*9bb1b549SSpandan Das	os.Setenv("GOROOT", output)
70*9bb1b549SSpandan Das
71*9bb1b549SSpandan Das	// Create a temporary cache directory. "go build" requires this starting
72*9bb1b549SSpandan Das	// in Go 1.12.
73*9bb1b549SSpandan Das	cachePath := filepath.Join(output, ".gocache")
74*9bb1b549SSpandan Das	os.Setenv("GOCACHE", cachePath)
75*9bb1b549SSpandan Das	defer os.RemoveAll(cachePath)
76*9bb1b549SSpandan Das
77*9bb1b549SSpandan Das	// Disable modules for the 'go install' command. Depending on the sandboxing
78*9bb1b549SSpandan Das	// mode, there may be a go.mod file in a parent directory which will turn
79*9bb1b549SSpandan Das	// modules on in "auto" mode.
80*9bb1b549SSpandan Das	os.Setenv("GO111MODULE", "off")
81*9bb1b549SSpandan Das
82*9bb1b549SSpandan Das	// Make sure we have an absolute path to the C compiler.
83*9bb1b549SSpandan Das	// TODO(#1357): also take absolute paths of includes and other paths in flags.
84*9bb1b549SSpandan Das	os.Setenv("CC", quotePathIfNeeded(abs(os.Getenv("CC"))))
85*9bb1b549SSpandan Das
86*9bb1b549SSpandan Das	// Ensure paths are absolute.
87*9bb1b549SSpandan Das	absPaths := []string{}
88*9bb1b549SSpandan Das	for _, path := range filepath.SplitList(os.Getenv("PATH")) {
89*9bb1b549SSpandan Das		absPaths = append(absPaths, abs(path))
90*9bb1b549SSpandan Das	}
91*9bb1b549SSpandan Das	os.Setenv("PATH", strings.Join(absPaths, string(os.PathListSeparator)))
92*9bb1b549SSpandan Das
93*9bb1b549SSpandan Das	sandboxPath := abs(".")
94*9bb1b549SSpandan Das
95*9bb1b549SSpandan Das	// Strip path prefix from source files in debug information.
96*9bb1b549SSpandan Das	os.Setenv("CGO_CFLAGS", os.Getenv("CGO_CFLAGS")+" "+strings.Join(defaultCFlags(output), " "))
97*9bb1b549SSpandan Das	os.Setenv("CGO_LDFLAGS", os.Getenv("CGO_LDFLAGS")+" "+strings.Join(defaultLdFlags(), " "))
98*9bb1b549SSpandan Das
99*9bb1b549SSpandan Das	// Allow flags in CGO_LDFLAGS that wouldn't pass the security check.
100*9bb1b549SSpandan Das	// Workaround for golang.org/issue/42565.
101*9bb1b549SSpandan Das	var b strings.Builder
102*9bb1b549SSpandan Das	sep := ""
103*9bb1b549SSpandan Das	cgoLdflags, _ := splitQuoted(os.Getenv("CGO_LDFLAGS"))
104*9bb1b549SSpandan Das	for _, f := range cgoLdflags {
105*9bb1b549SSpandan Das		b.WriteString(sep)
106*9bb1b549SSpandan Das		sep = "|"
107*9bb1b549SSpandan Das		b.WriteString(regexp.QuoteMeta(f))
108*9bb1b549SSpandan Das		// If the flag if -framework, the flag value needs to be in the same
109*9bb1b549SSpandan Das		// condition.
110*9bb1b549SSpandan Das		if f == "-framework" {
111*9bb1b549SSpandan Das			sep = " "
112*9bb1b549SSpandan Das		}
113*9bb1b549SSpandan Das	}
114*9bb1b549SSpandan Das	os.Setenv("CGO_LDFLAGS_ALLOW", b.String())
115*9bb1b549SSpandan Das	os.Setenv("GODEBUG", "installgoroot=all")
116*9bb1b549SSpandan Das
117*9bb1b549SSpandan Das	// Build the commands needed to build the std library in the right mode
118*9bb1b549SSpandan Das	// NOTE: the go command stamps compiled .a files with build ids, which are
119*9bb1b549SSpandan Das	// cryptographic sums derived from the inputs. This prevents us from
120*9bb1b549SSpandan Das	// creating reproducible builds because the build ids are hashed from
121*9bb1b549SSpandan Das	// CGO_CFLAGS, which frequently contains absolute paths. As a workaround,
122*9bb1b549SSpandan Das	// we strip the build ids, since they won't be used after this.
123*9bb1b549SSpandan Das	installArgs := goenv.goCmd("install", "-toolexec", abs(os.Args[0])+" filterbuildid")
124*9bb1b549SSpandan Das	if len(build.Default.BuildTags) > 0 {
125*9bb1b549SSpandan Das		installArgs = append(installArgs, "-tags", strings.Join(build.Default.BuildTags, ","))
126*9bb1b549SSpandan Das	}
127*9bb1b549SSpandan Das
128*9bb1b549SSpandan Das	ldflags := []string{"-trimpath", sandboxPath}
129*9bb1b549SSpandan Das	asmflags := []string{"-trimpath", output}
130*9bb1b549SSpandan Das	if *race {
131*9bb1b549SSpandan Das		installArgs = append(installArgs, "-race")
132*9bb1b549SSpandan Das	}
133*9bb1b549SSpandan Das	if *shared {
134*9bb1b549SSpandan Das		gcflags = append(gcflags, "-shared")
135*9bb1b549SSpandan Das		ldflags = append(ldflags, "-shared")
136*9bb1b549SSpandan Das		asmflags = append(asmflags, "-shared")
137*9bb1b549SSpandan Das	}
138*9bb1b549SSpandan Das	if *dynlink {
139*9bb1b549SSpandan Das		gcflags = append(gcflags, "-dynlink")
140*9bb1b549SSpandan Das		ldflags = append(ldflags, "-dynlink")
141*9bb1b549SSpandan Das		asmflags = append(asmflags, "-dynlink")
142*9bb1b549SSpandan Das	}
143*9bb1b549SSpandan Das
144*9bb1b549SSpandan Das	// Since Go 1.10, an all= prefix indicates the flags should apply to the package
145*9bb1b549SSpandan Das	// and its dependencies, rather than just the package itself. This was the
146*9bb1b549SSpandan Das	// default behavior before Go 1.10.
147*9bb1b549SSpandan Das	allSlug := ""
148*9bb1b549SSpandan Das	for _, t := range build.Default.ReleaseTags {
149*9bb1b549SSpandan Das		if t == "go1.10" {
150*9bb1b549SSpandan Das			allSlug = "all="
151*9bb1b549SSpandan Das			break
152*9bb1b549SSpandan Das		}
153*9bb1b549SSpandan Das	}
154*9bb1b549SSpandan Das	installArgs = append(installArgs, "-gcflags="+allSlug+strings.Join(gcflags, " "))
155*9bb1b549SSpandan Das	installArgs = append(installArgs, "-ldflags="+allSlug+strings.Join(ldflags, " "))
156*9bb1b549SSpandan Das	installArgs = append(installArgs, "-asmflags="+allSlug+strings.Join(asmflags, " "))
157*9bb1b549SSpandan Das
158*9bb1b549SSpandan Das	// Modifying CGO flags to use only absolute path
159*9bb1b549SSpandan Das	// because go is having its own sandbox, all CGO flags must use absolute path
160*9bb1b549SSpandan Das	if err := absEnv(cgoEnvVars, cgoAbsEnvFlags); err != nil {
161*9bb1b549SSpandan Das		return fmt.Errorf("error modifying cgo environment to absolute path: %v", err)
162*9bb1b549SSpandan Das	}
163*9bb1b549SSpandan Das
164*9bb1b549SSpandan Das	installArgs = append(installArgs, packages...)
165*9bb1b549SSpandan Das	if err := goenv.runCommand(installArgs); err != nil {
166*9bb1b549SSpandan Das		return err
167*9bb1b549SSpandan Das	}
168*9bb1b549SSpandan Das	return nil
169*9bb1b549SSpandan Das}
170