Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/go/internal/work/gccgo.go

Documentation: cmd/go/internal/work

     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  
     5  package work
     6  
     7  import (
     8  	"fmt"
     9  	exec "internal/execabs"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  	"sync"
    14  
    15  	"cmd/go/internal/base"
    16  	"cmd/go/internal/cfg"
    17  	"cmd/go/internal/fsys"
    18  	"cmd/go/internal/load"
    19  	"cmd/go/internal/str"
    20  	"cmd/internal/pkgpath"
    21  )
    22  
    23  // The Gccgo toolchain.
    24  
    25  type gccgoToolchain struct{}
    26  
    27  var GccgoName, GccgoBin string
    28  var gccgoErr error
    29  
    30  func init() {
    31  	GccgoName = cfg.Getenv("GCCGO")
    32  	if GccgoName == "" {
    33  		GccgoName = "gccgo"
    34  	}
    35  	GccgoBin, gccgoErr = exec.LookPath(GccgoName)
    36  }
    37  
    38  func (gccgoToolchain) compiler() string {
    39  	checkGccgoBin()
    40  	return GccgoBin
    41  }
    42  
    43  func (gccgoToolchain) linker() string {
    44  	checkGccgoBin()
    45  	return GccgoBin
    46  }
    47  
    48  func (gccgoToolchain) ar() string {
    49  	ar := cfg.Getenv("AR")
    50  	if ar == "" {
    51  		ar = "ar"
    52  	}
    53  	return ar
    54  }
    55  
    56  func checkGccgoBin() {
    57  	if gccgoErr == nil {
    58  		return
    59  	}
    60  	fmt.Fprintf(os.Stderr, "cmd/go: gccgo: %s\n", gccgoErr)
    61  	base.SetExitStatus(2)
    62  	base.Exit()
    63  }
    64  
    65  func (tools gccgoToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg []byte, symabis string, asmhdr bool, gofiles []string) (ofile string, output []byte, err error) {
    66  	p := a.Package
    67  	objdir := a.Objdir
    68  	out := "_go_.o"
    69  	ofile = objdir + out
    70  	gcargs := []string{"-g"}
    71  	gcargs = append(gcargs, b.gccArchArgs()...)
    72  	gcargs = append(gcargs, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build")
    73  	gcargs = append(gcargs, "-gno-record-gcc-switches")
    74  	if pkgpath := gccgoPkgpath(p); pkgpath != "" {
    75  		gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
    76  	}
    77  	if p.Internal.LocalPrefix != "" {
    78  		gcargs = append(gcargs, "-fgo-relative-import-path="+p.Internal.LocalPrefix)
    79  	}
    80  
    81  	args := str.StringList(tools.compiler(), "-c", gcargs, "-o", ofile, forcedGccgoflags)
    82  	if importcfg != nil {
    83  		if b.gccSupportsFlag(args[:1], "-fgo-importcfg=/dev/null") {
    84  			if err := b.writeFile(objdir+"importcfg", importcfg); err != nil {
    85  				return "", nil, err
    86  			}
    87  			args = append(args, "-fgo-importcfg="+objdir+"importcfg")
    88  		} else {
    89  			root := objdir + "_importcfgroot_"
    90  			if err := buildImportcfgSymlinks(b, root, importcfg); err != nil {
    91  				return "", nil, err
    92  			}
    93  			args = append(args, "-I", root)
    94  		}
    95  	}
    96  	if embedcfg != nil && b.gccSupportsFlag(args[:1], "-fgo-embedcfg=/dev/null") {
    97  		if err := b.writeFile(objdir+"embedcfg", embedcfg); err != nil {
    98  			return "", nil, err
    99  		}
   100  		args = append(args, "-fgo-embedcfg="+objdir+"embedcfg")
   101  	}
   102  
   103  	if b.gccSupportsFlag(args[:1], "-ffile-prefix-map=a=b") {
   104  		if cfg.BuildTrimpath {
   105  			args = append(args, "-ffile-prefix-map="+base.Cwd()+"=.")
   106  			args = append(args, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build")
   107  		}
   108  		if fsys.OverlayFile != "" {
   109  			for _, name := range gofiles {
   110  				absPath := mkAbs(p.Dir, name)
   111  				overlayPath, ok := fsys.OverlayPath(absPath)
   112  				if !ok {
   113  					continue
   114  				}
   115  				toPath := absPath
   116  				// gccgo only applies the last matching rule, so also handle the case where
   117  				// BuildTrimpath is true and the path is relative to base.Cwd().
   118  				if cfg.BuildTrimpath && str.HasFilePathPrefix(toPath, base.Cwd()) {
   119  					toPath = "." + toPath[len(base.Cwd()):]
   120  				}
   121  				args = append(args, "-ffile-prefix-map="+overlayPath+"="+toPath)
   122  			}
   123  		}
   124  	}
   125  
   126  	args = append(args, a.Package.Internal.Gccgoflags...)
   127  	for _, f := range gofiles {
   128  		f := mkAbs(p.Dir, f)
   129  		// Overlay files if necessary.
   130  		// See comment on gctoolchain.gc about overlay TODOs
   131  		f, _ = fsys.OverlayPath(f)
   132  		args = append(args, f)
   133  	}
   134  
   135  	output, err = b.runOut(a, p.Dir, nil, args)
   136  	return ofile, output, err
   137  }
   138  
   139  // buildImportcfgSymlinks builds in root a tree of symlinks
   140  // implementing the directives from importcfg.
   141  // This serves as a temporary transition mechanism until
   142  // we can depend on gccgo reading an importcfg directly.
   143  // (The Go 1.9 and later gc compilers already do.)
   144  func buildImportcfgSymlinks(b *Builder, root string, importcfg []byte) error {
   145  	for lineNum, line := range strings.Split(string(importcfg), "\n") {
   146  		lineNum++ // 1-based
   147  		line = strings.TrimSpace(line)
   148  		if line == "" {
   149  			continue
   150  		}
   151  		if line == "" || strings.HasPrefix(line, "#") {
   152  			continue
   153  		}
   154  		var verb, args string
   155  		if i := strings.Index(line, " "); i < 0 {
   156  			verb = line
   157  		} else {
   158  			verb, args = line[:i], strings.TrimSpace(line[i+1:])
   159  		}
   160  		var before, after string
   161  		if i := strings.Index(args, "="); i >= 0 {
   162  			before, after = args[:i], args[i+1:]
   163  		}
   164  		switch verb {
   165  		default:
   166  			base.Fatalf("importcfg:%d: unknown directive %q", lineNum, verb)
   167  		case "packagefile":
   168  			if before == "" || after == "" {
   169  				return fmt.Errorf(`importcfg:%d: invalid packagefile: syntax is "packagefile path=filename": %s`, lineNum, line)
   170  			}
   171  			archive := gccgoArchive(root, before)
   172  			if err := b.Mkdir(filepath.Dir(archive)); err != nil {
   173  				return err
   174  			}
   175  			if err := b.Symlink(after, archive); err != nil {
   176  				return err
   177  			}
   178  		case "importmap":
   179  			if before == "" || after == "" {
   180  				return fmt.Errorf(`importcfg:%d: invalid importmap: syntax is "importmap old=new": %s`, lineNum, line)
   181  			}
   182  			beforeA := gccgoArchive(root, before)
   183  			afterA := gccgoArchive(root, after)
   184  			if err := b.Mkdir(filepath.Dir(beforeA)); err != nil {
   185  				return err
   186  			}
   187  			if err := b.Mkdir(filepath.Dir(afterA)); err != nil {
   188  				return err
   189  			}
   190  			if err := b.Symlink(afterA, beforeA); err != nil {
   191  				return err
   192  			}
   193  		case "packageshlib":
   194  			return fmt.Errorf("gccgo -importcfg does not support shared libraries")
   195  		}
   196  	}
   197  	return nil
   198  }
   199  
   200  func (tools gccgoToolchain) asm(b *Builder, a *Action, sfiles []string) ([]string, error) {
   201  	p := a.Package
   202  	var ofiles []string
   203  	for _, sfile := range sfiles {
   204  		base := filepath.Base(sfile)
   205  		ofile := a.Objdir + base[:len(base)-len(".s")] + ".o"
   206  		ofiles = append(ofiles, ofile)
   207  		sfile, _ = fsys.OverlayPath(mkAbs(p.Dir, sfile))
   208  		defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch}
   209  		if pkgpath := tools.gccgoCleanPkgpath(b, p); pkgpath != "" {
   210  			defs = append(defs, `-D`, `GOPKGPATH=`+pkgpath)
   211  		}
   212  		defs = tools.maybePIC(defs)
   213  		defs = append(defs, b.gccArchArgs()...)
   214  		err := b.run(a, p.Dir, p.ImportPath, nil, tools.compiler(), "-xassembler-with-cpp", "-I", a.Objdir, "-c", "-o", ofile, defs, sfile)
   215  		if err != nil {
   216  			return nil, err
   217  		}
   218  	}
   219  	return ofiles, nil
   220  }
   221  
   222  func (gccgoToolchain) symabis(b *Builder, a *Action, sfiles []string) (string, error) {
   223  	return "", nil
   224  }
   225  
   226  func gccgoArchive(basedir, imp string) string {
   227  	end := filepath.FromSlash(imp + ".a")
   228  	afile := filepath.Join(basedir, end)
   229  	// add "lib" to the final element
   230  	return filepath.Join(filepath.Dir(afile), "lib"+filepath.Base(afile))
   231  }
   232  
   233  func (tools gccgoToolchain) pack(b *Builder, a *Action, afile string, ofiles []string) error {
   234  	p := a.Package
   235  	objdir := a.Objdir
   236  	var absOfiles []string
   237  	for _, f := range ofiles {
   238  		absOfiles = append(absOfiles, mkAbs(objdir, f))
   239  	}
   240  	var arArgs []string
   241  	if cfg.Goos == "aix" && cfg.Goarch == "ppc64" {
   242  		// AIX puts both 32-bit and 64-bit objects in the same archive.
   243  		// Tell the AIX "ar" command to only care about 64-bit objects.
   244  		arArgs = []string{"-X64"}
   245  	}
   246  	absAfile := mkAbs(objdir, afile)
   247  	// Try with D modifier first, then without if that fails.
   248  	output, err := b.runOut(a, p.Dir, nil, tools.ar(), arArgs, "rcD", absAfile, absOfiles)
   249  	if err != nil {
   250  		return b.run(a, p.Dir, p.ImportPath, nil, tools.ar(), arArgs, "rc", absAfile, absOfiles)
   251  	}
   252  
   253  	if len(output) > 0 {
   254  		// Show the output if there is any even without errors.
   255  		b.showOutput(a, p.Dir, p.ImportPath, b.processOutput(output))
   256  	}
   257  
   258  	return nil
   259  }
   260  
   261  func (tools gccgoToolchain) link(b *Builder, root *Action, out, importcfg string, allactions []*Action, buildmode, desc string) error {
   262  	// gccgo needs explicit linking with all package dependencies,
   263  	// and all LDFLAGS from cgo dependencies.
   264  	afiles := []string{}
   265  	shlibs := []string{}
   266  	ldflags := b.gccArchArgs()
   267  	cgoldflags := []string{}
   268  	usesCgo := false
   269  	cxx := false
   270  	objc := false
   271  	fortran := false
   272  	if root.Package != nil {
   273  		cxx = len(root.Package.CXXFiles) > 0 || len(root.Package.SwigCXXFiles) > 0
   274  		objc = len(root.Package.MFiles) > 0
   275  		fortran = len(root.Package.FFiles) > 0
   276  	}
   277  
   278  	readCgoFlags := func(flagsFile string) error {
   279  		flags, err := os.ReadFile(flagsFile)
   280  		if err != nil {
   281  			return err
   282  		}
   283  		const ldflagsPrefix = "_CGO_LDFLAGS="
   284  		for _, line := range strings.Split(string(flags), "\n") {
   285  			if strings.HasPrefix(line, ldflagsPrefix) {
   286  				newFlags := strings.Fields(line[len(ldflagsPrefix):])
   287  				for _, flag := range newFlags {
   288  					// Every _cgo_flags file has -g and -O2 in _CGO_LDFLAGS
   289  					// but they don't mean anything to the linker so filter
   290  					// them out.
   291  					if flag != "-g" && !strings.HasPrefix(flag, "-O") {
   292  						cgoldflags = append(cgoldflags, flag)
   293  					}
   294  				}
   295  			}
   296  		}
   297  		return nil
   298  	}
   299  
   300  	var arArgs []string
   301  	if cfg.Goos == "aix" && cfg.Goarch == "ppc64" {
   302  		// AIX puts both 32-bit and 64-bit objects in the same archive.
   303  		// Tell the AIX "ar" command to only care about 64-bit objects.
   304  		arArgs = []string{"-X64"}
   305  	}
   306  
   307  	newID := 0
   308  	readAndRemoveCgoFlags := func(archive string) (string, error) {
   309  		newID++
   310  		newArchive := root.Objdir + fmt.Sprintf("_pkg%d_.a", newID)
   311  		if err := b.copyFile(newArchive, archive, 0666, false); err != nil {
   312  			return "", err
   313  		}
   314  		if cfg.BuildN || cfg.BuildX {
   315  			b.Showcmd("", "ar d %s _cgo_flags", newArchive)
   316  			if cfg.BuildN {
   317  				// TODO(rsc): We could do better about showing the right _cgo_flags even in -n mode.
   318  				// Either the archive is already built and we can read them out,
   319  				// or we're printing commands to build the archive and can
   320  				// forward the _cgo_flags directly to this step.
   321  				return "", nil
   322  			}
   323  		}
   324  		err := b.run(root, root.Objdir, desc, nil, tools.ar(), arArgs, "x", newArchive, "_cgo_flags")
   325  		if err != nil {
   326  			return "", err
   327  		}
   328  		err = b.run(root, ".", desc, nil, tools.ar(), arArgs, "d", newArchive, "_cgo_flags")
   329  		if err != nil {
   330  			return "", err
   331  		}
   332  		err = readCgoFlags(filepath.Join(root.Objdir, "_cgo_flags"))
   333  		if err != nil {
   334  			return "", err
   335  		}
   336  		return newArchive, nil
   337  	}
   338  
   339  	// If using -linkshared, find the shared library deps.
   340  	haveShlib := make(map[string]bool)
   341  	targetBase := filepath.Base(root.Target)
   342  	if cfg.BuildLinkshared {
   343  		for _, a := range root.Deps {
   344  			p := a.Package
   345  			if p == nil || p.Shlib == "" {
   346  				continue
   347  			}
   348  
   349  			// The .a we are linking into this .so
   350  			// will have its Shlib set to this .so.
   351  			// Don't start thinking we want to link
   352  			// this .so into itself.
   353  			base := filepath.Base(p.Shlib)
   354  			if base != targetBase {
   355  				haveShlib[base] = true
   356  			}
   357  		}
   358  	}
   359  
   360  	// Arrange the deps into afiles and shlibs.
   361  	addedShlib := make(map[string]bool)
   362  	for _, a := range root.Deps {
   363  		p := a.Package
   364  		if p != nil && p.Shlib != "" && haveShlib[filepath.Base(p.Shlib)] {
   365  			// This is a package linked into a shared
   366  			// library that we will put into shlibs.
   367  			continue
   368  		}
   369  
   370  		if haveShlib[filepath.Base(a.Target)] {
   371  			// This is a shared library we want to link against.
   372  			if !addedShlib[a.Target] {
   373  				shlibs = append(shlibs, a.Target)
   374  				addedShlib[a.Target] = true
   375  			}
   376  			continue
   377  		}
   378  
   379  		if p != nil {
   380  			target := a.built
   381  			if p.UsesCgo() || p.UsesSwig() {
   382  				var err error
   383  				target, err = readAndRemoveCgoFlags(target)
   384  				if err != nil {
   385  					continue
   386  				}
   387  			}
   388  
   389  			afiles = append(afiles, target)
   390  		}
   391  	}
   392  
   393  	for _, a := range allactions {
   394  		// Gather CgoLDFLAGS, but not from standard packages.
   395  		// The go tool can dig up runtime/cgo from GOROOT and
   396  		// think that it should use its CgoLDFLAGS, but gccgo
   397  		// doesn't use runtime/cgo.
   398  		if a.Package == nil {
   399  			continue
   400  		}
   401  		if !a.Package.Standard {
   402  			cgoldflags = append(cgoldflags, a.Package.CgoLDFLAGS...)
   403  		}
   404  		if len(a.Package.CgoFiles) > 0 {
   405  			usesCgo = true
   406  		}
   407  		if a.Package.UsesSwig() {
   408  			usesCgo = true
   409  		}
   410  		if len(a.Package.CXXFiles) > 0 || len(a.Package.SwigCXXFiles) > 0 {
   411  			cxx = true
   412  		}
   413  		if len(a.Package.MFiles) > 0 {
   414  			objc = true
   415  		}
   416  		if len(a.Package.FFiles) > 0 {
   417  			fortran = true
   418  		}
   419  	}
   420  
   421  	wholeArchive := []string{"-Wl,--whole-archive"}
   422  	noWholeArchive := []string{"-Wl,--no-whole-archive"}
   423  	if cfg.Goos == "aix" {
   424  		wholeArchive = nil
   425  		noWholeArchive = nil
   426  	}
   427  	ldflags = append(ldflags, wholeArchive...)
   428  	ldflags = append(ldflags, afiles...)
   429  	ldflags = append(ldflags, noWholeArchive...)
   430  
   431  	ldflags = append(ldflags, cgoldflags...)
   432  	ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
   433  	if root.Package != nil {
   434  		ldflags = append(ldflags, root.Package.CgoLDFLAGS...)
   435  	}
   436  	if cfg.Goos != "aix" {
   437  		ldflags = str.StringList("-Wl,-(", ldflags, "-Wl,-)")
   438  	}
   439  
   440  	if root.buildID != "" {
   441  		// On systems that normally use gold or the GNU linker,
   442  		// use the --build-id option to write a GNU build ID note.
   443  		switch cfg.Goos {
   444  		case "android", "dragonfly", "linux", "netbsd":
   445  			ldflags = append(ldflags, fmt.Sprintf("-Wl,--build-id=0x%x", root.buildID))
   446  		}
   447  	}
   448  
   449  	var rLibPath string
   450  	if cfg.Goos == "aix" {
   451  		rLibPath = "-Wl,-blibpath="
   452  	} else {
   453  		rLibPath = "-Wl,-rpath="
   454  	}
   455  	for _, shlib := range shlibs {
   456  		ldflags = append(
   457  			ldflags,
   458  			"-L"+filepath.Dir(shlib),
   459  			rLibPath+filepath.Dir(shlib),
   460  			"-l"+strings.TrimSuffix(
   461  				strings.TrimPrefix(filepath.Base(shlib), "lib"),
   462  				".so"))
   463  	}
   464  
   465  	var realOut string
   466  	goLibBegin := str.StringList(wholeArchive, "-lgolibbegin", noWholeArchive)
   467  	switch buildmode {
   468  	case "exe":
   469  		if usesCgo && cfg.Goos == "linux" {
   470  			ldflags = append(ldflags, "-Wl,-E")
   471  		}
   472  
   473  	case "c-archive":
   474  		// Link the Go files into a single .o, and also link
   475  		// in -lgolibbegin.
   476  		//
   477  		// We need to use --whole-archive with -lgolibbegin
   478  		// because it doesn't define any symbols that will
   479  		// cause the contents to be pulled in; it's just
   480  		// initialization code.
   481  		//
   482  		// The user remains responsible for linking against
   483  		// -lgo -lpthread -lm in the final link. We can't use
   484  		// -r to pick them up because we can't combine
   485  		// split-stack and non-split-stack code in a single -r
   486  		// link, and libgo picks up non-split-stack code from
   487  		// libffi.
   488  		ldflags = append(ldflags, "-Wl,-r", "-nostdlib")
   489  		ldflags = append(ldflags, goLibBegin...)
   490  
   491  		if nopie := b.gccNoPie([]string{tools.linker()}); nopie != "" {
   492  			ldflags = append(ldflags, nopie)
   493  		}
   494  
   495  		// We are creating an object file, so we don't want a build ID.
   496  		if root.buildID == "" {
   497  			ldflags = b.disableBuildID(ldflags)
   498  		}
   499  
   500  		realOut = out
   501  		out = out + ".o"
   502  
   503  	case "c-shared":
   504  		ldflags = append(ldflags, "-shared", "-nostdlib")
   505  		ldflags = append(ldflags, goLibBegin...)
   506  		ldflags = append(ldflags, "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc")
   507  
   508  	case "shared":
   509  		if cfg.Goos != "aix" {
   510  			ldflags = append(ldflags, "-zdefs")
   511  		}
   512  		ldflags = append(ldflags, "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
   513  
   514  	default:
   515  		base.Fatalf("-buildmode=%s not supported for gccgo", buildmode)
   516  	}
   517  
   518  	switch buildmode {
   519  	case "exe", "c-shared":
   520  		if cxx {
   521  			ldflags = append(ldflags, "-lstdc++")
   522  		}
   523  		if objc {
   524  			ldflags = append(ldflags, "-lobjc")
   525  		}
   526  		if fortran {
   527  			fc := cfg.Getenv("FC")
   528  			if fc == "" {
   529  				fc = "gfortran"
   530  			}
   531  			// support gfortran out of the box and let others pass the correct link options
   532  			// via CGO_LDFLAGS
   533  			if strings.Contains(fc, "gfortran") {
   534  				ldflags = append(ldflags, "-lgfortran")
   535  			}
   536  		}
   537  	}
   538  
   539  	if err := b.run(root, ".", desc, nil, tools.linker(), "-o", out, ldflags, forcedGccgoflags, root.Package.Internal.Gccgoflags); err != nil {
   540  		return err
   541  	}
   542  
   543  	switch buildmode {
   544  	case "c-archive":
   545  		if err := b.run(root, ".", desc, nil, tools.ar(), arArgs, "rc", realOut, out); err != nil {
   546  			return err
   547  		}
   548  	}
   549  	return nil
   550  }
   551  
   552  func (tools gccgoToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string) error {
   553  	return tools.link(b, root, out, importcfg, root.Deps, ldBuildmode, root.Package.ImportPath)
   554  }
   555  
   556  func (tools gccgoToolchain) ldShared(b *Builder, root *Action, toplevelactions []*Action, out, importcfg string, allactions []*Action) error {
   557  	return tools.link(b, root, out, importcfg, allactions, "shared", out)
   558  }
   559  
   560  func (tools gccgoToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
   561  	p := a.Package
   562  	inc := filepath.Join(cfg.GOROOT, "pkg", "include")
   563  	cfile = mkAbs(p.Dir, cfile)
   564  	defs := []string{"-D", "GOOS_" + cfg.Goos, "-D", "GOARCH_" + cfg.Goarch}
   565  	defs = append(defs, b.gccArchArgs()...)
   566  	if pkgpath := tools.gccgoCleanPkgpath(b, p); pkgpath != "" {
   567  		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
   568  	}
   569  	compiler := envList("CC", cfg.DefaultCC(cfg.Goos, cfg.Goarch))
   570  	if b.gccSupportsFlag(compiler, "-fsplit-stack") {
   571  		defs = append(defs, "-fsplit-stack")
   572  	}
   573  	defs = tools.maybePIC(defs)
   574  	if b.gccSupportsFlag(compiler, "-ffile-prefix-map=a=b") {
   575  		defs = append(defs, "-ffile-prefix-map="+base.Cwd()+"=.")
   576  		defs = append(defs, "-ffile-prefix-map="+b.WorkDir+"=/tmp/go-build")
   577  	} else if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
   578  		defs = append(defs, "-fdebug-prefix-map="+b.WorkDir+"=/tmp/go-build")
   579  	}
   580  	if b.gccSupportsFlag(compiler, "-gno-record-gcc-switches") {
   581  		defs = append(defs, "-gno-record-gcc-switches")
   582  	}
   583  	return b.run(a, p.Dir, p.ImportPath, nil, compiler, "-Wall", "-g",
   584  		"-I", a.Objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
   585  }
   586  
   587  // maybePIC adds -fPIC to the list of arguments if needed.
   588  func (tools gccgoToolchain) maybePIC(args []string) []string {
   589  	switch cfg.BuildBuildmode {
   590  	case "c-shared", "shared", "plugin":
   591  		args = append(args, "-fPIC")
   592  	}
   593  	return args
   594  }
   595  
   596  func gccgoPkgpath(p *load.Package) string {
   597  	if p.Internal.Build.IsCommand() && !p.Internal.ForceLibrary {
   598  		return ""
   599  	}
   600  	return p.ImportPath
   601  }
   602  
   603  var gccgoToSymbolFuncOnce sync.Once
   604  var gccgoToSymbolFunc func(string) string
   605  
   606  func (tools gccgoToolchain) gccgoCleanPkgpath(b *Builder, p *load.Package) string {
   607  	gccgoToSymbolFuncOnce.Do(func() {
   608  		fn, err := pkgpath.ToSymbolFunc(tools.compiler(), b.WorkDir)
   609  		if err != nil {
   610  			fmt.Fprintf(os.Stderr, "cmd/go: %v\n", err)
   611  			base.SetExitStatus(2)
   612  			base.Exit()
   613  		}
   614  		gccgoToSymbolFunc = fn
   615  	})
   616  
   617  	return gccgoToSymbolFunc(gccgoPkgpath(p))
   618  }
   619  

View as plain text