1 //===-- llvm-go.go - go tool wrapper for LLVM -----------------------------===//
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
7 //===----------------------------------------------------------------------===//
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".
12 //===----------------------------------------------------------------------===//
27 linkmodeComponentLibs
= "component-libs"
28 linkmodeDylib
= "dylib"
32 llvmpath
, pkgpath
string
36 {"bindings/go/llvm", "llvm.org/llvm/bindings/go/llvm"},
39 type compilerFlags
struct {
43 var components
= []string{
70 func llvmConfig(args
...string) string {
71 configpath
:= os
.Getenv("LLVM_CONFIG")
73 bin
, _
:= filepath
.Split(os
.Args
[0])
74 configpath
= filepath
.Join(bin
, "llvm-config")
77 cmd
:= exec
.Command(configpath
, args
...)
78 cmd
.Stderr
= os
.Stderr
79 out
, err
:= cmd
.Output()
85 outstr
= strings
.TrimSuffix(outstr
, "\n")
86 outstr
= strings
.Replace(outstr
, "\n", " ", -1)
90 func llvmFlags() compilerFlags
{
91 args
:= append([]string{"--ldflags", "--libs", "--system-libs"}, components
...)
92 ldflags
:= llvmConfig(args
...)
93 if runtime
.GOOS
!= "darwin" {
94 // OS X doesn't like -rpath with cgo. See:
95 // https://github.com/golang/go/issues/7293
96 ldflags
= "-Wl,-rpath," + llvmConfig("--libdir") + " " + ldflags
99 cpp
: llvmConfig("--cppflags"),
105 func addTag(args
[]string, tag
string) []string {
106 args
= append([]string{}, args
...)
108 for i
, a
:= range args
{
109 if strings
.HasPrefix(a
, "-tags=") {
110 args
[i
] = a
+ " " + tag
112 } else if a
== "-tags" && i
+1 < len(args
) {
113 args
[i
+1] = args
[i
+1] + " " + tag
118 args
= append([]string{args
[0], "-tags", tag
}, args
[1:]...)
123 func printComponents() {
124 fmt
.Println(strings
.Join(components
, " "))
130 fmt
.Printf(`// +build !byollvm
132 // This file is generated by llvm-go, do not edit.
143 type (run_build_sh int)
144 `, flags
.cpp
, flags
.cxx
, flags
.ld
)
147 func runGoWithLLVMEnv(args
[]string, cc
, cxx
, gocmd
, llgo
, cppflags
, cxxflags
, ldflags
string, packages
[]pkg
) {
148 args
= addTag(args
, "byollvm")
150 srcdir
:= llvmConfig("--src-root")
152 tmpgopath
, err
:= ioutil
.TempDir("", "gopath")
157 for _
, p
:= range packages
{
158 path
:= filepath
.Join(tmpgopath
, "src", p
.pkgpath
)
159 err
:= os
.MkdirAll(filepath
.Dir(path
), os
.ModePerm
)
164 abspath
:= p
.llvmpath
165 if !filepath
.IsAbs(abspath
) {
166 abspath
= filepath
.Join(srcdir
, abspath
)
169 err
= os
.Symlink(abspath
, path
)
175 newpath
:= os
.Getenv("PATH")
177 newgopathlist
:= []string{tmpgopath
}
178 newgopathlist
= append(newgopathlist
, filepath
.SplitList(os
.Getenv("GOPATH"))...)
179 newgopath
:= strings
.Join(newgopathlist
, string(filepath
.ListSeparator
))
186 "CGO_CPPFLAGS=" + flags
.cpp
+ " " + cppflags
,
187 "CGO_CXXFLAGS=" + flags
.cxx
+ " " + cxxflags
,
188 "CGO_LDFLAGS=" + flags
.ld
+ " " + ldflags
,
189 "GOPATH=" + newgopath
,
193 newenv
= append(newenv
, "GCCGO="+llgo
)
196 for _
, v
:= range os
.Environ() {
197 if !strings
.HasPrefix(v
, "CC=") &&
198 !strings
.HasPrefix(v
, "CXX=") &&
199 !strings
.HasPrefix(v
, "CGO_CPPFLAGS=") &&
200 !strings
.HasPrefix(v
, "CGO_CXXFLAGS=") &&
201 !strings
.HasPrefix(v
, "CGO_LDFLAGS=") &&
202 !strings
.HasPrefix(v
, "GCCGO=") &&
203 !strings
.HasPrefix(v
, "GOPATH=") &&
204 !strings
.HasPrefix(v
, "PATH=") {
205 newenv
= append(newenv
, v
)
209 gocmdpath
, err
:= exec
.LookPath(gocmd
)
214 proc
, err
:= os
.StartProcess(gocmdpath
, append([]string{gocmd
}, args
...),
217 Files
: []*os
.File
{os
.Stdin
, os
.Stdout
, os
.Stderr
},
222 ps
, err
:= proc
.Wait()
227 os
.RemoveAll(tmpgopath
)
235 fmt
.Println(`Usage: llvm-go subcommand [flags]
237 Available subcommands: build get install run test print-components print-config`)
242 cc
:= os
.Getenv("CC")
243 cxx
:= os
.Getenv("CXX")
244 cppflags
:= os
.Getenv("CGO_CPPFLAGS")
245 cxxflags
:= os
.Getenv("CGO_CXXFLAGS")
246 ldflags
:= os
.Getenv("CGO_LDFLAGS")
259 {"cppflags", &cppflags
},
260 {"ldflags", &ldflags
},
261 {"packages", &packagesString
},
270 for _
, flag
:= range flags
{
271 if strings
.HasPrefix(args
[0], flag
.name
+"=") {
272 *flag
.dest
= args
[0][len(flag
.name
)+1:]
281 if packagesString
!= "" {
282 for _
, field
:= range strings
.Fields(packagesString
) {
283 pos
:= strings
.IndexRune(field
, '=')
285 fmt
.Fprintf(os
.Stderr
, "invalid packages value %q, expected 'pkgpath=llvmpath [pkgpath=llvmpath ...]'\n", packagesString
)
288 packages
= append(packages
, pkg
{
289 pkgpath
: field
[:pos
],
290 llvmpath
: field
[pos
+1:],
296 case "build", "get", "install", "run", "test":
297 runGoWithLLVMEnv(args
, cc
, cxx
, gocmd
, llgo
, cppflags
, cxxflags
, ldflags
, packages
)
298 case "print-components":