github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/cmd/gllgo/gllgo.go (about) 1 //===- gllgo.go - gccgo-like driver for llgo ------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This is llgo's driver. It has a gccgo-like interface in order to easily 11 // interoperate with the "go" command and the libgo build system. 12 // 13 //===----------------------------------------------------------------------===// 14 15 package main 16 17 /* 18 #include "config.h" 19 */ 20 import "C" 21 22 import ( 23 "errors" 24 "fmt" 25 "go/scanner" 26 "go/token" 27 "io/ioutil" 28 "log" 29 "os" 30 "os/exec" 31 "path/filepath" 32 "strings" 33 34 "llvm.org/llgo/debug" 35 "llvm.org/llgo/driver" 36 "llvm.org/llgo/irgen" 37 "llvm.org/llvm/bindings/go/llvm" 38 ) 39 40 const LibDirSuffix = C.LLVM_LIBDIR_SUFFIX 41 42 func report(err error) { 43 if list, ok := err.(scanner.ErrorList); ok { 44 for _, e := range list { 45 fmt.Fprintf(os.Stderr, "%s\n", e) 46 } 47 } else if err != nil { 48 fmt.Fprintf(os.Stderr, "gllgo: error: %s\n", err) 49 } 50 } 51 52 func llvmVersion() string { 53 return strings.Replace(llvm.Version, "svn", "", 1) 54 } 55 56 func displayVersion() { 57 fmt.Printf("llgo version %s (%s)\n\n", llvmVersion(), irgen.GoVersion()) 58 os.Exit(0) 59 } 60 61 func initCompiler(opts *driverOptions) (*irgen.Compiler, error) { 62 importPaths := make([]string, len(opts.importPaths)+len(opts.libPaths)) 63 copy(importPaths, opts.importPaths) 64 copy(importPaths[len(opts.importPaths):], opts.libPaths) 65 if opts.prefix != "" { 66 importPaths = append(importPaths, filepath.Join(opts.prefix, "lib"+LibDirSuffix, "go", "llgo-"+llvmVersion())) 67 } 68 copts := irgen.CompilerOptions{ 69 TargetTriple: opts.triple, 70 GenerateDebug: opts.generateDebug, 71 DebugPrefixMaps: opts.debugPrefixMaps, 72 DumpSSA: opts.dumpSSA, 73 GccgoPath: opts.gccgoPath, 74 GccgoABI: opts.gccgoPath != "", 75 ImportPaths: importPaths, 76 SanitizerAttribute: opts.sanitizer.getAttribute(), 77 } 78 if opts.dumpTrace { 79 copts.Logger = log.New(os.Stderr, "", 0) 80 } 81 return irgen.NewCompiler(copts) 82 } 83 84 type actionKind int 85 86 const ( 87 actionAssemble = actionKind(iota) 88 actionCompile 89 actionLink 90 actionPrint 91 ) 92 93 type action struct { 94 kind actionKind 95 inputs []string 96 } 97 98 type sanitizerOptions struct { 99 blacklist string 100 crtPrefix string 101 102 address, thread, memory, dataflow bool 103 } 104 105 func (san *sanitizerOptions) resourcePath() string { 106 return filepath.Join(san.crtPrefix, "lib"+LibDirSuffix, "clang", llvmVersion()) 107 } 108 109 func (san *sanitizerOptions) isPIEDefault() bool { 110 return san.thread || san.memory || san.dataflow 111 } 112 113 func (san *sanitizerOptions) addPasses(mpm, fpm llvm.PassManager) { 114 switch { 115 case san.address: 116 mpm.AddAddressSanitizerModulePass() 117 fpm.AddAddressSanitizerFunctionPass() 118 case san.thread: 119 mpm.AddThreadSanitizerPass() 120 case san.memory: 121 mpm.AddMemorySanitizerPass() 122 case san.dataflow: 123 blacklist := san.blacklist 124 if blacklist == "" { 125 blacklist = filepath.Join(san.resourcePath(), "dfsan_abilist.txt") 126 } 127 mpm.AddDataFlowSanitizerPass([]string{blacklist}) 128 } 129 } 130 131 func (san *sanitizerOptions) libPath(triple, sanitizerName string) string { 132 s := strings.Split(triple, "-") 133 return filepath.Join(san.resourcePath(), "lib", s[2], "libclang_rt."+sanitizerName+"-"+s[0]+".a") 134 } 135 136 func (san *sanitizerOptions) addLibsForSanitizer(flags []string, triple, sanitizerName string) []string { 137 return append(flags, san.libPath(triple, sanitizerName), 138 "-Wl,--no-as-needed", "-lpthread", "-lrt", "-lm", "-ldl") 139 } 140 141 func (san *sanitizerOptions) addLibs(triple string, flags []string) []string { 142 switch { 143 case san.address: 144 flags = san.addLibsForSanitizer(flags, triple, "asan") 145 case san.thread: 146 flags = san.addLibsForSanitizer(flags, triple, "tsan") 147 case san.memory: 148 flags = san.addLibsForSanitizer(flags, triple, "msan") 149 case san.dataflow: 150 flags = san.addLibsForSanitizer(flags, triple, "dfsan") 151 } 152 153 return flags 154 } 155 156 func (san *sanitizerOptions) getAttribute() llvm.Attribute { 157 switch { 158 case san.address: 159 return llvm.SanitizeAddressAttribute 160 case san.thread: 161 return llvm.SanitizeThreadAttribute 162 case san.memory: 163 return llvm.SanitizeMemoryAttribute 164 default: 165 return 0 166 } 167 } 168 169 type driverOptions struct { 170 actions []action 171 output string 172 173 bprefix string 174 debugPrefixMaps []debug.PrefixMap 175 dumpSSA bool 176 dumpTrace bool 177 emitIR bool 178 gccgoPath string 179 generateDebug bool 180 importPaths []string 181 libPaths []string 182 llvmArgs []string 183 lto bool 184 optLevel int 185 pic bool 186 pieLink bool 187 pkgpath string 188 plugins []string 189 prefix string 190 sanitizer sanitizerOptions 191 sizeLevel int 192 staticLibgcc bool 193 staticLibgo bool 194 staticLink bool 195 triple string 196 } 197 198 func getInstPrefix() (string, error) { 199 path, err := exec.LookPath(os.Args[0]) 200 if err != nil { 201 return "", err 202 } 203 204 path, err = filepath.EvalSymlinks(path) 205 if err != nil { 206 return "", err 207 } 208 209 prefix := filepath.Join(path, "..", "..") 210 return prefix, nil 211 } 212 213 func parseArguments(args []string) (opts driverOptions, err error) { 214 var goInputs, otherInputs []string 215 hasOtherNonFlagInputs := false 216 noPrefix := false 217 actionKind := actionLink 218 opts.triple = llvm.DefaultTargetTriple() 219 220 for len(args) > 0 { 221 consumedArgs := 1 222 223 switch { 224 case !strings.HasPrefix(args[0], "-"): 225 if strings.HasSuffix(args[0], ".go") { 226 goInputs = append(goInputs, args[0]) 227 } else { 228 hasOtherNonFlagInputs = true 229 otherInputs = append(otherInputs, args[0]) 230 } 231 232 case strings.HasPrefix(args[0], "-Wl,"), strings.HasPrefix(args[0], "-l"), strings.HasPrefix(args[0], "--sysroot="): 233 // TODO(pcc): Handle these correctly. 234 otherInputs = append(otherInputs, args[0]) 235 236 case args[0] == "-B": 237 if len(args) == 1 { 238 return opts, errors.New("missing argument after '-B'") 239 } 240 opts.bprefix = args[1] 241 consumedArgs = 2 242 243 case args[0] == "-D": 244 if len(args) == 1 { 245 return opts, errors.New("missing argument after '-D'") 246 } 247 otherInputs = append(otherInputs, args[0], args[1]) 248 consumedArgs = 2 249 250 case strings.HasPrefix(args[0], "-D"): 251 otherInputs = append(otherInputs, args[0]) 252 253 case args[0] == "-I": 254 if len(args) == 1 { 255 return opts, errors.New("missing argument after '-I'") 256 } 257 opts.importPaths = append(opts.importPaths, args[1]) 258 consumedArgs = 2 259 260 case strings.HasPrefix(args[0], "-I"): 261 opts.importPaths = append(opts.importPaths, args[0][2:]) 262 263 case args[0] == "-isystem": 264 if len(args) == 1 { 265 return opts, errors.New("missing argument after '-isystem'") 266 } 267 otherInputs = append(otherInputs, args[0], args[1]) 268 consumedArgs = 2 269 270 case args[0] == "-L": 271 if len(args) == 1 { 272 return opts, errors.New("missing argument after '-L'") 273 } 274 opts.libPaths = append(opts.libPaths, args[1]) 275 consumedArgs = 2 276 277 case strings.HasPrefix(args[0], "-L"): 278 opts.libPaths = append(opts.libPaths, args[0][2:]) 279 280 case args[0] == "-O0": 281 opts.optLevel = 0 282 283 case args[0] == "-O1", args[0] == "-O": 284 opts.optLevel = 1 285 286 case args[0] == "-O2": 287 opts.optLevel = 2 288 289 case args[0] == "-Os": 290 opts.optLevel = 2 291 opts.sizeLevel = 1 292 293 case args[0] == "-O3": 294 opts.optLevel = 3 295 296 case args[0] == "-S": 297 actionKind = actionAssemble 298 299 case args[0] == "-c": 300 actionKind = actionCompile 301 302 case strings.HasPrefix(args[0], "-fcompilerrt-prefix="): 303 opts.sanitizer.crtPrefix = args[0][20:] 304 305 case strings.HasPrefix(args[0], "-fdebug-prefix-map="): 306 split := strings.SplitN(args[0][19:], "=", 2) 307 if len(split) < 2 { 308 return opts, fmt.Errorf("argument '%s' must be of form '-fdebug-prefix-map=SOURCE=REPLACEMENT'", args[0]) 309 } 310 opts.debugPrefixMaps = append(opts.debugPrefixMaps, debug.PrefixMap{split[0], split[1]}) 311 312 case args[0] == "-fdump-ssa": 313 opts.dumpSSA = true 314 315 case args[0] == "-fdump-trace": 316 opts.dumpTrace = true 317 318 case strings.HasPrefix(args[0], "-fgccgo-path="): 319 opts.gccgoPath = args[0][13:] 320 321 case strings.HasPrefix(args[0], "-fgo-pkgpath="): 322 opts.pkgpath = args[0][13:] 323 324 case strings.HasPrefix(args[0], "-fgo-relative-import-path="): 325 // TODO(pcc): Handle this. 326 327 case strings.HasPrefix(args[0], "-fstack-protector"): 328 // TODO(axw) set ssp function attributes. This can be useful 329 // even for Go, if it interfaces with code written in a non- 330 // memory safe language (e.g. via cgo). 331 332 case strings.HasPrefix(args[0], "-W"): 333 // Go doesn't do warnings. Ignore. 334 335 case args[0] == "-fload-plugin": 336 if len(args) == 1 { 337 return opts, errors.New("missing argument after '-fload-plugin'") 338 } 339 opts.plugins = append(opts.plugins, args[1]) 340 consumedArgs = 2 341 342 case args[0] == "-fno-toplevel-reorder": 343 // This is a GCC-specific code generation option. Ignore. 344 345 case args[0] == "-emit-llvm": 346 opts.emitIR = true 347 348 case args[0] == "-flto": 349 opts.lto = true 350 351 case args[0] == "-fPIC": 352 opts.pic = true 353 354 case strings.HasPrefix(args[0], "-fsanitize-blacklist="): 355 opts.sanitizer.blacklist = args[0][21:] 356 357 // TODO(pcc): Enforce mutual exclusion between sanitizers. 358 359 case args[0] == "-fsanitize=address": 360 opts.sanitizer.address = true 361 362 case args[0] == "-fsanitize=thread": 363 opts.sanitizer.thread = true 364 365 case args[0] == "-fsanitize=memory": 366 opts.sanitizer.memory = true 367 368 case args[0] == "-fsanitize=dataflow": 369 opts.sanitizer.dataflow = true 370 371 case args[0] == "-g": 372 opts.generateDebug = true 373 374 case args[0] == "-mllvm": 375 if len(args) == 1 { 376 return opts, errors.New("missing argument after '-mllvm'") 377 } 378 opts.llvmArgs = append(opts.llvmArgs, args[1]) 379 consumedArgs = 2 380 381 case strings.HasPrefix(args[0], "-m"), args[0] == "-funsafe-math-optimizations", args[0] == "-ffp-contract=off": 382 // TODO(pcc): Handle code generation options. 383 384 case args[0] == "-no-prefix": 385 noPrefix = true 386 387 case args[0] == "-o": 388 if len(args) == 1 { 389 return opts, errors.New("missing argument after '-o'") 390 } 391 opts.output = args[1] 392 consumedArgs = 2 393 394 case args[0] == "-pie": 395 opts.pieLink = true 396 397 case args[0] == "-dumpversion", 398 args[0] == "-print-libgcc-file-name", 399 args[0] == "-print-multi-os-directory", 400 args[0] == "--version": 401 actionKind = actionPrint 402 opts.output = args[0] 403 404 case args[0] == "-static": 405 opts.staticLink = true 406 407 case args[0] == "-static-libgcc": 408 opts.staticLibgcc = true 409 410 case args[0] == "-static-libgo": 411 opts.staticLibgo = true 412 413 default: 414 return opts, fmt.Errorf("unrecognized command line option '%s'", args[0]) 415 } 416 417 args = args[consumedArgs:] 418 } 419 420 if actionKind != actionPrint && len(goInputs) == 0 && !hasOtherNonFlagInputs { 421 return opts, errors.New("no input files") 422 } 423 424 if !noPrefix { 425 opts.prefix, err = getInstPrefix() 426 if err != nil { 427 return opts, err 428 } 429 } 430 431 if opts.sanitizer.crtPrefix == "" { 432 opts.sanitizer.crtPrefix = opts.prefix 433 } 434 435 if opts.sanitizer.isPIEDefault() { 436 // This should really only be turning on -fPIE, but this isn't 437 // easy to do from Go, and -fPIC is a superset of it anyway. 438 opts.pic = true 439 opts.pieLink = true 440 } 441 442 switch actionKind { 443 case actionLink: 444 if len(goInputs) != 0 { 445 opts.actions = []action{action{actionCompile, goInputs}} 446 } 447 opts.actions = append(opts.actions, action{actionLink, otherInputs}) 448 449 case actionCompile, actionAssemble: 450 if len(goInputs) != 0 { 451 opts.actions = []action{action{actionKind, goInputs}} 452 } 453 454 case actionPrint: 455 opts.actions = []action{action{actionKind, nil}} 456 } 457 458 if opts.output == "" && len(opts.actions) != 0 { 459 switch actionKind { 460 case actionCompile, actionAssemble: 461 base := filepath.Base(goInputs[0]) 462 base = base[0 : len(base)-3] 463 if actionKind == actionCompile { 464 opts.output = base + ".o" 465 } else { 466 opts.output = base + ".s" 467 } 468 469 case actionLink: 470 opts.output = "a.out" 471 } 472 } 473 474 return opts, nil 475 } 476 477 func runPasses(opts *driverOptions, tm llvm.TargetMachine, m llvm.Module) { 478 fpm := llvm.NewFunctionPassManagerForModule(m) 479 defer fpm.Dispose() 480 481 mpm := llvm.NewPassManager() 482 defer mpm.Dispose() 483 484 pmb := llvm.NewPassManagerBuilder() 485 defer pmb.Dispose() 486 487 pmb.SetOptLevel(opts.optLevel) 488 pmb.SetSizeLevel(opts.sizeLevel) 489 490 tm.AddAnalysisPasses(mpm) 491 tm.AddAnalysisPasses(fpm) 492 493 mpm.AddVerifierPass() 494 fpm.AddVerifierPass() 495 496 pmb.Populate(mpm) 497 pmb.PopulateFunc(fpm) 498 499 if opts.optLevel == 0 { 500 // Remove references (via the descriptor) to dead functions, 501 // for compatibility with other compilers. 502 mpm.AddGlobalDCEPass() 503 } 504 505 opts.sanitizer.addPasses(mpm, fpm) 506 507 fpm.InitializeFunc() 508 for fn := m.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) { 509 fpm.RunFunc(fn) 510 } 511 fpm.FinalizeFunc() 512 513 mpm.Run(m) 514 } 515 516 func getMetadataSectionInlineAsm(name string) string { 517 // ELF: creates a non-allocated excluded section. 518 return ".section \"" + name + "\", \"e\"\n" 519 } 520 521 func getDataInlineAsm(data []byte) string { 522 edata := make([]byte, 0, len(data)*4+10) 523 524 edata = append(edata, ".ascii \""...) 525 for i := range data { 526 switch data[i] { 527 case '\000': 528 edata = append(edata, "\\000"...) 529 continue 530 case '\n': 531 edata = append(edata, "\\n"...) 532 continue 533 case '"', '\\': 534 edata = append(edata, '\\') 535 } 536 edata = append(edata, data[i]) 537 } 538 edata = append(edata, "\"\n"...) 539 return string(edata) 540 } 541 542 // Get the lib path to the standard libraries for the given driver options. 543 // This is normally 'lib' but can vary for cross compilation, LTO, sanitizers 544 // etc. 545 func getLibDir(opts *driverOptions) string { 546 lib := "lib" + LibDirSuffix 547 switch { 548 case opts.lto: 549 return filepath.Join(lib, "llvm-lto.0") 550 case opts.sanitizer.address: 551 return filepath.Join(lib, "llvm-asan.0") 552 case opts.sanitizer.thread: 553 return filepath.Join(lib, "llvm-tsan.0") 554 case opts.sanitizer.memory: 555 return filepath.Join(lib, "llvm-msan.0") 556 case opts.sanitizer.dataflow: 557 return filepath.Join(lib, "llvm-dfsan.0") 558 default: 559 return lib 560 } 561 } 562 563 func performAction(opts *driverOptions, kind actionKind, inputs []string, output string) error { 564 switch kind { 565 case actionPrint: 566 switch opts.output { 567 case "-dumpversion": 568 fmt.Println("llgo-" + llvmVersion()) 569 return nil 570 case "-print-libgcc-file-name": 571 cmd := exec.Command(opts.bprefix+"gcc", "-print-libgcc-file-name") 572 out, err := cmd.CombinedOutput() 573 os.Stdout.Write(out) 574 return err 575 case "-print-multi-os-directory": 576 fmt.Println(filepath.Join("..", getLibDir(opts))) 577 return nil 578 case "--version": 579 displayVersion() 580 return nil 581 default: 582 panic("unexpected print command") 583 } 584 585 case actionCompile, actionAssemble: 586 compiler, err := initCompiler(opts) 587 if err != nil { 588 return err 589 } 590 591 fset := token.NewFileSet() 592 files, err := driver.ParseFiles(fset, inputs) 593 if err != nil { 594 return err 595 } 596 597 module, err := compiler.Compile(fset, files, opts.pkgpath) 598 if err != nil { 599 return err 600 } 601 602 defer module.Dispose() 603 604 target, err := llvm.GetTargetFromTriple(opts.triple) 605 if err != nil { 606 return err 607 } 608 609 optLevel := [...]llvm.CodeGenOptLevel{ 610 llvm.CodeGenLevelNone, 611 llvm.CodeGenLevelLess, 612 llvm.CodeGenLevelDefault, 613 llvm.CodeGenLevelAggressive, 614 }[opts.optLevel] 615 616 relocMode := llvm.RelocStatic 617 if opts.pic { 618 relocMode = llvm.RelocPIC 619 } 620 621 tm := target.CreateTargetMachine(opts.triple, "", "", optLevel, 622 relocMode, llvm.CodeModelDefault) 623 defer tm.Dispose() 624 625 runPasses(opts, tm, module.Module) 626 627 var file *os.File 628 if output == "-" { 629 file = os.Stdout 630 } else { 631 file, err = os.Create(output) 632 if err != nil { 633 return err 634 } 635 defer file.Close() 636 } 637 638 switch { 639 case !opts.lto && !opts.emitIR: 640 if module.ExportData != nil { 641 asm := getMetadataSectionInlineAsm(".go_export") 642 asm += getDataInlineAsm(module.ExportData) 643 module.Module.SetInlineAsm(asm) 644 } 645 646 fileType := llvm.AssemblyFile 647 if kind == actionCompile { 648 fileType = llvm.ObjectFile 649 } 650 mb, err := tm.EmitToMemoryBuffer(module.Module, fileType) 651 if err != nil { 652 return err 653 } 654 defer mb.Dispose() 655 656 bytes := mb.Bytes() 657 _, err = file.Write(bytes) 658 return err 659 660 case opts.lto: 661 bcmb := llvm.WriteBitcodeToMemoryBuffer(module.Module) 662 defer bcmb.Dispose() 663 664 // This is a bit of a hack. We just want an object file 665 // containing some metadata sections. This might be simpler 666 // if we had bindings for the MC library, but for now we create 667 // a fresh module containing only inline asm that creates the 668 // sections. 669 outmodule := llvm.NewModule("") 670 defer outmodule.Dispose() 671 asm := getMetadataSectionInlineAsm(".llvmbc") 672 asm += getDataInlineAsm(bcmb.Bytes()) 673 if module.ExportData != nil { 674 asm += getMetadataSectionInlineAsm(".go_export") 675 asm += getDataInlineAsm(module.ExportData) 676 } 677 outmodule.SetInlineAsm(asm) 678 679 fileType := llvm.AssemblyFile 680 if kind == actionCompile { 681 fileType = llvm.ObjectFile 682 } 683 mb, err := tm.EmitToMemoryBuffer(outmodule, fileType) 684 if err != nil { 685 return err 686 } 687 defer mb.Dispose() 688 689 bytes := mb.Bytes() 690 _, err = file.Write(bytes) 691 return err 692 693 case kind == actionCompile: 694 err := llvm.WriteBitcodeToFile(module.Module, file) 695 return err 696 697 case kind == actionAssemble: 698 _, err := file.WriteString(module.Module.String()) 699 return err 700 701 default: 702 panic("unexpected action kind") 703 } 704 705 case actionLink: 706 // TODO(pcc): Teach this to do LTO. 707 args := []string{"-o", output} 708 if opts.pic { 709 args = append(args, "-fPIC") 710 } 711 if opts.pieLink { 712 args = append(args, "-pie") 713 } 714 if opts.staticLink { 715 args = append(args, "-static") 716 } 717 if opts.staticLibgcc { 718 args = append(args, "-static-libgcc") 719 } 720 for _, p := range opts.libPaths { 721 args = append(args, "-L", p) 722 } 723 for _, p := range opts.importPaths { 724 args = append(args, "-I", p) 725 } 726 args = append(args, inputs...) 727 var linkerPath string 728 if opts.gccgoPath == "" { 729 // TODO(pcc): See if we can avoid calling gcc here. 730 // We currently rely on it to find crt*.o and compile 731 // any C source files passed as arguments. 732 linkerPath = opts.bprefix + "gcc" 733 734 if opts.prefix != "" { 735 libdir := filepath.Join(opts.prefix, getLibDir(opts)) 736 args = append(args, "-L", libdir) 737 if !opts.staticLibgo { 738 args = append(args, "-Wl,-rpath,"+libdir) 739 } 740 } 741 742 args = append(args, "-lgobegin-llgo") 743 if opts.staticLibgo { 744 args = append(args, "-Wl,-Bstatic", "-lgo-llgo", "-Wl,-Bdynamic", "-lpthread", "-lm") 745 } else { 746 args = append(args, "-lgo-llgo", "-lm") 747 } 748 } else { 749 linkerPath = opts.gccgoPath 750 if opts.staticLibgo { 751 args = append(args, "-static-libgo") 752 } 753 } 754 755 args = opts.sanitizer.addLibs(opts.triple, args) 756 757 cmd := exec.Command(linkerPath, args...) 758 out, err := cmd.CombinedOutput() 759 if err != nil { 760 os.Stderr.Write(out) 761 } 762 return err 763 764 default: 765 panic("unexpected action kind") 766 } 767 } 768 769 func performActions(opts *driverOptions) error { 770 var extraInput string 771 772 for _, plugin := range opts.plugins { 773 err := llvm.LoadLibraryPermanently(plugin) 774 if err != nil { 775 return err 776 } 777 } 778 779 llvm.ParseCommandLineOptions(append([]string{"llgo"}, opts.llvmArgs...), "llgo (LLVM option parsing)\n") 780 781 for i, action := range opts.actions { 782 var output string 783 if i == len(opts.actions)-1 { 784 output = opts.output 785 } else { 786 tmpfile, err := ioutil.TempFile("", "llgo") 787 if err != nil { 788 return err 789 } 790 output = tmpfile.Name() + ".o" 791 tmpfile.Close() 792 err = os.Remove(tmpfile.Name()) 793 if err != nil { 794 return err 795 } 796 defer os.Remove(output) 797 } 798 799 inputs := action.inputs 800 if extraInput != "" { 801 inputs = append([]string{extraInput}, inputs...) 802 } 803 804 err := performAction(opts, action.kind, inputs, output) 805 if err != nil { 806 return err 807 } 808 809 extraInput = output 810 } 811 812 return nil 813 } 814 815 func main() { 816 llvm.InitializeAllTargets() 817 llvm.InitializeAllTargetMCs() 818 llvm.InitializeAllTargetInfos() 819 llvm.InitializeAllAsmParsers() 820 llvm.InitializeAllAsmPrinters() 821 822 opts, err := parseArguments(os.Args[1:]) 823 if err != nil { 824 report(err) 825 os.Exit(1) 826 } 827 828 err = performActions(&opts) 829 if err != nil { 830 report(err) 831 os.Exit(1) 832 } 833 }