1// Copyright 2011 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
5package work
6
7import (
8	"bufio"
9	"bytes"
10	"fmt"
11	"io"
12	"log"
13	"os"
14	"path/filepath"
15	"runtime"
16	"strings"
17
18	"cmd/go/internal/base"
19	"cmd/go/internal/cfg"
20	"cmd/go/internal/fsys"
21	"cmd/go/internal/load"
22	"cmd/go/internal/str"
23	"cmd/internal/objabi"
24	"cmd/internal/sys"
25	"crypto/sha1"
26)
27
28// The 'path' used for GOROOT_FINAL when -trimpath is specified
29const trimPathGoRootFinal = "go"
30
31// The Go toolchain.
32
33type gcToolchain struct{}
34
35func (gcToolchain) compiler() string {
36	return base.Tool("compile")
37}
38
39func (gcToolchain) linker() string {
40	return base.Tool("link")
41}
42
43func pkgPath(a *Action) string {
44	p := a.Package
45	ppath := p.ImportPath
46	if cfg.BuildBuildmode == "plugin" {
47		ppath = pluginPath(a)
48	} else if p.Name == "main" && !p.Internal.ForceLibrary {
49		ppath = "main"
50	}
51	return ppath
52}
53
54func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) {
55	p := a.Package
56	objdir := a.Objdir
57	if archive != "" {
58		ofile = archive
59	} else {
60		out := "_go_.o"
61		ofile = objdir + out
62	}
63
64	pkgpath := pkgPath(a)
65	gcargs := []string{"-p", pkgpath}
66	if p.Module != nil && p.Module.GoVersion != "" && allowedVersion(p.Module.GoVersion) {
67		gcargs = append(gcargs, "-lang=go"+p.Module.GoVersion)
68	}
69	if p.Standard {
70		gcargs = append(gcargs, "-std")
71	}
72	compilingRuntime := p.Standard && (p.ImportPath == "runtime" || strings.HasPrefix(p.ImportPath, "runtime/internal"))
73	// The runtime package imports a couple of general internal packages.
74	if p.Standard && (p.ImportPath == "internal/cpu" || p.ImportPath == "internal/bytealg") {
75		compilingRuntime = true
76	}
77	if compilingRuntime {
78		// runtime compiles with a special gc flag to check for
79		// memory allocations that are invalid in the runtime package,
80		// and to implement some special compiler pragmas.
81		gcargs = append(gcargs, "-+")
82	}
83
84	// If we're giving the compiler the entire package (no C etc files), tell it that,
85	// so that it can give good error messages about forward declarations.
86	// Exceptions: a few standard packages have forward declarations for
87	// pieces supplied behind-the-scenes by package runtime.
88	extFiles := len(p.CgoFiles) + len(p.CFiles) + len(p.CXXFiles) + len(p.MFiles) + len(p.FFiles) + len(p.SFiles) + len(p.SysoFiles) + len(p.SwigFiles) + len(p.SwigCXXFiles)
89	if p.Standard {
90		switch p.ImportPath {
91		case "bytes", "internal/poll", "net", "os":
92			fallthrough
93		case "runtime/metrics", "runtime/pprof", "runtime/trace":
94			fallthrough
95		case "sync", "syscall", "time":
96			extFiles++
97		}
98	}
99	if extFiles == 0 {
100		gcargs = append(gcargs, "-complete")
101	}
102	if cfg.BuildContext.InstallSuffix != "" {
103		gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix)
104	}
105	if a.buildID != "" {
106		gcargs = append(gcargs, "-buildid", a.buildID)
107	}
108	if p.Internal.OmitDebug || cfg.Goos == "plan9" || cfg.Goarch == "wasm" {
109		gcargs = append(gcargs, "-dwarf=false")
110	}
111	if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") {
112		gcargs = append(gcargs, "-goversion", runtimeVersion)
113	}
114	if symabis != "" {
115		gcargs = append(gcargs, "-symabis", symabis)
116	}
117
118	gcflags := str.StringList(forcedGcflags, p.Internal.Gcflags)
119	if compilingRuntime {
120		// Remove -N, if present.
121		// It is not possible to build the runtime with no optimizations,
122		// because the compiler cannot eliminate enough write barriers.
123		for i := 0; i < len(gcflags); i++ {
124			if gcflags[i] == "-N" {
125				copy(gcflags[i:], gcflags[i+1:])
126				gcflags = gcflags[:len(gcflags)-1]
127				i--
128			}
129		}
130	}
131
132	args := []interface{}{cfg.BuildToolexec, base.Tool("compile"), "-o", ofile, "-trimpath", a.trimpath(), gcflags, gcargs, "-D", p.Internal.LocalPrefix}
133	if importcfg != nil {
134		if err := b.writeFile(objdir+"importcfg", importcfg); err != nil {
135			return "", nil, err
136		}
137		args = append(args, "-importcfg", objdir+"importcfg")
138	}
139	if embedcfg != nil {
140		if err := b.writeFile(objdir+"embedcfg", embedcfg); err != nil {
141			return "", nil, err
142		}
143		args = append(args, "-embedcfg", objdir+"embedcfg")
144	}
145	if ofile == archive {
146		args = append(args, "-pack")
147	}
148	if asmhdr {
149		args = append(args, "-asmhdr", objdir+"go_asm.h")
150	}
151
152	// Add -c=N to use concurrent backend compilation, if possible.
153	if c := gcBackendConcurrency(gcflags); c > 1 {
154		args = append(args, fmt.Sprintf("-c=%d", c))
155	}
156
157	for _, f := range gofiles {
158		f := mkAbs(p.Dir, f)
159
160		// Handle overlays. Convert path names using OverlayPath
161		// so these paths can be handed directly to tools.
162		// Deleted files won't show up in when scanning directories earlier,
163		// so OverlayPath will never return "" (meaning a deleted file) here.
164		// TODO(#39958): Handle cases where the package directory
165		// doesn't exist on disk (this can happen when all the package's
166		// files are in an overlay): the code expects the package directory
167		// to exist and runs some tools in that directory.
168		// TODO(#39958): Process the overlays when the
169		// gofiles, cgofiles, cfiles, sfiles, and cxxfiles variables are
170		// created in (*Builder).build. Doing that requires rewriting the
171		// code that uses those values to expect absolute paths.
172		f, _ = fsys.OverlayPath(f)
173
174		args = append(args, f)
175	}
176
177	output, err = b.runOut(a, base.Cwd, nil, args...)
178	return ofile, output, err
179}
180
181// gcBackendConcurrency returns the backend compiler concurrency level for a package compilation.
182func gcBackendConcurrency(gcflags []string) int {
183	// First, check whether we can use -c at all for this compilation.
184	canDashC := concurrentGCBackendCompilationEnabledByDefault
185
186	switch e := os.Getenv("GO19CONCURRENTCOMPILATION"); e {
187	case "0":
188		canDashC = false
189	case "1":
190		canDashC = true
191	case "":
192		// Not set. Use default.
193	default:
194		log.Fatalf("GO19CONCURRENTCOMPILATION must be 0, 1, or unset, got %q", e)
195	}
196
197CheckFlags:
198	for _, flag := range gcflags {
199		// Concurrent compilation is presumed incompatible with any gcflags,
200		// except for known commonly used flags.
201		// If the user knows better, they can manually add their own -c to the gcflags.
202		switch flag {
203		case "-N", "-l", "-S", "-B", "-C", "-I":
204			// OK
205		default:
206			canDashC = false
207			break CheckFlags
208		}
209	}
210
211	// TODO: Test and delete these conditions.
212	if objabi.Fieldtrack_enabled != 0 || objabi.Preemptibleloops_enabled != 0 {
213		canDashC = false
214	}
215
216	if !canDashC {
217		return 1
218	}
219
220	// Decide how many concurrent backend compilations to allow.
221	//
222	// If we allow too many, in theory we might end up with p concurrent processes,
223	// each with c concurrent backend compiles, all fighting over the same resources.
224	// However, in practice, that seems not to happen too much.
225	// Most build graphs are surprisingly serial, so p==1 for much of the build.
226	// Furthermore, concurrent backend compilation is only enabled for a part
227	// of the overall compiler execution, so c==1 for much of the build.
228	// So don't worry too much about that interaction for now.
229	//
230	// However, in practice, setting c above 4 tends not to help very much.
231	// See the analysis in CL 41192.
232	//
233	// TODO(josharian): attempt to detect whether this particular compilation
234	// is likely to be a bottleneck, e.g. when:
235	//   - it has no successor packages to compile (usually package main)
236	//   - all paths through the build graph pass through it
237	//   - critical path scheduling says it is high priority
238	// and in such a case, set c to runtime.NumCPU.
239	// We do this now when p==1.
240	if cfg.BuildP == 1 {
241		// No process parallelism. Max out c.
242		return runtime.NumCPU()
243	}
244	// Some process parallelism. Set c to min(4, numcpu).
245	c := 4
246	if ncpu := runtime.NumCPU(); ncpu < c {
247		c = ncpu
248	}
249	return c
250}
251
252// trimpath returns the -trimpath argument to use
253// when compiling the action.
254func (a *Action) trimpath() string {
255	// Keep in sync with Builder.ccompile
256	// The trimmed paths are a little different, but we need to trim in the
257	// same situations.
258
259	// Strip the object directory entirely.
260	objdir := a.Objdir
261	if len(objdir) > 1 && objdir[len(objdir)-1] == filepath.Separator {
262		objdir = objdir[:len(objdir)-1]
263	}
264	rewrite := ""
265
266	rewriteDir := a.Package.Dir
267	if cfg.BuildTrimpath {
268		if m := a.Package.Module; m != nil && m.Version != "" {
269			rewriteDir = m.Path + "@" + m.Version + strings.TrimPrefix(a.Package.ImportPath, m.Path)
270		} else {
271			rewriteDir = a.Package.ImportPath
272		}
273		rewrite += a.Package.Dir + "=>" + rewriteDir + ";"
274	}
275
276	// Add rewrites for overlays. The 'from' and 'to' paths in overlays don't need to have
277	// same basename, so go from the overlay contents file path (passed to the compiler)
278	// to the path the disk path would be rewritten to.
279
280	cgoFiles := make(map[string]bool)
281	for _, f := range a.Package.CgoFiles {
282		cgoFiles[f] = true
283	}
284
285	// TODO(matloob): Higher up in the stack, when the logic for deciding when to make copies
286	// of c/c++/m/f/hfiles is consolidated, use the same logic that Build uses to determine
287	// whether to create the copies in objdir to decide whether to rewrite objdir to the
288	// package directory here.
289	var overlayNonGoRewrites string // rewrites for non-go files
290	hasCgoOverlay := false
291	if fsys.OverlayFile != "" {
292		for _, filename := range a.Package.AllFiles() {
293			path := filename
294			if !filepath.IsAbs(path) {
295				path = filepath.Join(a.Package.Dir, path)
296			}
297			base := filepath.Base(path)
298			isGo := strings.HasSuffix(filename, ".go") || strings.HasSuffix(filename, ".s")
299			isCgo := cgoFiles[filename] || !isGo
300			overlayPath, isOverlay := fsys.OverlayPath(path)
301			if isCgo && isOverlay {
302				hasCgoOverlay = true
303			}
304			if !isCgo && isOverlay {
305				rewrite += overlayPath + "=>" + filepath.Join(rewriteDir, base) + ";"
306			} else if isCgo {
307				// Generate rewrites for non-Go files copied to files in objdir.
308				if filepath.Dir(path) == a.Package.Dir {
309					// This is a file copied to objdir.
310					overlayNonGoRewrites += filepath.Join(objdir, base) + "=>" + filepath.Join(rewriteDir, base) + ";"
311				}
312			} else {
313				// Non-overlay Go files are covered by the a.Package.Dir rewrite rule above.
314			}
315		}
316	}
317	if hasCgoOverlay {
318		rewrite += overlayNonGoRewrites
319	}
320	rewrite += objdir + "=>"
321
322	return rewrite
323}
324
325func asmArgs(a *Action, p *load.Package) []interface{} {
326	// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
327	inc := filepath.Join(cfg.GOROOT, "pkg", "include")
328	pkgpath := pkgPath(a)
329	args := []interface{}{cfg.BuildToolexec, base.Tool("asm"), "-p", pkgpath, "-trimpath", a.trimpath(), "-I", a.Objdir, "-I", inc, "-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch, forcedAsmflags, p.Internal.Asmflags}
330	if p.ImportPath == "runtime" && cfg.Goarch == "386" {
331		for _, arg := range forcedAsmflags {
332			if arg == "-dynlink" {
333				args = append(args, "-D=GOBUILDMODE_shared=1")
334			}
335		}
336	}
337	if objabi.IsRuntimePackagePath(pkgpath) {
338		args = append(args, "-compiling-runtime")
339		if objabi.Regabi_enabled != 0 {
340			// In order to make it easier to port runtime assembly
341			// to the register ABI, we introduce a macro
342			// indicating the experiment is enabled.
343			//
344			// Note: a similar change also appears in
345			// cmd/dist/build.go.
346			//
347			// TODO(austin): Remove this once we commit to the
348			// register ABI (#40724).
349			args = append(args, "-D=GOEXPERIMENT_REGABI=1")
350		}
351	}
352
353	if cfg.Goarch == "mips" || cfg.Goarch == "mipsle" {
354		// Define GOMIPS_value from cfg.GOMIPS.
355		args = append(args, "-D", "GOMIPS_"+cfg.GOMIPS)
356	}
357
358	if cfg.Goarch == "mips64" || cfg.Goarch == "mips64le" {
359		// Define GOMIPS64_value from cfg.GOMIPS64.
360		args = append(args, "-D", "GOMIPS64_"+cfg.GOMIPS64)
361	}
362
363	return args
364}
365
366func (gcToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) {
367	p := a.Package
368	args := asmArgs(a, p)
369
370	var ofiles []string
371	for _, sfile := range sfiles {
372		overlayPath, _ := fsys.OverlayPath(mkAbs(p.Dir, sfile))
373		ofile := a.Objdir + sfile[:len(sfile)-len(".s")] + ".o"
374		ofiles = append(ofiles, ofile)
375		args1 := append(args, "-o", ofile, overlayPath)
376		if err := b.run(a, p.Dir, p.ImportPath, nil, args1...); err != nil {
377			return nil, err
378		}
379	}
380	return ofiles, nil
381}
382
383func (gcToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
384	mkSymabis := func(p *load.Package, sfiles []string, path string) error {
385		args := asmArgs(a, p)
386		args = append(args, "-gensymabis", "-o", path)
387		for _, sfile := range sfiles {
388			if p.ImportPath == "runtime/cgo" && strings.HasPrefix(sfile, "gcc_") {
389				continue
390			}
391			op, _ := fsys.OverlayPath(mkAbs(p.Dir, sfile))
392			args = append(args, op)
393		}
394
395		// Supply an empty go_asm.h as if the compiler had been run.
396		// -gensymabis parsing is lax enough that we don't need the
397		// actual definitions that would appear in go_asm.h.
398		if err := b.writeFile(a.Objdir+"go_asm.h", nil); err != nil {
399			return err
400		}
401
402		return b.run(a, p.Dir, p.ImportPath, nil, args...)
403	}
404
405	var symabis string // Only set if we actually create the file
406	p := a.Package
407	if len(sfiles) != 0 {
408		symabis = a.Objdir + "symabis"
409		if err := mkSymabis(p, sfiles, symabis); err != nil {
410			return "", err
411		}
412	}
413
414	return symabis, nil
415}
416
417// toolVerify checks that the command line args writes the same output file
418// if run using newTool instead.
419// Unused now but kept around for future use.
420func toolVerify(a *Action, b *Builder, p *load.Package, newTool string, ofile string, args []interface{}) error {
421	newArgs := make([]interface{}, len(args))
422	copy(newArgs, args)
423	newArgs[1] = base.Tool(newTool)
424	newArgs[3] = ofile + ".new" // x.6 becomes x.6.new
425	if err := b.run(a, p.Dir, p.ImportPath, nil, newArgs...); err != nil {
426		return err
427	}
428	data1, err := os.ReadFile(ofile)
429	if err != nil {
430		return err
431	}
432	data2, err := os.ReadFile(ofile + ".new")
433	if err != nil {
434		return err
435	}
436	if !bytes.Equal(data1, data2) {
437		return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(str.StringList(args...), " "), strings.Join(str.StringList(newArgs...), " "))
438	}
439	os.Remove(ofile + ".new")
440	return nil
441}
442
443func (gcToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
444	var absOfiles []string
445	for _, f := range ofiles {
446		absOfiles = append(absOfiles, mkAbs(a.Objdir, f))
447	}
448	absAfile := mkAbs(a.Objdir, afile)
449
450	// The archive file should have been created by the compiler.
451	// Since it used to not work that way, verify.
452	if !cfg.BuildN {
453		if _, err := os.Stat(absAfile); err != nil {
454			base.Fatalf("os.Stat of archive file failed: %v", err)
455		}
456	}
457
458	p := a.Package
459	if cfg.BuildN || cfg.BuildX {
460		cmdline := str.StringList(base.Tool("pack"), "r", absAfile, absOfiles)
461		b.Showcmd(p.Dir, "%s # internal", joinUnambiguously(cmdline))
462	}
463	if cfg.BuildN {
464		return nil
465	}
466	if err := packInternal(absAfile, absOfiles); err != nil {
467		b.showOutput(a, p.Dir, p.Desc(), err.Error()+"\n")
468		return errPrintedOutput
469	}
470	return nil
471}
472
473func packInternal(afile string, ofiles []string) error {
474	dst, err := os.OpenFile(afile, os.O_WRONLY|os.O_APPEND, 0)
475	if err != nil {
476		return err
477	}
478	defer dst.Close() // only for error returns or panics
479	w := bufio.NewWriter(dst)
480
481	for _, ofile := range ofiles {
482		src, err := os.Open(ofile)
483		if err != nil {
484			return err
485		}
486		fi, err := src.Stat()
487		if err != nil {
488			src.Close()
489			return err
490		}
491		// Note: Not using %-16.16s format because we care
492		// about bytes, not runes.
493		name := fi.Name()
494		if len(name) > 16 {
495			name = name[:16]
496		} else {
497			name += strings.Repeat(" ", 16-len(name))
498		}
499		size := fi.Size()
500		fmt.Fprintf(w, "%s%-12d%-6d%-6d%-8o%-10d`\n",
501			name, 0, 0, 0, 0644, size)
502		n, err := io.Copy(w, src)
503		src.Close()
504		if err == nil && n < size {
505			err = io.ErrUnexpectedEOF
506		} else if err == nil && n > size {
507			err = fmt.Errorf("file larger than size reported by stat")
508		}
509		if err != nil {
510			return fmt.Errorf("copying %s to %s: %v", ofile, afile, err)
511		}
512		if size&1 != 0 {
513			w.WriteByte(0)
514		}
515	}
516
517	if err := w.Flush(); err != nil {
518		return err
519	}
520	return dst.Close()
521}
522
523// setextld sets the appropriate linker flags for the specified compiler.
524func setextld(ldflags []string, compiler []string) []string {
525	for _, f := range ldflags {
526		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
527			// don't override -extld if supplied
528			return ldflags
529		}
530	}
531	ldflags = append(ldflags, "-extld="+compiler[0])
532	if len(compiler) > 1 {
533		extldflags := false
534		add := strings.Join(compiler[1:], " ")
535		for i, f := range ldflags {
536			if f == "-extldflags" && i+1 < len(ldflags) {
537				ldflags[i+1] = add + " " + ldflags[i+1]
538				extldflags = true
539				break
540			} else if strings.HasPrefix(f, "-extldflags=") {
541				ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
542				extldflags = true
543				break
544			}
545		}
546		if !extldflags {
547			ldflags = append(ldflags, "-extldflags="+add)
548		}
549	}
550	return ldflags
551}
552
553// pluginPath computes the package path for a plugin main package.
554//
555// This is typically the import path of the main package p, unless the
556// plugin is being built directly from source files. In that case we
557// combine the package build ID with the contents of the main package
558// source files. This allows us to identify two different plugins
559// built from two source files with the same name.
560func pluginPath(a *Action) string {
561	p := a.Package
562	if p.ImportPath != "command-line-arguments" {
563		return p.ImportPath
564	}
565	h := sha1.New()
566	buildID := a.buildID
567	if a.Mode == "link" {
568		// For linking, use the main package's build ID instead of
569		// the binary's build ID, so it is the same hash used in
570		// compiling and linking.
571		// When compiling, we use actionID/actionID (instead of
572		// actionID/contentID) as a temporary build ID to compute
573		// the hash. Do the same here. (See buildid.go:useCache)
574		// The build ID matters because it affects the overall hash
575		// in the plugin's pseudo-import path returned below.
576		// We need to use the same import path when compiling and linking.
577		id := strings.Split(buildID, buildIDSeparator)
578		buildID = id[1] + buildIDSeparator + id[1]
579	}
580	fmt.Fprintf(h, "build ID: %s\n", buildID)
581	for _, file := range str.StringList(p.GoFiles, p.CgoFiles, p.SFiles) {
582		data, err := os.ReadFile(filepath.Join(p.Dir, file))
583		if err != nil {
584			base.Fatalf("go: %s", err)
585		}
586		h.Write(data)
587	}
588	return fmt.Sprintf("plugin/unnamed-%x", h.Sum(nil))
589}
590
591func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error {
592	cxx := len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0
593	for _, a := range root.Deps {
594		if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) {
595			cxx = true
596		}
597	}
598	var ldflags []string
599	if cfg.BuildContext.InstallSuffix != "" {
600		ldflags = append(ldflags, "-installsuffix", cfg.BuildContext.InstallSuffix)
601	}
602	if root.Package.Internal.OmitDebug {
603		ldflags = append(ldflags, "-s", "-w")
604	}
605	if cfg.BuildBuildmode == "plugin" {
606		ldflags = append(ldflags, "-pluginpath", pluginPath(root))
607	}
608
609	// Store BuildID inside toolchain binaries as a unique identifier of the
610	// tool being run, for use by content-based staleness determination.
611	if root.Package.Goroot && strings.HasPrefix(root.Package.ImportPath, "cmd/") {
612		// External linking will include our build id in the external
613		// linker's build id, which will cause our build id to not
614		// match the next time the tool is built.
615		// Rely on the external build id instead.
616		if !sys.MustLinkExternal(cfg.Goos, cfg.Goarch) {
617			ldflags = append(ldflags, "-X=cmd/internal/objabi.buildID="+root.buildID)
618		}
619	}
620
621	// If the user has not specified the -extld option, then specify the
622	// appropriate linker. In case of C++ code, use the compiler named
623	// by the CXX environment variable or defaultCXX if CXX is not set.
624	// Else, use the CC environment variable and defaultCC as fallback.
625	var compiler []string
626	if cxx {
627		compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
628	} else {
629		compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
630	}
631	ldflags = append(ldflags, "-buildmode="+ldBuildmode)
632	if root.buildID != "" {
633		ldflags = append(ldflags, "-buildid="+root.buildID)
634	}
635	ldflags = append(ldflags, forcedLdflags...)
636	ldflags = append(ldflags, root.Package.Internal.Ldflags...)
637	ldflags = setextld(ldflags, compiler)
638
639	// On OS X when using external linking to build a shared library,
640	// the argument passed here to -o ends up recorded in the final
641	// shared library in the LC_ID_DYLIB load command.
642	// To avoid putting the temporary output directory name there
643	// (and making the resulting shared library useless),
644	// run the link in the output directory so that -o can name
645	// just the final path element.
646	// On Windows, DLL file name is recorded in PE file
647	// export section, so do like on OS X.
648	dir := "."
649	if (cfg.Goos == "darwin" || cfg.Goos == "windows") && cfg.BuildBuildmode == "c-shared" {
650		dir, out = filepath.Split(out)
651	}
652
653	env := []string{}
654	if cfg.BuildTrimpath {
655		env = append(env, "GOROOT_FINAL="+trimPathGoRootFinal)
656	}
657	return b.run(root, dir, root.Package.ImportPath, env, cfg.BuildToolexec, base.Tool("link"), "-o", out, "-importcfg", importcfg, ldflags, mainpkg)
658}
659
660func (gcToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
661	ldflags := []string{"-installsuffix", cfg.BuildContext.InstallSuffix}
662	ldflags = append(ldflags, "-buildmode=shared")
663	ldflags = append(ldflags, forcedLdflags...)
664	ldflags = append(ldflags, root.Package.Internal.Ldflags...)
665	cxx := false
666	for _, a := range allactions {
667		if a.Package != nil && (len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0) {
668			cxx = true
669		}
670	}
671	// If the user has not specified the -extld option, then specify the
672	// appropriate linker. In case of C++ code, use the compiler named
673	// by the CXX environment variable or defaultCXX if CXX is not set.
674	// Else, use the CC environment variable and defaultCC as fallback.
675	var compiler []string
676	if cxx {
677		compiler = envList("CXX", cfg.DefaultCXX(cfg.Goos, cfg.Goarch))
678	} else {
679		compiler = envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
680	}
681	ldflags = setextld(ldflags, compiler)
682	for _, d := range toplevelactions {
683		if !strings.HasSuffix(d.Target, ".a") { // omit unsafe etc and actions for other shared libraries
684			continue
685		}
686		ldflags = append(ldflags, d.Package.ImportPath+"="+d.Target)
687	}
688	return b.run(root, ".", out, nil, cfg.BuildToolexec, base.Tool("link"), "-o", out, "-importcfg", importcfg, ldflags)
689}
690
691func (gcToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
692	return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(a.Package.Dir, cfile))
693}
694