Source file src/cmd/go/internal/toolchain/exec.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build !js && !wasip1
     6  
     7  package toolchain
     8  
     9  import (
    10  	"cmd/go/internal/base"
    11  	"fmt"
    12  	"internal/godebug"
    13  	"os"
    14  	"os/exec"
    15  	"runtime"
    16  	"syscall"
    17  )
    18  
    19  // execGoToolchain execs the Go toolchain with the given name (gotoolchain),
    20  // GOROOT directory, and go command executable.
    21  // The GOROOT directory is empty if we are invoking a command named
    22  // gotoolchain found in $PATH.
    23  func execGoToolchain(gotoolchain, dir, exe string) {
    24  	os.Setenv(targetEnv, gotoolchain)
    25  	if dir == "" {
    26  		os.Unsetenv("GOROOT")
    27  	} else {
    28  		os.Setenv("GOROOT", dir)
    29  	}
    30  	if toolchainTrace {
    31  		if dir == "" {
    32  			fmt.Fprintf(os.Stderr, "go: using %s toolchain located in system PATH (%s)\n", gotoolchain, exe)
    33  		} else {
    34  			fmt.Fprintf(os.Stderr, "go: using %s toolchain from cache located at %s\n", gotoolchain, exe)
    35  		}
    36  	}
    37  
    38  	// On Windows, there is no syscall.Exec, so the best we can do
    39  	// is run a subprocess and exit with the same status.
    40  	// Doing the same on Unix would be a problem because it wouldn't
    41  	// propagate signals and such, but there are no signals on Windows.
    42  	// We also use the exec case when GODEBUG=gotoolchainexec=0,
    43  	// to allow testing this code even when not on Windows.
    44  	if godebug.New("#gotoolchainexec").Value() == "0" || runtime.GOOS == "windows" {
    45  		cmd := exec.Command(exe, os.Args[1:]...)
    46  		cmd.Stdin = os.Stdin
    47  		cmd.Stdout = os.Stdout
    48  		cmd.Stderr = os.Stderr
    49  		err := cmd.Run()
    50  		if err != nil {
    51  			if e, ok := err.(*exec.ExitError); ok && e.ProcessState != nil {
    52  				if e.ProcessState.Exited() {
    53  					os.Exit(e.ProcessState.ExitCode())
    54  				}
    55  				base.Fatalf("exec %s: %s", gotoolchain, e.ProcessState)
    56  			}
    57  			base.Fatalf("exec %s: %s", exe, err)
    58  		}
    59  		os.Exit(0)
    60  	}
    61  	err := syscall.Exec(exe, os.Args, os.Environ())
    62  	base.Fatalf("exec %s: %v", gotoolchain, err)
    63  }
    64  

View as plain text