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