OSDN Git Service

android: AMDGPU/GlobalISel: fix tablegen rules (llvm90)
[android-x86/external-llvm.git] / tools / llvm-go / llvm-go.go
1 //===-- llvm-go.go - go tool wrapper for LLVM -----------------------------===//
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 tool lets us build LLVM components within the tree by setting up a
10 // $GOPATH that resembles a tree fetched in the normal way with "go get".
11 //
12 //===----------------------------------------------------------------------===//
13
14 package main
15
16 import (
17         "fmt"
18         "io/ioutil"
19         "os"
20         "os/exec"
21         "path/filepath"
22         "runtime"
23         "strings"
24 )
25
26 const (
27         linkmodeComponentLibs = "component-libs"
28         linkmodeDylib         = "dylib"
29 )
30
31 type pkg struct {
32         llvmpath, pkgpath string
33 }
34
35 var packages = []pkg{
36         {"bindings/go/llvm", "llvm.org/llvm/bindings/go/llvm"},
37 }
38
39 type compilerFlags struct {
40         cpp, cxx, ld string
41 }
42
43 var components = []string{
44         "all-targets",
45         "analysis",
46         "asmparser",
47         "asmprinter",
48         "bitreader",
49         "bitwriter",
50         "codegen",
51         "core",
52         "coroutines",
53         "debuginfodwarf",
54         "executionengine",
55         "instrumentation",
56         "interpreter",
57         "ipo",
58         "irreader",
59         "linker",
60         "mc",
61         "mcjit",
62         "objcarcopts",
63         "option",
64         "profiledata",
65         "scalaropts",
66         "support",
67         "target",
68 }
69
70 func llvmConfig(args ...string) string {
71         configpath := os.Getenv("LLVM_CONFIG")
72         if configpath == "" {
73                 bin, _ := filepath.Split(os.Args[0])
74                 configpath = filepath.Join(bin, "llvm90-config")
75         }
76
77         cmd := exec.Command(configpath, args...)
78         cmd.Stderr = os.Stderr
79         out, err := cmd.Output()
80         if err != nil {
81                 panic(err.Error())
82         }
83
84         outstr := string(out)
85         outstr = strings.TrimSuffix(outstr, "\n")
86         outstr = strings.Replace(outstr, "\n", " ", -1)
87         return outstr
88 }
89
90 func llvmFlags() compilerFlags {
91         args := append([]string{"--ldflags", "--libs", "--system-libs"}, components...)
92         ldflags := llvmConfig(args...)
93         stdLibOption := ""
94         if strings.Contains(llvmConfig("--cxxflags"), "-stdlib=libc++") {
95                 // If libc++ is used to build LLVM libraries, -stdlib=libc++ is
96                 // needed to resolve dependent symbols
97                 stdLibOption = "-stdlib=libc++"
98         }
99         if runtime.GOOS != "darwin" {
100                 // OS X doesn't like -rpath with cgo. See:
101                 // https://github.com/golang/go/issues/7293
102                 ldflags = "-Wl,-rpath," + llvmConfig("--libdir") + " " + ldflags
103         }
104         return compilerFlags{
105                 cpp: llvmConfig("--cppflags"),
106                 cxx: "-std=c++11" + " " + stdLibOption,
107                 ld:  ldflags,
108         }
109 }
110
111 func addTag(args []string, tag string) []string {
112         args = append([]string{}, args...)
113         addedTag := false
114         for i, a := range args {
115                 if strings.HasPrefix(a, "-tags=") {
116                         args[i] = a + " " + tag
117                         addedTag = true
118                 } else if a == "-tags" && i+1 < len(args) {
119                         args[i+1] = args[i+1] + " " + tag
120                         addedTag = true
121                 }
122         }
123         if !addedTag {
124                 args = append([]string{args[0], "-tags", tag}, args[1:]...)
125         }
126         return args
127 }
128
129 func printComponents() {
130         fmt.Println(strings.Join(components, " "))
131 }
132
133 func printConfig() {
134         flags := llvmFlags()
135
136         fmt.Printf(`// +build !byollvm
137
138 // This file is generated by llvm-go, do not edit.
139
140 package llvm90
141
142 /*
143 #cgo CPPFLAGS: %s
144 #cgo CXXFLAGS: %s
145 #cgo LDFLAGS: %s
146 */
147 import "C"
148
149 type (run_build_sh int)
150 `, flags.cpp, flags.cxx, flags.ld)
151 }
152
153 func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags string, packages []pkg) {
154         args = addTag(args, "byollvm")
155
156         srcdir := llvmConfig("--src-root")
157
158         tmpgopath, err := ioutil.TempDir("", "gopath")
159         if err != nil {
160                 panic(err.Error())
161         }
162
163         for _, p := range packages {
164                 path := filepath.Join(tmpgopath, "src", p.pkgpath)
165                 err := os.MkdirAll(filepath.Dir(path), os.ModePerm)
166                 if err != nil {
167                         panic(err.Error())
168                 }
169
170                 abspath := p.llvmpath
171                 if !filepath.IsAbs(abspath) {
172                         abspath = filepath.Join(srcdir, abspath)
173                 }
174
175                 err = os.Symlink(abspath, path)
176                 if err != nil {
177                         panic(err.Error())
178                 }
179         }
180
181         newpath := os.Getenv("PATH")
182
183         newgopathlist := []string{tmpgopath}
184         newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...)
185         newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator))
186
187         flags := llvmFlags()
188
189         newenv := []string{
190                 "CC=" + cc,
191                 "CXX=" + cxx,
192                 "CGO_CPPFLAGS=" + flags.cpp + " " + cppflags,
193                 "CGO_CXXFLAGS=" + flags.cxx + " " + cxxflags,
194                 "CGO_LDFLAGS=" + flags.ld + " " + ldflags,
195                 "GOPATH=" + newgopath,
196                 "PATH=" + newpath,
197         }
198         if llgo != "" {
199                 newenv = append(newenv, "GCCGO="+llgo)
200         }
201
202         for _, v := range os.Environ() {
203                 if !strings.HasPrefix(v, "CC=") &&
204                         !strings.HasPrefix(v, "CXX=") &&
205                         !strings.HasPrefix(v, "CGO_CPPFLAGS=") &&
206                         !strings.HasPrefix(v, "CGO_CXXFLAGS=") &&
207                         !strings.HasPrefix(v, "CGO_LDFLAGS=") &&
208                         !strings.HasPrefix(v, "GCCGO=") &&
209                         !strings.HasPrefix(v, "GOPATH=") &&
210                         !strings.HasPrefix(v, "PATH=") {
211                         newenv = append(newenv, v)
212                 }
213         }
214
215         gocmdpath, err := exec.LookPath(gocmd)
216         if err != nil {
217                 panic(err.Error())
218         }
219
220         proc, err := os.StartProcess(gocmdpath, append([]string{gocmd}, args...),
221                 &os.ProcAttr{
222                         Env:   newenv,
223                         Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
224                 })
225         if err != nil {
226                 panic(err.Error())
227         }
228         ps, err := proc.Wait()
229         if err != nil {
230                 panic(err.Error())
231         }
232
233         os.RemoveAll(tmpgopath)
234
235         if !ps.Success() {
236                 os.Exit(1)
237         }
238 }
239
240 func usage() {
241         fmt.Println(`Usage: llvm-go subcommand [flags]
242
243 Available subcommands: build get install run test print-components print-config`)
244         os.Exit(0)
245 }
246
247 func main() {
248         cc := os.Getenv("CC")
249         cxx := os.Getenv("CXX")
250         cppflags := os.Getenv("CGO_CPPFLAGS")
251         cxxflags := os.Getenv("CGO_CXXFLAGS")
252         ldflags := os.Getenv("CGO_LDFLAGS")
253         gocmd := "go"
254         llgo := ""
255         packagesString := ""
256
257         flags := []struct {
258                 name string
259                 dest *string
260         }{
261                 {"cc", &cc},
262                 {"cxx", &cxx},
263                 {"go", &gocmd},
264                 {"llgo", &llgo},
265                 {"cppflags", &cppflags},
266                 {"ldflags", &ldflags},
267                 {"packages", &packagesString},
268         }
269
270         args := os.Args[1:]
271 LOOP:
272         for {
273                 if len(args) == 0 {
274                         usage()
275                 }
276                 for _, flag := range flags {
277                         if strings.HasPrefix(args[0], flag.name+"=") {
278                                 *flag.dest = args[0][len(flag.name)+1:]
279                                 args = args[1:]
280                                 continue LOOP
281                         }
282                 }
283                 break
284         }
285
286         packages := packages
287         if packagesString != "" {
288                 for _, field := range strings.Fields(packagesString) {
289                         pos := strings.IndexRune(field, '=')
290                         if pos == -1 {
291                                 fmt.Fprintf(os.Stderr, "invalid packages value %q, expected 'pkgpath=llvmpath [pkgpath=llvmpath ...]'\n", packagesString)
292                                 os.Exit(1)
293                         }
294                         packages = append(packages, pkg{
295                                 pkgpath:  field[:pos],
296                                 llvmpath: field[pos+1:],
297                         })
298                 }
299         }
300
301         switch args[0] {
302         case "build", "get", "install", "run", "test":
303                 runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags, packages)
304         case "print-components":
305                 printComponents()
306         case "print-config":
307                 printConfig()
308         default:
309                 usage()
310         }
311 }