forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			291 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Go
		
	
	
	
//===-- llvm-go.go - go tool wrapper for LLVM -----------------------------===//
 | 
						|
//
 | 
						|
//                     The LLVM Compiler Infrastructure
 | 
						|
//
 | 
						|
// This file is distributed under the University of Illinois Open Source
 | 
						|
// License. See LICENSE.TXT for details.
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// 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"
 | 
						|
)
 | 
						|
 | 
						|
type pkg struct {
 | 
						|
	llvmpath, pkgpath string
 | 
						|
}
 | 
						|
 | 
						|
var packages = []pkg{
 | 
						|
	{"bindings/go/llvm", "llvm.org/llvm/bindings/go/llvm"},
 | 
						|
	{"tools/llgo", "llvm.org/llgo"},
 | 
						|
}
 | 
						|
 | 
						|
type compilerFlags struct {
 | 
						|
	cpp, cxx, ld string
 | 
						|
}
 | 
						|
 | 
						|
var components = []string{
 | 
						|
	"all-targets",
 | 
						|
	"analysis",
 | 
						|
	"asmparser",
 | 
						|
	"asmprinter",
 | 
						|
	"bitreader",
 | 
						|
	"bitwriter",
 | 
						|
	"codegen",
 | 
						|
	"core",
 | 
						|
	"debuginfo",
 | 
						|
	"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 == "" {
 | 
						|
		// strip llvm-go, add llvm-config
 | 
						|
		configpath = os.Args[0][:len(os.Args[0])-7] + "llvm-config"
 | 
						|
	}
 | 
						|
 | 
						|
	cmd := exec.Command(configpath, args...)
 | 
						|
	out, err := cmd.Output()
 | 
						|
	if err != nil {
 | 
						|
		panic(err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	outstr := string(out)
 | 
						|
	outstr = strings.TrimSuffix(outstr, "\n")
 | 
						|
	return strings.Replace(outstr, "\n", " ", -1)
 | 
						|
}
 | 
						|
 | 
						|
func llvmFlags() compilerFlags {
 | 
						|
	ldflags := llvmConfig(append([]string{"--ldflags", "--libs", "--system-libs"}, components...)...)
 | 
						|
	if runtime.GOOS != "darwin" {
 | 
						|
		// OS X doesn't like -rpath with cgo. See:
 | 
						|
		// https://code.google.com/p/go/issues/detail?id=7293
 | 
						|
		ldflags = "-Wl,-rpath," + llvmConfig("--libdir") + " " + ldflags
 | 
						|
	}
 | 
						|
	return compilerFlags{
 | 
						|
		cpp: llvmConfig("--cppflags"),
 | 
						|
		cxx: "-std=c++11",
 | 
						|
		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, llgo, cppflags, cxxflags, ldflags string) {
 | 
						|
	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())
 | 
						|
		}
 | 
						|
 | 
						|
		err = os.Symlink(filepath.Join(srcdir, p.llvmpath), path)
 | 
						|
		if err != nil {
 | 
						|
			panic(err.Error())
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	newpath := os.Getenv("PATH")
 | 
						|
 | 
						|
	if llgo != "" {
 | 
						|
		bindir := filepath.Join(tmpgopath, "bin")
 | 
						|
 | 
						|
		err = os.MkdirAll(bindir, os.ModePerm)
 | 
						|
		if err != nil {
 | 
						|
			panic(err.Error())
 | 
						|
		}
 | 
						|
 | 
						|
		err = os.Symlink(llgo, filepath.Join(bindir, "gccgo"))
 | 
						|
		if err != nil {
 | 
						|
			panic(err.Error())
 | 
						|
		}
 | 
						|
 | 
						|
		newpathlist := []string{bindir}
 | 
						|
		newpathlist = append(newpathlist, filepath.SplitList(newpath)...)
 | 
						|
		newpath = strings.Join(newpathlist, string(filepath.ListSeparator))
 | 
						|
 | 
						|
		args = append([]string{args[0], "-compiler", "gccgo"}, args[1:]...)
 | 
						|
	}
 | 
						|
 | 
						|
	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,
 | 
						|
	}
 | 
						|
	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, "GOPATH=") &&
 | 
						|
			!strings.HasPrefix(v, "PATH=") {
 | 
						|
			newenv = append(newenv, v)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	gocmdpath, err := exec.LookPath("go")
 | 
						|
	if err != nil {
 | 
						|
		panic(err.Error())
 | 
						|
	}
 | 
						|
 | 
						|
	proc, err := os.StartProcess(gocmdpath, append([]string{"go"}, 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")
 | 
						|
	llgo := ""
 | 
						|
 | 
						|
	args := os.Args[1:]
 | 
						|
	DONE: for {
 | 
						|
		switch {
 | 
						|
		case len(args) == 0:
 | 
						|
			usage()
 | 
						|
		case strings.HasPrefix(args[0], "cc="):
 | 
						|
			cc = args[0][3:]
 | 
						|
			args = args[1:]
 | 
						|
		case strings.HasPrefix(args[0], "cxx="):
 | 
						|
			cxx = args[0][4:]
 | 
						|
			args = args[1:]
 | 
						|
		case strings.HasPrefix(args[0], "llgo="):
 | 
						|
			llgo = args[0][5:]
 | 
						|
			args = args[1:]
 | 
						|
		case strings.HasPrefix(args[0], "cppflags="):
 | 
						|
			cppflags = args[0][9:]
 | 
						|
			args = args[1:]
 | 
						|
		case strings.HasPrefix(args[0], "cxxflags="):
 | 
						|
			cxxflags = args[0][9:]
 | 
						|
			args = args[1:]
 | 
						|
		case strings.HasPrefix(args[0], "ldflags="):
 | 
						|
			ldflags = args[0][8:]
 | 
						|
			args = args[1:]
 | 
						|
		default:
 | 
						|
			break DONE
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	switch args[0] {
 | 
						|
	case "build", "get", "install", "run", "test":
 | 
						|
		runGoWithLLVMEnv(args, cc, cxx, llgo, cppflags, cxxflags, ldflags)
 | 
						|
	case "print-components":
 | 
						|
		printComponents()
 | 
						|
	case "print-config":
 | 
						|
		printConfig()
 | 
						|
	default:
 | 
						|
		usage()
 | 
						|
	}
 | 
						|
}
 |