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  }