diff options
author | Eric Christopher <echristo@gmail.com> | 2020-02-13 12:53:32 -0800 |
---|---|---|
committer | Eric Christopher <echristo@gmail.com> | 2020-02-13 17:24:55 -0800 |
commit | e635e48020adbe1139f2de8d2db0d4875d6d75a8 (patch) | |
tree | 2b5dbf95ab9fd442609f0541103bae49ffe87b26 /llvm/tools/llvm-go/llvm-go.go | |
parent | [mlir][DeclarativeParser] Add support for formatting enum attributes in the s... (diff) | |
download | llvm-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.go | 311 |
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() + } +} |