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