github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/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 target := tm.TargetData() 491 mpm.Add(target) 492 fpm.Add(target) 493 tm.AddAnalysisPasses(mpm) 494 tm.AddAnalysisPasses(fpm) 495 496 mpm.AddVerifierPass() 497 fpm.AddVerifierPass() 498 499 pmb.Populate(mpm) 500 pmb.PopulateFunc(fpm) 501 502 if opts.optLevel == 0 { 503 // Remove references (via the descriptor) to dead functions, 504 // for compatibility with other compilers. 505 mpm.AddGlobalDCEPass() 506 } 507 508 opts.sanitizer.addPasses(mpm, fpm) 509 510 fpm.InitializeFunc() 511 for fn := m.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) { 512 fpm.RunFunc(fn) 513 } 514 fpm.FinalizeFunc() 515 516 mpm.Run(m) 517 } 518 519 func getMetadataSectionInlineAsm(name string) string { 520 // ELF: creates a non-allocated excluded section. 521 return ".section \"" + name + "\", \"e\"\n" 522 } 523 524 func getDataInlineAsm(data []byte) string { 525 edata := make([]byte, 0, len(data)*4+10) 526 527 edata = append(edata, ".ascii \""...) 528 for i := range data { 529 switch data[i] { 530 case '\000': 531 edata = append(edata, "\\000"...) 532 continue 533 case '\n': 534 edata = append(edata, "\\n"...) 535 continue 536 case '"', '\\': 537 edata = append(edata, '\\') 538 } 539 edata = append(edata, data[i]) 540 } 541 edata = append(edata, "\"\n"...) 542 return string(edata) 543 } 544 545 // Get the lib path to the standard libraries for the given driver options. 546 // This is normally 'lib' but can vary for cross compilation, LTO, sanitizers 547 // etc. 548 func getLibDir(opts *driverOptions) string { 549 lib := "lib" + LibDirSuffix 550 switch { 551 case opts.lto: 552 return filepath.Join(lib, "llvm-lto.0") 553 case opts.sanitizer.address: 554 return filepath.Join(lib, "llvm-asan.0") 555 case opts.sanitizer.thread: 556 return filepath.Join(lib, "llvm-tsan.0") 557 case opts.sanitizer.memory: 558 return filepath.Join(lib, "llvm-msan.0") 559 case opts.sanitizer.dataflow: 560 return filepath.Join(lib, "llvm-dfsan.0") 561 default: 562 return lib 563 } 564 } 565 566 func performAction(opts *driverOptions, kind actionKind, inputs []string, output string) error { 567 switch kind { 568 case actionPrint: 569 switch opts.output { 570 case "-dumpversion": 571 fmt.Println("llgo-" + llvmVersion()) 572 return nil 573 case "-print-libgcc-file-name": 574 cmd := exec.Command(opts.bprefix+"gcc", "-print-libgcc-file-name") 575 out, err := cmd.CombinedOutput() 576 os.Stdout.Write(out) 577 return err 578 case "-print-multi-os-directory": 579 fmt.Println(filepath.Join("..", getLibDir(opts))) 580 return nil 581 case "--version": 582 displayVersion() 583 return nil 584 default: 585 panic("unexpected print command") 586 } 587 588 case actionCompile, actionAssemble: 589 compiler, err := initCompiler(opts) 590 if err != nil { 591 return err 592 } 593 594 fset := token.NewFileSet() 595 files, err := driver.ParseFiles(fset, inputs) 596 if err != nil { 597 return err 598 } 599 600 module, err := compiler.Compile(fset, files, opts.pkgpath) 601 if err != nil { 602 return err 603 } 604 605 defer module.Dispose() 606 607 target, err := llvm.GetTargetFromTriple(opts.triple) 608 if err != nil { 609 return err 610 } 611 612 optLevel := [...]llvm.CodeGenOptLevel{ 613 llvm.CodeGenLevelNone, 614 llvm.CodeGenLevelLess, 615 llvm.CodeGenLevelDefault, 616 llvm.CodeGenLevelAggressive, 617 }[opts.optLevel] 618 619 relocMode := llvm.RelocStatic 620 if opts.pic { 621 relocMode = llvm.RelocPIC 622 } 623 624 tm := target.CreateTargetMachine(opts.triple, "", "", optLevel, 625 relocMode, llvm.CodeModelDefault) 626 defer tm.Dispose() 627 628 runPasses(opts, tm, module.Module) 629 630 var file *os.File 631 if output == "-" { 632 file = os.Stdout 633 } else { 634 file, err = os.Create(output) 635 if err != nil { 636 return err 637 } 638 defer file.Close() 639 } 640 641 switch { 642 case !opts.lto && !opts.emitIR: 643 if module.ExportData != nil { 644 asm := getMetadataSectionInlineAsm(".go_export") 645 asm += getDataInlineAsm(module.ExportData) 646 module.Module.SetInlineAsm(asm) 647 } 648 649 fileType := llvm.AssemblyFile 650 if kind == actionCompile { 651 fileType = llvm.ObjectFile 652 } 653 mb, err := tm.EmitToMemoryBuffer(module.Module, fileType) 654 if err != nil { 655 return err 656 } 657 defer mb.Dispose() 658 659 bytes := mb.Bytes() 660 _, err = file.Write(bytes) 661 return err 662 663 case opts.lto: 664 bcmb := llvm.WriteBitcodeToMemoryBuffer(module.Module) 665 defer bcmb.Dispose() 666 667 // This is a bit of a hack. We just want an object file 668 // containing some metadata sections. This might be simpler 669 // if we had bindings for the MC library, but for now we create 670 // a fresh module containing only inline asm that creates the 671 // sections. 672 outmodule := llvm.NewModule("") 673 defer outmodule.Dispose() 674 asm := getMetadataSectionInlineAsm(".llvmbc") 675 asm += getDataInlineAsm(bcmb.Bytes()) 676 if module.ExportData != nil { 677 asm += getMetadataSectionInlineAsm(".go_export") 678 asm += getDataInlineAsm(module.ExportData) 679 } 680 outmodule.SetInlineAsm(asm) 681 682 fileType := llvm.AssemblyFile 683 if kind == actionCompile { 684 fileType = llvm.ObjectFile 685 } 686 mb, err := tm.EmitToMemoryBuffer(outmodule, fileType) 687 if err != nil { 688 return err 689 } 690 defer mb.Dispose() 691 692 bytes := mb.Bytes() 693 _, err = file.Write(bytes) 694 return err 695 696 case kind == actionCompile: 697 err := llvm.WriteBitcodeToFile(module.Module, file) 698 return err 699 700 case kind == actionAssemble: 701 _, err := file.WriteString(module.Module.String()) 702 return err 703 704 default: 705 panic("unexpected action kind") 706 } 707 708 case actionLink: 709 // TODO(pcc): Teach this to do LTO. 710 args := []string{"-o", output} 711 if opts.pic { 712 args = append(args, "-fPIC") 713 } 714 if opts.pieLink { 715 args = append(args, "-pie") 716 } 717 if opts.staticLink { 718 args = append(args, "-static") 719 } 720 if opts.staticLibgcc { 721 args = append(args, "-static-libgcc") 722 } 723 for _, p := range opts.libPaths { 724 args = append(args, "-L", p) 725 } 726 for _, p := range opts.importPaths { 727 args = append(args, "-I", p) 728 } 729 args = append(args, inputs...) 730 var linkerPath string 731 if opts.gccgoPath == "" { 732 // TODO(pcc): See if we can avoid calling gcc here. 733 // We currently rely on it to find crt*.o and compile 734 // any C source files passed as arguments. 735 linkerPath = opts.bprefix + "gcc" 736 737 if opts.prefix != "" { 738 libdir := filepath.Join(opts.prefix, getLibDir(opts)) 739 args = append(args, "-L", libdir) 740 if !opts.staticLibgo { 741 args = append(args, "-Wl,-rpath,"+libdir) 742 } 743 } 744 745 args = append(args, "-lgobegin-llgo") 746 if opts.staticLibgo { 747 args = append(args, "-Wl,-Bstatic", "-lgo-llgo", "-Wl,-Bdynamic", "-lpthread", "-lm") 748 } else { 749 args = append(args, "-lgo-llgo") 750 } 751 } else { 752 linkerPath = opts.gccgoPath 753 if opts.staticLibgo { 754 args = append(args, "-static-libgo") 755 } 756 } 757 758 args = opts.sanitizer.addLibs(opts.triple, args) 759 760 cmd := exec.Command(linkerPath, args...) 761 out, err := cmd.CombinedOutput() 762 if err != nil { 763 os.Stderr.Write(out) 764 } 765 return err 766 767 default: 768 panic("unexpected action kind") 769 } 770 } 771 772 func performActions(opts *driverOptions) error { 773 var extraInput string 774 775 for _, plugin := range opts.plugins { 776 err := llvm.LoadLibraryPermanently(plugin) 777 if err != nil { 778 return err 779 } 780 } 781 782 llvm.ParseCommandLineOptions(append([]string{"llgo"}, opts.llvmArgs...), "llgo (LLVM option parsing)\n") 783 784 for i, action := range opts.actions { 785 var output string 786 if i == len(opts.actions)-1 { 787 output = opts.output 788 } else { 789 tmpfile, err := ioutil.TempFile("", "llgo") 790 if err != nil { 791 return err 792 } 793 output = tmpfile.Name() + ".o" 794 tmpfile.Close() 795 err = os.Remove(tmpfile.Name()) 796 if err != nil { 797 return err 798 } 799 defer os.Remove(output) 800 } 801 802 inputs := action.inputs 803 if extraInput != "" { 804 inputs = append([]string{extraInput}, inputs...) 805 } 806 807 err := performAction(opts, action.kind, inputs, output) 808 if err != nil { 809 return err 810 } 811 812 extraInput = output 813 } 814 815 return nil 816 } 817 818 func main() { 819 llvm.InitializeAllTargets() 820 llvm.InitializeAllTargetMCs() 821 llvm.InitializeAllTargetInfos() 822 llvm.InitializeAllAsmParsers() 823 llvm.InitializeAllAsmPrinters() 824 825 opts, err := parseArguments(os.Args[1:]) 826 if err != nil { 827 report(err) 828 os.Exit(1) 829 } 830 831 err = performActions(&opts) 832 if err != nil { 833 report(err) 834 os.Exit(1) 835 } 836 }