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