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