...

Source file src/github.com/bazelbuild/rules_go/go/tools/builders/stdlib.go

Documentation: github.com/bazelbuild/rules_go/go/tools/builders

     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  	"regexp"
    24  	"strings"
    25  )
    26  
    27  // stdlib builds the standard library in the appropriate mode into a new goroot.
    28  func stdlib(args []string) error {
    29  	// process the args
    30  	flags := flag.NewFlagSet("stdlib", flag.ExitOnError)
    31  	goenv := envFlags(flags)
    32  	out := flags.String("out", "", "Path to output go root")
    33  	race := flags.Bool("race", false, "Build in race mode")
    34  	shared := flags.Bool("shared", false, "Build in shared mode")
    35  	dynlink := flags.Bool("dynlink", false, "Build in dynlink mode")
    36  	pgoprofile := flags.String("pgoprofile", "", "Build with pgo using the given pprof file")
    37  	var packages multiFlag
    38  	flags.Var(&packages, "package", "Packages to build")
    39  	var gcflags quoteMultiFlag
    40  	flags.Var(&gcflags, "gcflags", "Go compiler flags")
    41  	if err := flags.Parse(args); err != nil {
    42  		return err
    43  	}
    44  	if err := goenv.checkFlags(); err != nil {
    45  		return err
    46  	}
    47  	goroot := os.Getenv("GOROOT")
    48  	if goroot == "" {
    49  		return fmt.Errorf("GOROOT not set")
    50  	}
    51  	output := abs(*out)
    52  
    53  	// Fail fast if cgo is required but a toolchain is not configured.
    54  	if os.Getenv("CGO_ENABLED") == "1" && filepath.Base(os.Getenv("CC")) == "vc_installation_error.bat" {
    55  		return fmt.Errorf(`cgo is required, but a C toolchain has not been configured.
    56  You may need to use the flags --cpu=x64_windows --compiler=mingw-gcc.`)
    57  	}
    58  
    59  	// Link in the bare minimum needed to the new GOROOT
    60  	if err := replicate(goroot, output, replicatePaths("src", "pkg/tool", "pkg/include")); err != nil {
    61  		return err
    62  	}
    63  
    64  	output, err := processPath(output)
    65  	if err != nil {
    66  		return err
    67  	}
    68  
    69  	// Now switch to the newly created GOROOT
    70  	os.Setenv("GOROOT", output)
    71  
    72  	// Create a temporary cache directory. "go build" requires this starting
    73  	// in Go 1.12.
    74  	cachePath := filepath.Join(output, ".gocache")
    75  	os.Setenv("GOCACHE", cachePath)
    76  	defer os.RemoveAll(cachePath)
    77  
    78  	// Disable modules for the 'go install' command. Depending on the sandboxing
    79  	// mode, there may be a go.mod file in a parent directory which will turn
    80  	// modules on in "auto" mode.
    81  	os.Setenv("GO111MODULE", "off")
    82  
    83  	// Make sure we have an absolute path to the C compiler.
    84  	os.Setenv("CC", quotePathIfNeeded(abs(os.Getenv("CC"))))
    85  
    86  	// Ensure paths are absolute.
    87  	absPaths := []string{}
    88  	for _, path := range filepath.SplitList(os.Getenv("PATH")) {
    89  		absPaths = append(absPaths, abs(path))
    90  	}
    91  	os.Setenv("PATH", strings.Join(absPaths, string(os.PathListSeparator)))
    92  
    93  	sandboxPath := abs(".")
    94  
    95  	// Strip path prefix from source files in debug information.
    96  	os.Setenv("CGO_CFLAGS", os.Getenv("CGO_CFLAGS")+" "+strings.Join(defaultCFlags(output), " "))
    97  	os.Setenv("CGO_LDFLAGS", os.Getenv("CGO_LDFLAGS")+" "+strings.Join(defaultLdFlags(), " "))
    98  
    99  	// Allow flags in CGO_LDFLAGS that wouldn't pass the security check.
   100  	// Workaround for golang.org/issue/42565.
   101  	var b strings.Builder
   102  	sep := ""
   103  	cgoLdflags, _ := splitQuoted(os.Getenv("CGO_LDFLAGS"))
   104  	for _, f := range cgoLdflags {
   105  		b.WriteString(sep)
   106  		sep = "|"
   107  		b.WriteString(regexp.QuoteMeta(f))
   108  		// If the flag if -framework, the flag value needs to be in the same
   109  		// condition.
   110  		if f == "-framework" {
   111  			sep = " "
   112  		}
   113  	}
   114  	os.Setenv("CGO_LDFLAGS_ALLOW", b.String())
   115  	os.Setenv("GODEBUG", "installgoroot=all")
   116  
   117  	// Build the commands needed to build the std library in the right mode
   118  	// NOTE: the go command stamps compiled .a files with build ids, which are
   119  	// cryptographic sums derived from the inputs. This prevents us from
   120  	// creating reproducible builds because the build ids are hashed from
   121  	// CGO_CFLAGS, which frequently contains absolute paths. As a workaround,
   122  	// we strip the build ids, since they won't be used after this.
   123  	installArgs := goenv.goCmd("install", "-toolexec", abs(os.Args[0])+" filterbuildid")
   124  	if len(build.Default.BuildTags) > 0 {
   125  		installArgs = append(installArgs, "-tags", strings.Join(build.Default.BuildTags, ","))
   126  	}
   127  
   128  	ldflags := []string{"-trimpath", sandboxPath}
   129  	asmflags := []string{"-trimpath", output}
   130  	if *race {
   131  		installArgs = append(installArgs, "-race")
   132  	}
   133  	if *pgoprofile != "" {
   134  		installArgs = append(installArgs, "-pgo", abs(*pgoprofile))
   135  	}
   136  	if *shared {
   137  		gcflags = append(gcflags, "-shared")
   138  		ldflags = append(ldflags, "-shared")
   139  		asmflags = append(asmflags, "-shared")
   140  	}
   141  	if *dynlink {
   142  		gcflags = append(gcflags, "-dynlink")
   143  		ldflags = append(ldflags, "-dynlink")
   144  		asmflags = append(asmflags, "-dynlink")
   145  	}
   146  
   147  	// Since Go 1.10, an all= prefix indicates the flags should apply to the package
   148  	// and its dependencies, rather than just the package itself. This was the
   149  	// default behavior before Go 1.10.
   150  	allSlug := ""
   151  	for _, t := range build.Default.ReleaseTags {
   152  		if t == "go1.10" {
   153  			allSlug = "all="
   154  			break
   155  		}
   156  	}
   157  	installArgs = append(installArgs, "-gcflags="+allSlug+strings.Join(gcflags, " "))
   158  	installArgs = append(installArgs, "-ldflags="+allSlug+strings.Join(ldflags, " "))
   159  	installArgs = append(installArgs, "-asmflags="+allSlug+strings.Join(asmflags, " "))
   160  
   161  	// Modify CGO flags to use only absolute path
   162  	// because go is having its own sandbox, all CGO flags must use absolute path
   163  	if err := absEnv(cgoEnvVars, cgoAbsEnvFlags); err != nil {
   164  		return fmt.Errorf("error modifying cgo environment to absolute path: %v", err)
   165  	}
   166  
   167  	installArgs = append(installArgs, packages...)
   168  	if err := goenv.runCommand(installArgs); err != nil {
   169  		return err
   170  	}
   171  	return nil
   172  }
   173  

View as plain text