blob: 55f20315dedf706c636712701caa26433f1e9b25 [file] [log] [blame]
Peter Collingbourne244ecf52014-10-23 02:33:23 +00001//===-- llvm-go.go - go tool wrapper for LLVM -----------------------------===//
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 tool lets us build LLVM components within the tree by setting up a
11// $GOPATH that resembles a tree fetched in the normal way with "go get".
12//
13//===----------------------------------------------------------------------===//
14
15package main
16
17import (
18 "fmt"
19 "io/ioutil"
20 "os"
21 "os/exec"
22 "path/filepath"
23 "runtime"
24 "strings"
25)
26
27type pkg struct {
28 llvmpath, pkgpath string
29}
30
31var packages = []pkg{
32 {"bindings/go/llvm", "llvm.org/llvm/bindings/go/llvm"},
Peter Collingbournea4f0bd72014-11-27 00:15:21 +000033 {"tools/llgo", "llvm.org/llgo"},
Peter Collingbourne244ecf52014-10-23 02:33:23 +000034}
35
36type compilerFlags struct {
37 cpp, cxx, ld string
38}
39
40var components = []string{
41 "all-targets",
42 "analysis",
43 "asmparser",
44 "asmprinter",
45 "bitreader",
46 "bitwriter",
47 "codegen",
48 "core",
Zachary Turner82af9432015-01-30 18:07:45 +000049 "debuginfodwarf",
Peter Collingbourne244ecf52014-10-23 02:33:23 +000050 "executionengine",
51 "instrumentation",
52 "interpreter",
53 "ipo",
54 "irreader",
55 "linker",
56 "mc",
57 "mcjit",
58 "objcarcopts",
59 "option",
60 "profiledata",
61 "scalaropts",
62 "support",
63 "target",
64}
65
66func llvmConfig(args ...string) string {
67 configpath := os.Getenv("LLVM_CONFIG")
68 if configpath == "" {
69 // strip llvm-go, add llvm-config
70 configpath = os.Args[0][:len(os.Args[0])-7] + "llvm-config"
71 }
72
73 cmd := exec.Command(configpath, args...)
74 out, err := cmd.Output()
75 if err != nil {
76 panic(err.Error())
77 }
78
79 outstr := string(out)
80 outstr = strings.TrimSuffix(outstr, "\n")
81 return strings.Replace(outstr, "\n", " ", -1)
82}
83
84func llvmFlags() compilerFlags {
85 ldflags := llvmConfig(append([]string{"--ldflags", "--libs", "--system-libs"}, components...)...)
86 if runtime.GOOS != "darwin" {
87 // OS X doesn't like -rpath with cgo. See:
88 // https://code.google.com/p/go/issues/detail?id=7293
89 ldflags = "-Wl,-rpath," + llvmConfig("--libdir") + " " + ldflags
90 }
91 return compilerFlags{
92 cpp: llvmConfig("--cppflags"),
93 cxx: "-std=c++11",
94 ld: ldflags,
95 }
96}
97
98func addTag(args []string, tag string) []string {
99 args = append([]string{}, args...)
100 addedTag := false
101 for i, a := range args {
102 if strings.HasPrefix(a, "-tags=") {
103 args[i] = a + " " + tag
104 addedTag = true
105 } else if a == "-tags" && i+1 < len(args) {
106 args[i+1] = args[i+1] + " " + tag
107 addedTag = true
108 }
109 }
110 if !addedTag {
111 args = append([]string{args[0], "-tags", tag}, args[1:]...)
112 }
113 return args
114}
115
116func printComponents() {
117 fmt.Println(strings.Join(components, " "))
118}
119
120func printConfig() {
121 flags := llvmFlags()
122
123 fmt.Printf(`// +build !byollvm
124
125// This file is generated by llvm-go, do not edit.
126
127package llvm
128
129/*
130#cgo CPPFLAGS: %s
131#cgo CXXFLAGS: %s
132#cgo LDFLAGS: %s
133*/
134import "C"
135
136type (run_build_sh int)
137`, flags.cpp, flags.cxx, flags.ld)
138}
139
Peter Collingbourne55707082015-02-14 01:45:56 +0000140func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags string) {
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000141 args = addTag(args, "byollvm")
142
143 srcdir := llvmConfig("--src-root")
144
145 tmpgopath, err := ioutil.TempDir("", "gopath")
146 if err != nil {
147 panic(err.Error())
148 }
149
150 for _, p := range packages {
151 path := filepath.Join(tmpgopath, "src", p.pkgpath)
152 err := os.MkdirAll(filepath.Dir(path), os.ModePerm)
153 if err != nil {
154 panic(err.Error())
155 }
156
157 err = os.Symlink(filepath.Join(srcdir, p.llvmpath), path)
158 if err != nil {
159 panic(err.Error())
160 }
161 }
162
Peter Collingbournea4f0bd72014-11-27 00:15:21 +0000163 newpath := os.Getenv("PATH")
164
165 if llgo != "" {
166 bindir := filepath.Join(tmpgopath, "bin")
167
168 err = os.MkdirAll(bindir, os.ModePerm)
169 if err != nil {
170 panic(err.Error())
171 }
172
173 err = os.Symlink(llgo, filepath.Join(bindir, "gccgo"))
174 if err != nil {
175 panic(err.Error())
176 }
177
178 newpathlist := []string{bindir}
179 newpathlist = append(newpathlist, filepath.SplitList(newpath)...)
180 newpath = strings.Join(newpathlist, string(filepath.ListSeparator))
181
182 args = append([]string{args[0], "-compiler", "gccgo"}, args[1:]...)
183 }
184
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000185 newgopathlist := []string{tmpgopath}
186 newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...)
187 newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator))
188
189 flags := llvmFlags()
190
191 newenv := []string{
192 "CC=" + cc,
193 "CXX=" + cxx,
194 "CGO_CPPFLAGS=" + flags.cpp + " " + cppflags,
195 "CGO_CXXFLAGS=" + flags.cxx + " " + cxxflags,
196 "CGO_LDFLAGS=" + flags.ld + " " + ldflags,
197 "GOPATH=" + newgopath,
Peter Collingbournea4f0bd72014-11-27 00:15:21 +0000198 "PATH=" + newpath,
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000199 }
200 for _, v := range os.Environ() {
201 if !strings.HasPrefix(v, "CC=") &&
202 !strings.HasPrefix(v, "CXX=") &&
203 !strings.HasPrefix(v, "CGO_CPPFLAGS=") &&
204 !strings.HasPrefix(v, "CGO_CXXFLAGS=") &&
205 !strings.HasPrefix(v, "CGO_LDFLAGS=") &&
Peter Collingbournea4f0bd72014-11-27 00:15:21 +0000206 !strings.HasPrefix(v, "GOPATH=") &&
207 !strings.HasPrefix(v, "PATH=") {
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000208 newenv = append(newenv, v)
209 }
210 }
211
Peter Collingbourne55707082015-02-14 01:45:56 +0000212 gocmdpath, err := exec.LookPath(gocmd)
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000213 if err != nil {
214 panic(err.Error())
215 }
216
Peter Collingbourne55707082015-02-14 01:45:56 +0000217 proc, err := os.StartProcess(gocmdpath, append([]string{gocmd}, args...),
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000218 &os.ProcAttr{
219 Env: newenv,
220 Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
221 })
222 if err != nil {
223 panic(err.Error())
224 }
225 ps, err := proc.Wait()
226 if err != nil {
227 panic(err.Error())
228 }
229
230 os.RemoveAll(tmpgopath)
231
232 if !ps.Success() {
233 os.Exit(1)
234 }
235}
236
237func usage() {
238 fmt.Println(`Usage: llvm-go subcommand [flags]
239
240Available subcommands: build get install run test print-components print-config`)
241 os.Exit(0)
242}
243
244func main() {
245 cc := os.Getenv("CC")
246 cxx := os.Getenv("CXX")
247 cppflags := os.Getenv("CGO_CPPFLAGS")
248 cxxflags := os.Getenv("CGO_CXXFLAGS")
249 ldflags := os.Getenv("CGO_LDFLAGS")
Peter Collingbourne55707082015-02-14 01:45:56 +0000250 gocmd := "go"
Peter Collingbournea4f0bd72014-11-27 00:15:21 +0000251 llgo := ""
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000252
253 args := os.Args[1:]
254 DONE: for {
255 switch {
256 case len(args) == 0:
257 usage()
258 case strings.HasPrefix(args[0], "cc="):
259 cc = args[0][3:]
260 args = args[1:]
261 case strings.HasPrefix(args[0], "cxx="):
262 cxx = args[0][4:]
263 args = args[1:]
Peter Collingbourne55707082015-02-14 01:45:56 +0000264 case strings.HasPrefix(args[0], "go="):
265 gocmd = args[0][3:]
266 args = args[1:]
Peter Collingbournea4f0bd72014-11-27 00:15:21 +0000267 case strings.HasPrefix(args[0], "llgo="):
268 llgo = args[0][5:]
269 args = args[1:]
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000270 case strings.HasPrefix(args[0], "cppflags="):
271 cppflags = args[0][9:]
272 args = args[1:]
273 case strings.HasPrefix(args[0], "cxxflags="):
274 cxxflags = args[0][9:]
275 args = args[1:]
276 case strings.HasPrefix(args[0], "ldflags="):
277 ldflags = args[0][8:]
278 args = args[1:]
279 default:
280 break DONE
281 }
282 }
283
284 switch args[0] {
285 case "build", "get", "install", "run", "test":
Peter Collingbourne55707082015-02-14 01:45:56 +0000286 runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags)
Peter Collingbourne244ecf52014-10-23 02:33:23 +0000287 case "print-components":
288 printComponents()
289 case "print-config":
290 printConfig()
291 default:
292 usage()
293 }
294}