1// Copyright 2013 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package gccgoimporter
6
7import (
8	"bufio"
9	"go/types"
10	"os"
11	"os/exec"
12	"path/filepath"
13	"strings"
14)
15
16// Information about a specific installation of gccgo.
17type GccgoInstallation struct {
18	// Version of gcc (e.g. 4.8.0).
19	GccVersion string
20
21	// Target triple (e.g. x86_64-unknown-linux-gnu).
22	TargetTriple string
23
24	// Built-in library paths used by this installation.
25	LibPaths []string
26}
27
28// Ask the driver at the given path for information for this GccgoInstallation.
29// The given arguments are passed directly to the call of the driver.
30func (inst *GccgoInstallation) InitFromDriver(gccgoPath string, args ...string) (err error) {
31	argv := append([]string{"-###", "-S", "-x", "go", "-"}, args...)
32	cmd := exec.Command(gccgoPath, argv...)
33	stderr, err := cmd.StderrPipe()
34	if err != nil {
35		return
36	}
37
38	err = cmd.Start()
39	if err != nil {
40		return
41	}
42
43	scanner := bufio.NewScanner(stderr)
44	for scanner.Scan() {
45		line := scanner.Text()
46		switch {
47		case strings.HasPrefix(line, "Target: "):
48			inst.TargetTriple = line[8:]
49
50		case line[0] == ' ':
51			args := strings.Fields(line)
52			for _, arg := range args[1:] {
53				if strings.HasPrefix(arg, "-L") {
54					inst.LibPaths = append(inst.LibPaths, arg[2:])
55				}
56			}
57		}
58	}
59
60	argv = append([]string{"-dumpversion"}, args...)
61	stdout, err := exec.Command(gccgoPath, argv...).Output()
62	if err != nil {
63		return
64	}
65	inst.GccVersion = strings.TrimSpace(string(stdout))
66
67	return
68}
69
70// Return the list of export search paths for this GccgoInstallation.
71func (inst *GccgoInstallation) SearchPaths() (paths []string) {
72	for _, lpath := range inst.LibPaths {
73		spath := filepath.Join(lpath, "go", inst.GccVersion)
74		fi, err := os.Stat(spath)
75		if err != nil || !fi.IsDir() {
76			continue
77		}
78		paths = append(paths, spath)
79
80		spath = filepath.Join(spath, inst.TargetTriple)
81		fi, err = os.Stat(spath)
82		if err != nil || !fi.IsDir() {
83			continue
84		}
85		paths = append(paths, spath)
86	}
87
88	paths = append(paths, inst.LibPaths...)
89
90	return
91}
92
93// Return an importer that searches incpaths followed by the gcc installation's
94// built-in search paths and the current directory.
95func (inst *GccgoInstallation) GetImporter(incpaths []string, initmap map[*types.Package]InitData) Importer {
96	return GetImporter(append(append(incpaths, inst.SearchPaths()...), "."), initmap)
97}
98