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