aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Christopher <echristo@gmail.com>2020-02-13 12:53:32 -0800
committerEric Christopher <echristo@gmail.com>2020-02-13 17:24:55 -0800
commite635e48020adbe1139f2de8d2db0d4875d6d75a8 (patch)
tree2b5dbf95ab9fd442609f0541103bae49ffe87b26 /llvm/tools/llvm-go/llvm-go.go
parent[mlir][DeclarativeParser] Add support for formatting enum attributes in the s... (diff)
downloadllvm-project-e635e48020adbe1139f2de8d2db0d4875d6d75a8.tar.gz
llvm-project-e635e48020adbe1139f2de8d2db0d4875d6d75a8.tar.bz2
llvm-project-e635e48020adbe1139f2de8d2db0d4875d6d75a8.zip
Reinstate llvm-go to test the go bindings.
This partially reverts commit 102814b4d36ad004a2e37cd2a1e84bd2c3593d29.
Diffstat (limited to 'llvm/tools/llvm-go/llvm-go.go')
-rw-r--r--llvm/tools/llvm-go/llvm-go.go311
1 files changed, 311 insertions, 0 deletions
diff --git a/llvm/tools/llvm-go/llvm-go.go b/llvm/tools/llvm-go/llvm-go.go
new file mode 100644
index 000000000000..a0561dd5fd8d
--- /dev/null
+++ b/llvm/tools/llvm-go/llvm-go.go
@@ -0,0 +1,311 @@
+//===-- llvm-go.go - go tool wrapper for LLVM -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool lets us build LLVM components within the tree by setting up a
+// $GOPATH that resembles a tree fetched in the normal way with "go get".
+//
+//===----------------------------------------------------------------------===//
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+const (
+ linkmodeComponentLibs = "component-libs"
+ linkmodeDylib = "dylib"
+)
+
+type pkg struct {
+ llvmpath, pkgpath string
+}
+
+var packages = []pkg{
+ {"bindings/go/llvm", "llvm.org/llvm/bindings/go/llvm"},
+}
+
+type compilerFlags struct {
+ cpp, cxx, ld string
+}
+
+var components = []string{
+ "all-targets",
+ "analysis",
+ "asmparser",
+ "asmprinter",
+ "bitreader",
+ "bitwriter",
+ "codegen",
+ "core",
+ "coroutines",
+ "debuginfodwarf",
+ "executionengine",
+ "instrumentation",
+ "interpreter",
+ "ipo",
+ "irreader",
+ "linker",
+ "mc",
+ "mcjit",
+ "objcarcopts",
+ "option",
+ "profiledata",
+ "scalaropts",
+ "support",
+ "target",
+}
+
+func llvmConfig(args ...string) string {
+ configpath := os.Getenv("LLVM_CONFIG")
+ if configpath == "" {
+ bin, _ := filepath.Split(os.Args[0])
+ configpath = filepath.Join(bin, "llvm-config")
+ }
+
+ cmd := exec.Command(configpath, args...)
+ cmd.Stderr = os.Stderr
+ out, err := cmd.Output()
+ if err != nil {
+ panic(err.Error())
+ }
+
+ outstr := string(out)
+ outstr = strings.TrimSuffix(outstr, "\n")
+ outstr = strings.Replace(outstr, "\n", " ", -1)
+ return outstr
+}
+
+func llvmFlags() compilerFlags {
+ args := append([]string{"--ldflags", "--libs", "--system-libs"}, components...)
+ ldflags := llvmConfig(args...)
+ stdLibOption := ""
+ if strings.Contains(llvmConfig("--cxxflags"), "-stdlib=libc++") {
+ // If libc++ is used to build LLVM libraries, -stdlib=libc++ is
+ // needed to resolve dependent symbols
+ stdLibOption = "-stdlib=libc++"
+ }
+ if runtime.GOOS != "darwin" {
+ // OS X doesn't like -rpath with cgo. See:
+ // https://github.com/golang/go/issues/7293
+ ldflags = "-Wl,-rpath," + llvmConfig("--libdir") + " " + ldflags
+ }
+ return compilerFlags{
+ cpp: llvmConfig("--cppflags"),
+ cxx: "-std=c++14" + " " + stdLibOption,
+ ld: ldflags,
+ }
+}
+
+func addTag(args []string, tag string) []string {
+ args = append([]string{}, args...)
+ addedTag := false
+ for i, a := range args {
+ if strings.HasPrefix(a, "-tags=") {
+ args[i] = a + " " + tag
+ addedTag = true
+ } else if a == "-tags" && i+1 < len(args) {
+ args[i+1] = args[i+1] + " " + tag
+ addedTag = true
+ }
+ }
+ if !addedTag {
+ args = append([]string{args[0], "-tags", tag}, args[1:]...)
+ }
+ return args
+}
+
+func printComponents() {
+ fmt.Println(strings.Join(components, " "))
+}
+
+func printConfig() {
+ flags := llvmFlags()
+
+ fmt.Printf(`// +build !byollvm
+
+// This file is generated by llvm-go, do not edit.
+
+package llvm
+
+/*
+#cgo CPPFLAGS: %s
+#cgo CXXFLAGS: %s
+#cgo LDFLAGS: %s
+*/
+import "C"
+
+type (run_build_sh int)
+`, flags.cpp, flags.cxx, flags.ld)
+}
+
+func runGoWithLLVMEnv(args []string, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags string, packages []pkg) {
+ args = addTag(args, "byollvm")
+
+ srcdir := llvmConfig("--src-root")
+
+ tmpgopath, err := ioutil.TempDir("", "gopath")
+ if err != nil {
+ panic(err.Error())
+ }
+
+ for _, p := range packages {
+ path := filepath.Join(tmpgopath, "src", p.pkgpath)
+ err := os.MkdirAll(filepath.Dir(path), os.ModePerm)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ abspath := p.llvmpath
+ if !filepath.IsAbs(abspath) {
+ abspath = filepath.Join(srcdir, abspath)
+ }
+
+ err = os.Symlink(abspath, path)
+ if err != nil {
+ panic(err.Error())
+ }
+ }
+
+ newpath := os.Getenv("PATH")
+
+ newgopathlist := []string{tmpgopath}
+ newgopathlist = append(newgopathlist, filepath.SplitList(os.Getenv("GOPATH"))...)
+ newgopath := strings.Join(newgopathlist, string(filepath.ListSeparator))
+
+ flags := llvmFlags()
+
+ newenv := []string{
+ "CC=" + cc,
+ "CXX=" + cxx,
+ "CGO_CPPFLAGS=" + flags.cpp + " " + cppflags,
+ "CGO_CXXFLAGS=" + flags.cxx + " " + cxxflags,
+ "CGO_LDFLAGS=" + flags.ld + " " + ldflags,
+ "GOPATH=" + newgopath,
+ "PATH=" + newpath,
+ }
+ if llgo != "" {
+ newenv = append(newenv, "GCCGO="+llgo)
+ }
+
+ for _, v := range os.Environ() {
+ if !strings.HasPrefix(v, "CC=") &&
+ !strings.HasPrefix(v, "CXX=") &&
+ !strings.HasPrefix(v, "CGO_CPPFLAGS=") &&
+ !strings.HasPrefix(v, "CGO_CXXFLAGS=") &&
+ !strings.HasPrefix(v, "CGO_LDFLAGS=") &&
+ !strings.HasPrefix(v, "GCCGO=") &&
+ !strings.HasPrefix(v, "GOPATH=") &&
+ !strings.HasPrefix(v, "PATH=") {
+ newenv = append(newenv, v)
+ }
+ }
+
+ gocmdpath, err := exec.LookPath(gocmd)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ proc, err := os.StartProcess(gocmdpath, append([]string{gocmd}, args...),
+ &os.ProcAttr{
+ Env: newenv,
+ Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
+ })
+ if err != nil {
+ panic(err.Error())
+ }
+ ps, err := proc.Wait()
+ if err != nil {
+ panic(err.Error())
+ }
+
+ os.RemoveAll(tmpgopath)
+
+ if !ps.Success() {
+ os.Exit(1)
+ }
+}
+
+func usage() {
+ fmt.Println(`Usage: llvm-go subcommand [flags]
+
+Available subcommands: build get install run test print-components print-config`)
+ os.Exit(0)
+}
+
+func main() {
+ cc := os.Getenv("CC")
+ cxx := os.Getenv("CXX")
+ cppflags := os.Getenv("CGO_CPPFLAGS")
+ cxxflags := os.Getenv("CGO_CXXFLAGS")
+ ldflags := os.Getenv("CGO_LDFLAGS")
+ gocmd := "go"
+ llgo := ""
+ packagesString := ""
+
+ flags := []struct {
+ name string
+ dest *string
+ }{
+ {"cc", &cc},
+ {"cxx", &cxx},
+ {"go", &gocmd},
+ {"llgo", &llgo},
+ {"cppflags", &cppflags},
+ {"ldflags", &ldflags},
+ {"packages", &packagesString},
+ }
+
+ args := os.Args[1:]
+LOOP:
+ for {
+ if len(args) == 0 {
+ usage()
+ }
+ for _, flag := range flags {
+ if strings.HasPrefix(args[0], flag.name+"=") {
+ *flag.dest = args[0][len(flag.name)+1:]
+ args = args[1:]
+ continue LOOP
+ }
+ }
+ break
+ }
+
+ packages := packages
+ if packagesString != "" {
+ for _, field := range strings.Fields(packagesString) {
+ pos := strings.IndexRune(field, '=')
+ if pos == -1 {
+ fmt.Fprintf(os.Stderr, "invalid packages value %q, expected 'pkgpath=llvmpath [pkgpath=llvmpath ...]'\n", packagesString)
+ os.Exit(1)
+ }
+ packages = append(packages, pkg{
+ pkgpath: field[:pos],
+ llvmpath: field[pos+1:],
+ })
+ }
+ }
+
+ switch args[0] {
+ case "build", "get", "install", "run", "test":
+ runGoWithLLVMEnv(args, cc, cxx, gocmd, llgo, cppflags, cxxflags, ldflags, packages)
+ case "print-components":
+ printComponents()
+ case "print-config":
+ printConfig()
+ default:
+ usage()
+ }
+}