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