Newer
Older
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"path/filepath"
)
// Initialization for any invocation.
Bryan C. Mills
committed
gorootBin string
gorootBinGo string
gohostarch string
gohostos string
goos string
goarm string
gomips string
goppc64 string
goroot string
goextlinkenabled string
gogcflags string // For running built compiler
goldflags string
goexperiment string
workdir string
tooldir string
oldgoos string
oldgoarch string
oldgocache string
exe string
defaultcc map[string]string
defaultcxx map[string]string
defaultpkgconfig string
defaultldso string
isRelease bool
var okgoarch = []string{
var okgoos = []string{
"solaris",
// find reports the first index of p in l[0:n], or else -1.
func find(p string, l []string) int {
for i, s := range l {
if p == s {
return i
}
}
return -1
// xinit handles initialization of the various global state, like goroot and goarch.
func xinit() {
b := os.Getenv("GOROOT")
if b == "" {
goroot = filepath.Clean(b)
Bryan C. Mills
committed
gorootBin = pathf("%s/bin", goroot)
// Don't run just 'go' because the build infrastructure
// runs cmd/dist inside go/bin often, and on Windows
// it will be found in the current directory and refuse to exec.
// All exec calls rewrite "go" into gorootBinGo.
gorootBinGo = pathf("%s/bin/go", goroot)
b = os.Getenv("GOOS")
if b == "" {
b = gohostos
}
goos = b
if find(goos, okgoos) < 0 {
fatalf("unknown $GOOS %s", goos)
}
b = os.Getenv("GOARM")
if b == "" {
b = xgetgoarm()
}
goarm = b
b = os.Getenv("GOARM64")
if b == "" {
b = "v8.0"
}
goarm64 = b
b = os.Getenv("GO386")
if b == "" {
b = "sse2"
}
go386 = b
b = os.Getenv("GOAMD64")
if b == "" {
b = "v1"
}
goamd64 = b
b = os.Getenv("GOMIPS")
if b == "" {
b = "hardfloat"
}
gomips = b
b = os.Getenv("GOMIPS64")
if b == "" {
b = "hardfloat"
}
gomips64 = b
b = os.Getenv("GOPPC64")
if b == "" {
b = "power8"
}
goppc64 = b
b = os.Getenv("GORISCV64")
if b == "" {
b = "rva20u64"
}
goriscv64 = b
if p := pathf("%s/src/all.bash", goroot); !isfile(p) {
fatalf("$GOROOT is not set correctly or not exported\n"+
"\tGOROOT=%s\n"+
"\t%s does not exist", goroot, p)
}
b = os.Getenv("GOHOSTARCH")
if b != "" {
gohostarch = b
}
if find(gohostarch, okgoarch) < 0 {
fatalf("unknown $GOHOSTARCH %s", gohostarch)
}
b = os.Getenv("GOARCH")
if b == "" {
b = gohostarch
}
goarch = b
if find(goarch, okgoarch) < 0 {
fatalf("unknown $GOARCH %s", goarch)
}
b = os.Getenv("GO_EXTLINK_ENABLED")
if b != "" {
if b != "0" && b != "1" {
fatalf("unknown $GO_EXTLINK_ENABLED %s", b)
}
goextlinkenabled = b
}
goexperiment = os.Getenv("GOEXPERIMENT")
// TODO(mdempsky): Validate known experiments?
gogcflags = os.Getenv("BOOT_GO_GCFLAGS")
goldflags = os.Getenv("BOOT_GO_LDFLAGS")
defaultcc = compilerEnv("CC", "")
defaultcxx = compilerEnv("CXX", "")
b = os.Getenv("PKG_CONFIG")
if b == "" {
b = "pkg-config"
}
defaultpkgconfig = b
defaultldso = os.Getenv("GO_LDSO")
// For tools being invoked but also for os.ExpandEnv.
os.Setenv("GOARCH", goarch)
os.Setenv("GOARM", goarm)
os.Setenv("GOARM64", goarm64)
os.Setenv("GOHOSTARCH", gohostarch)
os.Setenv("GOHOSTOS", gohostos)
os.Setenv("GOOS", goos)
os.Setenv("GOMIPS", gomips)
os.Setenv("GOMIPS64", gomips64)
os.Setenv("GOPPC64", goppc64)
os.Setenv("GORISCV64", goriscv64)
os.Setenv("GOROOT", goroot)
Bryan C. Mills
committed
// Set GOBIN to GOROOT/bin. The meaning of GOBIN has drifted over time
// (see https://go.dev/issue/3269, https://go.dev/cl/183058,
// https://go.dev/issue/31576). Since we want binaries installed by 'dist' to
// always go to GOROOT/bin anyway.
os.Setenv("GOBIN", gorootBin)
os.Setenv("LANG", "C")
os.Setenv("LANGUAGE", "en_US.UTF8")
Bryan C. Mills
committed
os.Unsetenv("GO111MODULE")
os.Setenv("GOENV", "off")
os.Unsetenv("GOFLAGS")
os.Setenv("GOWORK", "off")
// Create the go.mod for building toolchain2 and toolchain3. Toolchain1 and go_bootstrap are built with
// a separate go.mod (with a lower required go version to allow all allowed bootstrap toolchain versions)
// in bootstrapBuildTools.
modVer := goModVersion()
workdir = xworkdir()
if err := os.WriteFile(pathf("%s/go.mod", workdir), []byte("module bootstrap\n\ngo "+modVer+"\n"), 0666); err != nil {
fatalf("cannot write stub go.mod: %s", err)
}
xatexit(rmworkdir)
tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
goversion := findgoversion()
isRelease = strings.HasPrefix(goversion, "release.") || strings.HasPrefix(goversion, "go")
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
// compilerEnv returns a map from "goos/goarch" to the
// compiler setting to use for that platform.
// The entry for key "" covers any goos/goarch not explicitly set in the map.
// For example, compilerEnv("CC", "gcc") returns the C compiler settings
// read from $CC, defaulting to gcc.
//
// The result is a map because additional environment variables
// can be set to change the compiler based on goos/goarch settings.
// The following applies to all envNames but CC is assumed to simplify
// the presentation.
//
// If no environment variables are set, we use def for all goos/goarch.
// $CC, if set, applies to all goos/goarch but is overridden by the following.
// $CC_FOR_TARGET, if set, applies to all goos/goarch except gohostos/gohostarch,
// but is overridden by the following.
// If gohostos=goos and gohostarch=goarch, then $CC_FOR_TARGET applies even for gohostos/gohostarch.
// $CC_FOR_goos_goarch, if set, applies only to goos/goarch.
func compilerEnv(envName, def string) map[string]string {
m := map[string]string{"": def}
if env := os.Getenv(envName); env != "" {
m[""] = env
}
if env := os.Getenv(envName + "_FOR_TARGET"); env != "" {
if gohostos != goos || gohostarch != goarch {
m[gohostos+"/"+gohostarch] = m[""]
}
m[""] = env
}
for _, goos := range okgoos {
for _, goarch := range okgoarch {
if env := os.Getenv(envName + "_FOR_" + goos + "_" + goarch); env != "" {
m[goos+"/"+goarch] = env
}
}
}
return m
}
// clangos lists the operating systems where we prefer clang to gcc.
var clangos = []string{
"darwin", "ios", // macOS 10.9 and later require clang
"freebsd", // FreeBSD 10 and later do not ship gcc
"openbsd", // OpenBSD ships with GCC 4.2, which is now quite old.
}
// compilerEnvLookup returns the compiler settings for goos/goarch in map m.
// kind is "CC" or "CXX".
func compilerEnvLookup(kind string, m map[string]string, goos, goarch string) string {
if cc := m[goos+"/"+goarch]; cc != "" {
return cc
}
if cc := m[""]; cc != "" {
return cc
}
for _, os := range clangos {
if goos == os {
if kind == "CXX" {
return "clang++"
}
return "clang"
}
}
if kind == "CXX" {
return "g++"
}
return "gcc"
func rmworkdir() {
if vflag > 1 {
errprintf("rm -rf %s\n", workdir)
}
xremoveall(workdir)
func chomp(s string) string {
return strings.TrimRight(s, " \t\r\n")
}
// findgoversion determines the Go version to use in the version string.
// It also parses any other metadata found in the version file.
func findgoversion() string {
// The $GOROOT/VERSION file takes priority, for distributions
path := pathf("%s/VERSION", goroot)
if isfile(path) {
b := chomp(readfile(path))
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
// Starting in Go 1.21 the VERSION file starts with the
// version on a line by itself but then can contain other
// metadata about the release, one item per line.
if i := strings.Index(b, "\n"); i >= 0 {
rest := b[i+1:]
b = chomp(b[:i])
for _, line := range strings.Split(rest, "\n") {
f := strings.Fields(line)
if len(f) == 0 {
continue
}
switch f[0] {
default:
fatalf("VERSION: unexpected line: %s", line)
case "time":
if len(f) != 2 {
fatalf("VERSION: unexpected time line: %s", line)
}
_, err := time.Parse(time.RFC3339, f[1])
if err != nil {
fatalf("VERSION: bad time: %s", err)
}
}
}
}
// Commands such as "dist version > VERSION" will cause
// the shell to create an empty VERSION file and set dist's
// stdout to its fd. dist in turn looks at VERSION and uses
// its content if available, which is empty at this point.
// Only use the VERSION file if it is non-empty.
if b != "" {
return b
}
}
// The $GOROOT/VERSION.cache file is a cache to avoid invoking
// git every time we run this command. Unlike VERSION, it gets
// deleted by the clean command.
path = pathf("%s/VERSION.cache", goroot)
if isfile(path) {
return chomp(readfile(path))
// Show a nicer error message if this isn't a Git repo.
if !isGitRepo() {
fatalf("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
}
//
// Include 1.x base version, hash, and date in the version.
//
// Note that we lightly parse internal/goversion/goversion.go to
// obtain the base version. We can't just import the package,
// because cmd/dist is built with a bootstrap GOROOT which could
// be an entirely different version of Go. We assume
// that the file contains "const Version = <Integer>".
goversionSource := readfile(pathf("%s/src/internal/goversion/goversion.go", goroot))
m := regexp.MustCompile(`(?m)^const Version = (\d+)`).FindStringSubmatch(goversionSource)
if m == nil {
fatalf("internal/goversion/goversion.go does not contain 'const Version = ...'")
}
version := fmt.Sprintf("devel go1.%s-", m[1])
version += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format:%h %cd", "HEAD"))
writefile(version, path, 0)
return version
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
// goModVersion returns the go version declared in src/go.mod. This is the
// go version to use in the go.mod building go_bootstrap, toolchain2, and toolchain3.
// (toolchain1 must be built with requiredBootstrapVersion(goModVersion))
func goModVersion() string {
goMod := readfile(pathf("%s/src/go.mod", goroot))
m := regexp.MustCompile(`(?m)^go (1.\d+)$`).FindStringSubmatch(goMod)
if m == nil {
fatalf("std go.mod does not contain go 1.X")
}
return m[1]
}
func requiredBootstrapVersion(v string) string {
minorstr, ok := strings.CutPrefix(v, "1.")
if !ok {
fatalf("go version %q in go.mod does not start with %q", v, "1.")
}
minor, err := strconv.Atoi(minorstr)
if err != nil {
fatalf("invalid go version minor component %q: %v", minorstr, err)
}
// Per go.dev/doc/install/source, for N >= 22, Go version 1.N will require a Go 1.M compiler,
// where M is N-2 rounded down to an even number. Example: Go 1.24 and 1.25 require Go 1.22.
requiredMinor := minor - 2 - minor%2
return "1." + strconv.Itoa(requiredMinor)
}
// isGitRepo reports whether the working directory is inside a Git repository.
func isGitRepo() bool {
// NB: simply checking the exit code of `git rev-parse --git-dir` would
// suffice here, but that requires deviating from the infrastructure
// provided by `run`.
gitDir := chomp(run(goroot, 0, "git", "rev-parse", "--git-dir"))
if !filepath.IsAbs(gitDir) {
gitDir = filepath.Join(goroot, gitDir)
}
/*
* Initial tree setup.
*/
// The old tools that no longer live in $GOBIN or $GOROOT/bin.
var oldtool = []string{
"5a", "5c", "5g", "5l",
"6a", "6c", "6g", "6l",
"8a", "8c", "8g", "8l",
"9a", "9c", "9g", "9l",
"cgo",
"ebnflint",
"goapi",
"gofix",
"goinstall",
"gomake",
"gopack",
"gopprof",
"gotest",
"gotype",
"govet",
"goyacc",
"quietgcc",
// Unreleased directories (relative to $GOROOT) that should
// not be in release branches.
var unreleased = []string{
"src/debug/goobj",
"src/old",
func setup() {
if p := pathf("%s/bin", goroot); !isdir(p) {
xmkdir(p)
}
if p := pathf("%s/pkg", goroot); !isdir(p) {
xmkdir(p)
}
goosGoarch := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
if rebuildall {
xremoveall(goosGoarch)
xmkdirall(goosGoarch)
xatexit(func() {
if files := xreaddir(goosGoarch); len(files) == 0 {
xremove(goosGoarch)
}
})
if goos != gohostos || goarch != gohostarch {
p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
if rebuildall {
xremoveall(p)
}
xmkdirall(p)
// We used to use it for C objects.
// Now we use it for the build cache, to separate dist's cache
// from any other cache the user might have, and for the location
// to build the bootstrap versions of the standard library.
obj := pathf("%s/pkg/obj", goroot)
if !isdir(obj) {
xmkdir(obj)
}
xatexit(func() { xremove(obj) })
// Create build cache directory.
objGobuild := pathf("%s/pkg/obj/go-build", goroot)
if rebuildall {
xmkdirall(objGobuild)
xatexit(func() { xremoveall(objGobuild) })
// Create directory for bootstrap versions of standard library .a files.
objGoBootstrap := pathf("%s/pkg/obj/go-bootstrap", goroot)
if rebuildall {
xmkdirall(objGoBootstrap)
xatexit(func() { xremoveall(objGoBootstrap) })
// Create tool directory.
// We keep it in pkg/, just like the object directory above.
if rebuildall {
xremoveall(tooldir)
}
xmkdirall(tooldir)
// Remove tool binaries from before the tool/gohostos_gohostarch
xremoveall(pathf("%s/bin/tool", goroot))
for _, old := range oldtool {
xremove(pathf("%s/bin/%s", goroot, old))
}
// Special release-specific setup.
if isRelease {
// Make sure release-excluded things are excluded.
for _, dir := range unreleased {
if p := pathf("%s/%s", goroot, dir); isdir(p) {
fatalf("%s should not exist in release build", p)
// mustLinkExternal is a copy of internal/platform.MustLinkExternal,
// duplicated here to avoid version skew in the MustLinkExternal function
// during bootstrapping.
func mustLinkExternal(goos, goarch string, cgoEnabled bool) bool {
if cgoEnabled {
switch goarch {
Joel Sing
committed
case "loong64", "mips", "mipsle", "mips64", "mips64le":
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/14449
return true
case "arm64":
if goos == "windows" {
// windows/arm64 internal linking is not implemented.
return true
}
case "ppc64":
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
if goos == "aix" || goos == "linux" {
return true
}
}
switch goos {
case "android":
return true
case "dragonfly":
// It seems that on Dragonfly thread local storage is
// set up by the dynamic linker, so internal cgo linking
// doesn't work. Test case is "go test runtime/cgo".
return true
}
}
switch goos {
case "android":
if goarch != "arm64" {
return true
}
case "ios":
if goarch == "arm64" {
return true
}
}
return false
}
// depsuffix records the allowed suffixes for source files.
var depsuffix = []string{
// gentab records how to generate some trivial files.
// Files listed here should also be listed in ../distpack/pack.go's srcArch.Remove list.
var gentab = []struct {
pkg string // Relative to $GOROOT/src
file string
gen func(dir, file string)
{"go/build", "zcgo.go", mkzcgo},
{"cmd/go/internal/cfg", "zdefaultcc.go", mkzdefaultcc},
{"internal/runtime/sys", "zversion.go", mkzversion},
{"time/tzdata", "zzipdata.go", mktzdata},
// installed maps from a dir name (as given to install) to a chan
// closed when the dir's package is installed.
var installed = make(map[string]chan struct{})
func install(dir string) {
<-startInstall(dir)
}
func startInstall(dir string) chan struct{} {
installedMu.Lock()
ch := installed[dir]
if ch == nil {
ch = make(chan struct{})
installed[dir] = ch
go runInstall(dir, ch)
}
installedMu.Unlock()
return ch
}
// runInstall installs the library, package, or binary associated with pkg,
// which is relative to $GOROOT/src.
func runInstall(pkg string, ch chan struct{}) {
if pkg == "net" || pkg == "os/user" || pkg == "crypto/x509" {
fatalf("go_bootstrap cannot depend on cgo package %s", pkg)
if vflag > 0 {
if goos != gohostos || goarch != gohostarch {
errprintf("%s (%s/%s)\n", pkg, goos, goarch)
xmkdirall(workdir)
var clean []string
defer func() {
for _, name := range clean {
xremove(name)
}
}()
// dir = full path to pkg.
dir := pathf("%s/src/%s", goroot, pkg)
name := filepath.Base(dir)
// ispkg predicts whether the package should be linked as a binary, based
// on the name. There should be no "main" packages in vendor, since
// 'go mod vendor' will only copy imported packages there.
ispkg := !strings.HasPrefix(pkg, "cmd/") || strings.Contains(pkg, "/internal/") || strings.Contains(pkg, "/vendor/")
// Note: code below knows that link.p[targ] is the target.
var (
link []string
targ int
ispackcmd bool
)
ispackcmd = true
link = []string{"pack", packagefile(pkg)}
targ = len(link) - 1
xmkdirall(filepath.Dir(link[targ]))
elem := name
if elem == "go" {
elem = "go_bootstrap"
}
link = []string{pathf("%s/link", tooldir)}
if goos == "android" {
link = append(link, "-buildmode=pie")
}
if goldflags != "" {
link = append(link, goldflags)
}
link = append(link, "-extld="+compilerEnvLookup("CC", defaultcc, goos, goarch))
link = append(link, "-L="+pathf("%s/pkg/obj/go-bootstrap/%s_%s", goroot, goos, goarch))
link = append(link, "-o", pathf("%s/%s%s", tooldir, elem, exe))
targ = len(link) - 1
ttarg := mtime(link[targ])
// Gather files that are sources for this target.
// Everything in that directory, and any target-specific
// additions.
// Remove files beginning with . or _,
// which are likely to be editor temporary files.
// This is the same heuristic build.ScanDir uses.
// There do exist real C files beginning with _,
// so limit that check to just Go files.
files = filter(files, func(p string) bool {
return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
})
// Add generated files for this package.
for _, gt := range gentab {
if gt.pkg == pkg {
files = append(files, gt.file)
files = uniq(files)
for i, p := range files {
var gofiles, sfiles []string
stale := rebuildall
files = filter(files, func(p string) bool {
for _, suf := range depsuffix {
if strings.HasSuffix(p, suf) {
goto ok
}
}
return false
t := mtime(p)
if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, pkg) {
return false
if strings.HasSuffix(p, ".go") {
gofiles = append(gofiles, p)
} else if strings.HasSuffix(p, ".s") {
sfiles = append(sfiles, p)
if t.After(ttarg) {
stale = true
}
return true
})
// If there are no files to compile, we're done.
if len(files) == 0 {
return
}
if !stale {
return
}
// For package runtime, copy some files into the work space.
Russ Cox
committed
xmkdirall(pathf("%s/pkg/include", goroot))
// For use by assembly and C files.
Russ Cox
committed
copyfile(pathf("%s/pkg/include/textflag.h", goroot),
pathf("%s/src/runtime/textflag.h", goroot), 0)
Russ Cox
committed
copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
pathf("%s/src/runtime/funcdata.h", goroot), 0)
Michael Hudson-Doyle
committed
copyfile(pathf("%s/pkg/include/asm_ppc64x.h", goroot),
pathf("%s/src/runtime/asm_ppc64x.h", goroot), 0)
copyfile(pathf("%s/pkg/include/asm_amd64.h", goroot),
pathf("%s/src/runtime/asm_amd64.h", goroot), 0)
}
// Generate any missing files; regenerate existing ones.
for _, gt := range gentab {
if gt.pkg != pkg {
continue
p := pathf("%s/%s", dir, gt.file)
if vflag > 1 {
errprintf("generate %s\n", p)
gt.gen(dir, p)
// Do not add generated file to clean list.
// In runtime, we want to be able to
// build the package with the go tool,
// and it assumes these generated files already
// exist (it does not know how to build them).
// The 'clean' command can remove
// the generated files.
// Resolve imported packages to actual package paths.
// Make sure they're installed.
importMap := make(map[string]string)
if imp == "C" {
fatalf("%s imports C", p)
}
importMap[imp] = resolveVendor(imp, dir)
}
}
sortedImports := make([]string, 0, len(importMap))
for imp := range importMap {
sortedImports = append(sortedImports, imp)
sort.Strings(sortedImports)
for _, dep := range importMap {
if dep == "C" {
fatalf("%s imports C", pkg)
}
for _, dep := range importMap {
install(dep)
if goos != gohostos || goarch != gohostarch {
// We've generated the right files; the go command can do the build.
if vflag > 1 {
errprintf("skip build for cross-compile %s\n", pkg)
}
return
asmArgs := []string{
pathf("%s/asm", tooldir),
"-I", workdir,
"-I", pathf("%s/pkg/include", goroot),
"-D", "GOOS_" + goos,
"-D", "GOARCH_" + goarch,
"-D", "GOOS_GOARCH_" + goos + "_" + goarch,
"-p", pkg,
}
if goarch == "mips" || goarch == "mipsle" {
// Define GOMIPS_value from gomips.
asmArgs = append(asmArgs, "-D", "GOMIPS_"+gomips)
}
if goarch == "mips64" || goarch == "mips64le" {
// Define GOMIPS64_value from gomips64.
asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
}
if goarch == "ppc64" || goarch == "ppc64le" {
// We treat each powerpc version as a superset of functionality.
switch goppc64 {
case "power10":
asmArgs = append(asmArgs, "-D", "GOPPC64_power10")
fallthrough
case "power9":
asmArgs = append(asmArgs, "-D", "GOPPC64_power9")
fallthrough
default: // This should always be power8.
asmArgs = append(asmArgs, "-D", "GOPPC64_power8")
}
}
if goarch == "riscv64" {
// Define GORISCV64_value from goriscv64
asmArgs = append(asmArgs, "-D", "GORISCV64_"+goriscv64)
}
Cherry Mui
committed
if goarch == "arm" {
// Define GOARM_value from goarm, which can be either a version
// like "6", or a version and a FP mode, like "7,hardfloat".
switch {
case strings.Contains(goarm, "7"):
asmArgs = append(asmArgs, "-D", "GOARM_7")
fallthrough
case strings.Contains(goarm, "6"):
asmArgs = append(asmArgs, "-D", "GOARM_6")
fallthrough
default:
asmArgs = append(asmArgs, "-D", "GOARM_5")
}
}
goasmh := pathf("%s/go_asm.h", workdir)
// Collect symabis from assembly code.
var symabis string
if len(sfiles) > 0 {
symabis = pathf("%s/symabis", workdir)
var wg sync.WaitGroup
asmabis := append(asmArgs[:len(asmArgs):len(asmArgs)], "-gensymabis", "-o", symabis)
asmabis = append(asmabis, sfiles...)
if err := os.WriteFile(goasmh, nil, 0666); err != nil {
fatalf("cannot write empty go_asm.h: %s", err)
}
bgwait(&wg)
}
// Build an importcfg file for the compiler.
buf := &bytes.Buffer{}
for _, imp := range sortedImports {
if imp == "unsafe" {
continue
}
dep := importMap[imp]
if imp != dep {
fmt.Fprintf(buf, "importmap %s=%s\n", imp, dep)
}
fmt.Fprintf(buf, "packagefile %s=%s\n", dep, packagefile(dep))
}
importcfg := pathf("%s/importcfg", workdir)
if err := os.WriteFile(importcfg, buf.Bytes(), 0666); err != nil {
fatalf("cannot write importcfg file: %v", err)
}
var archive string
// The next loop will compile individual non-Go files.
// Hand the Go files to the compiler en masse.
// For packages containing assembly, this writes go_asm.h, which
// the assembly files will need.
pkgName := pkg
if strings.HasPrefix(pkg, "cmd/") && strings.Count(pkg, "/") == 1 {
pkgName = "main"
}
b := pathf("%s/_go_.a", workdir)
clean = append(clean, b)
if !ispackcmd {
link = append(link, b)
} else {
archive = b