From: Peter Collingbourne Date: Thu, 23 Oct 2014 02:33:23 +0000 (+0000) Subject: Add llvm-go tool. X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=bdc3a5b99af0dfbf2b0c4b1d59cd50f247b06522 Add llvm-go tool. 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". It is intended that components such as the Go frontend will be built in-tree using this tool. Differential Revision: http://reviews.llvm.org/D5902 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@220462 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/bindings/go/build.sh b/bindings/go/build.sh index 4a6b442eedb..3f0be00f808 100755 --- a/bindings/go/build.sh +++ b/bindings/go/build.sh @@ -1,36 +1,5 @@ #!/bin/sh -xe -llvm_components="\ -all-targets \ -analysis \ -asmparser \ -asmprinter \ -bitreader \ -bitwriter \ -codegen \ -core \ -debuginfo \ -executionengine \ -instrumentation \ -interpreter \ -ipo \ -irreader \ -linker \ -mc \ -mcjit \ -objcarcopts \ -option \ -profiledata \ -scalaropts \ -support \ -target \ -" - -if [ "$1" = "--print-components" ] ; then - echo $llvm_components - exit 0 -fi - gollvmdir=$(dirname "$0")/llvm workdir=$gollvmdir/workdir @@ -41,12 +10,14 @@ mkdir -p $llvm_builddir cmake_flags="../../../../.. $@" llvm_config="$llvm_builddir/bin/llvm-config" +llvm_go="$llvm_builddir/bin/llvm-go" if test -n "`which ninja`" ; then # If Ninja is available, we can speed up the build by building only the # required subset of LLVM. (cd $llvm_builddir && cmake -G Ninja $cmake_flags) - ninja -C $llvm_builddir llvm-config + ninja -C $llvm_builddir llvm-config llvm-go + llvm_components="$($llvm_go print-components)" llvm_buildtargets="$($llvm_config --libs $llvm_components | sed -e 's/-l//g')" ninja -C $llvm_builddir $llvm_buildtargets FileCheck else @@ -54,14 +25,7 @@ else make -C $llvm_builddir -j4 fi +$llvm_go print-config > $gollvmdir/llvm_config.go + llvm_version="$($llvm_config --version)" -llvm_cflags="$($llvm_config --cppflags)" -llvm_ldflags="$($llvm_config --ldflags) $($llvm_config --libs $llvm_components) $($llvm_config --system-libs)" -if [ $(uname) != "Darwin" ]; then - # OS X doesn't like -rpath with cgo. See: - # https://code.google.com/p/go/issues/detail?id=7293 - llvm_ldflags="-Wl,-rpath,$($llvm_config --libdir) $llvm_ldflags" -fi -sed -e "s#@LLVM_CFLAGS@#$llvm_cflags#g; s#@LLVM_LDFLAGS@#$llvm_ldflags#g" $gollvmdir/llvm_config.go.in > \ - $gollvmdir/llvm_config.go printf "package llvm\n\nconst Version = \"%s\"\n" "$llvm_version" > $gollvmdir/version.go diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake index 358a32cd107..8139d57ff83 100755 --- a/cmake/config-ix.cmake +++ b/cmake/config-ix.cmake @@ -493,16 +493,20 @@ else() endif() set(LLVM_BINDINGS "") -find_program(GO_EXECUTABLE NAMES go DOC "go executable") -if(GO_EXECUTABLE STREQUAL "GO_EXECUTABLE-NOTFOUND") +if(WIN32) message(STATUS "Go bindings disabled.") else() - execute_process(COMMAND ${GO_EXECUTABLE} run ${CMAKE_SOURCE_DIR}/bindings/go/conftest.go - RESULT_VARIABLE GO_CONFTEST) - if(GO_CONFTEST STREQUAL "0") - set(LLVM_BINDINGS "${LLVM_BINDINGS} go") - message(STATUS "Go bindings enabled.") + find_program(GO_EXECUTABLE NAMES go DOC "go executable") + if(GO_EXECUTABLE STREQUAL "GO_EXECUTABLE-NOTFOUND") + message(STATUS "Go bindings disabled.") else() - message(STATUS "Go bindings disabled, need at least Go 1.2.") + execute_process(COMMAND ${GO_EXECUTABLE} run ${CMAKE_SOURCE_DIR}/bindings/go/conftest.go + RESULT_VARIABLE GO_CONFTEST) + if(GO_CONFTEST STREQUAL "0") + set(LLVM_BINDINGS "${LLVM_BINDINGS} go") + message(STATUS "Go bindings enabled.") + else() + message(STATUS "Go bindings disabled, need at least Go 1.2.") + endif() endif() endif() diff --git a/test/Bindings/Go/go.test b/test/Bindings/Go/go.test index ff0cf90e1d8..3951483b6ff 100644 --- a/test/Bindings/Go/go.test +++ b/test/Bindings/Go/go.test @@ -1,8 +1,3 @@ -; RUN: cd %S/../../../bindings/go/llvm && \ -; RUN: env CGO_CPPFLAGS="$(llvm-config --cppflags)" \ -; RUN: CGO_CXXFLAGS=-std=c++11 \ -; RUN: CGO_LDFLAGS="$(llvm-config --ldflags --libs --system-libs \ -; RUN: $(../build.sh --print-components)) $CGO_LDFLAGS" \ -; RUN: %go test -tags byollvm . +; RUN: llvm-go test llvm.org/llvm/bindings/go/llvm ; REQUIRES: shell diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f20bc950385..14e54b7ffff 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,8 +30,9 @@ set(LLVM_TEST_DEPENDS llvm-cov llvm-diff llvm-dis - llvm-extract llvm-dwarfdump + llvm-extract + llvm-go llvm-link llvm-lto llvm-mc diff --git a/test/lit.cfg b/test/lit.cfg index 1b4df111921..55f559e68dc 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -200,6 +200,7 @@ for pattern in [r"\bbugpoint\b(?!-)", r"\bllvm-dis\b", r"\bllvm-dwarfdump\b", r"\bllvm-extract\b", + r"\bllvm-go\b", r"\bllvm-link\b", r"\bllvm-lto\b", r"\bllvm-mc\b", diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 940f656b598..2b0f853cbb4 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -52,6 +52,8 @@ add_llvm_tool_subdirectory(llvm-c-test) add_llvm_tool_subdirectory(obj2yaml) add_llvm_tool_subdirectory(yaml2obj) +add_llvm_tool_subdirectory(llvm-go) + if(NOT CYGWIN AND LLVM_ENABLE_PIC) add_llvm_tool_subdirectory(lto) add_llvm_tool_subdirectory(llvm-lto) diff --git a/tools/Makefile b/tools/Makefile index ff6e55d7299..4b8923a58d3 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -74,4 +74,8 @@ ifneq ($(ENABLE_SHARED),1) endif endif +ifneq (,$(filter go,$(BINDINGS_TO_BUILD))) + PARALLEL_DIRS += llvm-go +endif + include $(LEVEL)/Makefile.common diff --git a/tools/llvm-go/CMakeLists.txt b/tools/llvm-go/CMakeLists.txt new file mode 100644 index 00000000000..20393f728f8 --- /dev/null +++ b/tools/llvm-go/CMakeLists.txt @@ -0,0 +1,9 @@ +if(LLVM_BINDINGS MATCHES "go") + set(binpath ${CMAKE_BINARY_DIR}/bin/llvm-go${CMAKE_EXECUTABLE_SUFFIX}) + add_custom_command(OUTPUT ${binpath} + COMMAND ${GO_EXECUTABLE} build -o ${binpath} llvm-go.go + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/llvm-go.go + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Building Go executable llvm-go") + add_custom_target(llvm-go ALL DEPENDS ${binpath}) +endif() diff --git a/tools/llvm-go/Makefile b/tools/llvm-go/Makefile new file mode 100644 index 00000000000..4465b2a4a9d --- /dev/null +++ b/tools/llvm-go/Makefile @@ -0,0 +1,16 @@ +##===- tools/llvm-go/Makefile ------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +include $(LEVEL)/Makefile.common + +all:: $(ToolDir)/llvm-go$(EXEEXT) + +$(ToolDir)/llvm-go$(EXEEXT): $(PROJ_SRC_DIR)/llvm-go.go + $(GO) build -o $@ $< diff --git a/tools/llvm-go/llvm-go.go b/tools/llvm-go/llvm-go.go new file mode 100644 index 00000000000..47f948150f0 --- /dev/null +++ b/tools/llvm-go/llvm-go.go @@ -0,0 +1,261 @@ +//===-- 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"}, +} + +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, 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()) + } + } + + 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, + } + 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=") { + 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") + + 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], "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, cppflags, cxxflags, ldflags) + case "print-components": + printComponents() + case "print-config": + printConfig() + default: + usage() + } +}