aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2019-01-26 00:30:28 +0100
committerAyke van Laethem <[email protected]>2019-02-01 13:26:32 +0100
commit25cd98226399922f6586515ee3d69592633725a7 (patch)
treeac46cc4c9be9c2d5bcb1708fb7d7a5475f035bf3
parent9bbb233cf02be8f0521bfbc6f96f70c8a0c5c6b8 (diff)
downloadtinygo-25cd98226399922f6586515ee3d69592633725a7.tar.gz
tinygo-25cd98226399922f6586515ee3d69592633725a7.zip
main: optionally build with LLD
When building statically against LLVM, LLD is also included now. When included, the built in wasm-ld will automatically be used instead of the external command. There is also support for linking ELF files but because lld does not fully support armv6m this is not yet enabled (it produces a warning).
-rw-r--r--BUILDING.md28
-rw-r--r--Makefile9
-rw-r--r--linker-builtin.go66
-rw-r--r--linker-external.go22
-rw-r--r--lld.cpp19
-rw-r--r--main.go12
-rw-r--r--targets/wasm.json3
7 files changed, 134 insertions, 25 deletions
diff --git a/BUILDING.md b/BUILDING.md
index cd15d77db..55b9f74d6 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -1,16 +1,17 @@
# Building TinyGo
-TinyGo depends on LLVM and libclang, which are both big C++ libraries. There are
-two ways these can be linked: dynamically and statically. The default is dynamic
-linking because it is fast and works almost out of the box on Debian-based
-systems with the right libraries installed.
+TinyGo depends on LLVM and libclang, which are both big C++ libraries. It can
+also optionally use a built-in lld to ease cross compiling. There are two ways
+these can be linked: dynamically and statically. The default is dynamic linking
+because it is fast and works almost out of the box on Debian-based systems with
+the right libraries installed.
-This guide describes how to statically link TinyGo against LLVM and libclang so
-that the binary can be easily moved between systems.
+This guide describes how to statically link TinyGo against LLVM, libclang and
+lld so that the binary can be easily moved between systems.
## Dependencies
-LLVM and Clang are both quite light on dependencies, requiring only standard
+LLVM, Clang and LLD are quite light on dependencies, requiring only standard
build tools to be built. Go is of course necessary to build TinyGo itself.
* Go (1.11+)
@@ -30,14 +31,15 @@ The first step is to get the source code. Place it in some directory, assuming
git clone -b release_70 https://github.com/llvm-mirror/llvm.git $HOME/src/llvm
git clone -b release_70 https://github.com/llvm-mirror/clang.git $HOME/src/llvm/tools/clang
+ git clone -b release_70 https://github.com/llvm-mirror/lld.git $HOME/src/llvm/tools/lld
go get -d github.com/tinygo-org/tinygo
cd $HOME/go/src/github.com/tinygo-org/tinygo
dep ensure -vendor-only # download dependencies
-Note that Clang must be placed inside the tools subdirectory of LLVM to be
-automatically built with the rest of the system.
+Note that Clang and LLD must be placed inside the tools subdirectory of LLVM to
+be automatically built with the rest of the system.
-## Build LLVM and Clang
+## Build LLVM, Clang, LLD
Building LLVM is quite easy compared to some other software packages. However,
the default configuration is _not_ optimized for distribution. It is optimized
@@ -86,10 +88,10 @@ This can take over an hour depending on the speed of your system.
## Build TinyGo
Now that you have a working version of LLVM, build TinyGo using it. You need to
-specify the directories to the LLVM build directory and to the Clang source.
+specify the directories to the LLVM build directory and to the Clang and LLD source.
cd $HOME/go/src/github.com/tinygo-org/tinygo
- make static LLVM_BUILDDIR=$HOME/src/llvm-build CLANG_SRC=$HOME/src/llvm/tools/clang
+ make static LLVM_BUILDDIR=$HOME/src/llvm-build CLANG_SRC=$HOME/src/llvm/tools/clang LLD_SRC=$HOME/src/llvm/tools/lld
## Verify TinyGo
@@ -98,7 +100,7 @@ Try running TinyGo:
./build/tinygo help
Also, make sure the `tinygo` binary really is statically linked. Check this
-using `ldd`:
+using `ldd` (not to be confused with `lld`):
ldd ./build/tinygo
diff --git a/Makefile b/Makefile
index c913c92d0..c42eb805f 100644
--- a/Makefile
+++ b/Makefile
@@ -40,14 +40,17 @@ $(error Unknown target)
endif
-LLVM_COMPONENTS = 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
+LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines debuginfodwarf executionengine instrumentation interpreter ipo irreader linker lto mc mcjit objcarcopts option profiledata scalaropts support target
CLANG_LIBS = -Wl,--start-group $(abspath $(LLVM_BUILDDIR))/lib/libclang.a -lclangAnalysis -lclangARCMigrate -lclangAST -lclangASTMatchers -lclangBasic -lclangCodeGen -lclangCrossTU -lclangDriver -lclangDynamicASTMatchers -lclangEdit -lclangFormat -lclangFrontend -lclangFrontendTool -lclangHandleCXX -lclangHandleLLVM -lclangIndex -lclangLex -lclangParse -lclangRewrite -lclangRewriteFrontend -lclangSema -lclangSerialization -lclangStaticAnalyzerCheckers -lclangStaticAnalyzerCore -lclangStaticAnalyzerFrontend -lclangTooling -lclangToolingASTDiff -lclangToolingCore -lclangToolingInclusions -lclangToolingRefactor -Wl,--end-group -lstdc++
+LLD_LIBS = -Wl,--start-group -llldCOFF -llldCommon -llldCore -llldDriver -llldELF -llldMachO -llldMinGW -llldReaderWriter -llldWasm -llldYAML -Wl,--end-group
+
+
# For static linking.
-CGO_CPPFLAGS=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(CLANG_SRC))/include
+CGO_CPPFLAGS=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
CGO_CXXFLAGS=-std=c++11
-CGO_LDFLAGS=-L$(LLVM_BUILDDIR)/lib $(CLANG_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS))
+CGO_LDFLAGS=-L$(LLVM_BUILDDIR)/lib $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS))
diff --git a/linker-builtin.go b/linker-builtin.go
new file mode 100644
index 000000000..ba63f8279
--- /dev/null
+++ b/linker-builtin.go
@@ -0,0 +1,66 @@
+// +build byollvm
+
+package main
+
+// This file provides a Link() function that uses the bundled lld if possible.
+
+import (
+ "errors"
+ "os"
+ "os/exec"
+ "unsafe"
+)
+
+/*
+#include <stdbool.h>
+#include <stdlib.h>
+bool tinygo_link_elf(int argc, char **argv);
+bool tinygo_link_wasm(int argc, char **argv);
+*/
+import "C"
+
+// Link invokes a linker with the given name and flags.
+//
+// This version uses the built-in linker when trying to use lld.
+func Link(dir, linker string, flags ...string) error {
+ switch linker {
+ case "ld.lld", commands["ld.lld"]:
+ flags = append([]string{"tinygo:" + linker}, flags...)
+ var cflag *C.char
+ buf := C.calloc(C.size_t(len(flags)), C.size_t(unsafe.Sizeof(cflag)))
+ cflags := (*[1 << 10]*C.char)(unsafe.Pointer(buf))[:len(flags):len(flags)]
+ for i, flag := range flags {
+ cflag := C.CString(flag)
+ cflags[i] = cflag
+ defer C.free(unsafe.Pointer(cflag))
+ }
+ ok := C.tinygo_link_elf(C.int(len(flags)), (**C.char)(buf))
+ if !ok {
+ return errors.New("failed to link using built-in ld.lld")
+ }
+ return nil
+ case "wasm-ld", commands["wasm-ld"]:
+ flags = append([]string{"tinygo:" + linker}, flags...)
+ var cflag *C.char
+ buf := C.calloc(C.size_t(len(flags)), C.size_t(unsafe.Sizeof(cflag)))
+ defer C.free(buf)
+ cflags := (*[1 << 10]*C.char)(unsafe.Pointer(buf))[:len(flags):len(flags)]
+ for i, flag := range flags {
+ cflag := C.CString(flag)
+ cflags[i] = cflag
+ defer C.free(unsafe.Pointer(cflag))
+ }
+ ok := C.tinygo_link_wasm(C.int(len(flags)), (**C.char)(buf))
+ if !ok {
+ return errors.New("failed to link using built-in wasm-ld")
+ }
+ return nil
+ default:
+ // Fall back to external command.
+ cmd := exec.Command(linker, flags...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.Dir = dir
+ return cmd.Run()
+ }
+}
diff --git a/linker-external.go b/linker-external.go
new file mode 100644
index 000000000..d0c8126ad
--- /dev/null
+++ b/linker-external.go
@@ -0,0 +1,22 @@
+// +build !byollvm
+
+package main
+
+// This file provides a Link() function that always runs an external command. It
+// is provided for when tinygo is built without linking to liblld.
+
+import (
+ "os"
+ "os/exec"
+)
+
+// Link invokes a linker with the given name and arguments.
+//
+// This version always runs the linker as an external command.
+func Link(dir, linker string, flags ...string) error {
+ cmd := exec.Command(linker, flags...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.Dir = dir
+ return cmd.Run()
+}
diff --git a/lld.cpp b/lld.cpp
new file mode 100644
index 000000000..2373edeec
--- /dev/null
+++ b/lld.cpp
@@ -0,0 +1,19 @@
+// +build byollvm
+
+// This file provides C wrappers for liblld.
+
+#include <lld/Common/Driver.h>
+
+extern "C" {
+
+bool tinygo_link_elf(int argc, char **argv) {
+ std::vector<const char*> args(argv, argv + argc);
+ return lld::elf::link(args, false);
+}
+
+bool tinygo_link_wasm(int argc, char **argv) {
+ std::vector<const char*> args(argv, argv + argc);
+ return lld::wasm::link(args, false);
+}
+
+} // external "C"
diff --git a/main.go b/main.go
index 3f61b83c3..65f2effbd 100644
--- a/main.go
+++ b/main.go
@@ -21,8 +21,10 @@ import (
)
var commands = map[string]string{
- "ar": "ar",
- "clang": "clang-7",
+ "ar": "ar",
+ "clang": "clang-7",
+ "ld.lld": "ld.lld-7",
+ "wasm-ld": "wasm-ld-7",
}
// commandError is an error type to wrap os/exec.Command errors. This provides
@@ -234,11 +236,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
}
// Link the object files together.
- cmd := exec.Command(spec.Linker, ldflags...)
- cmd.Stdout = os.Stdout
- cmd.Stderr = os.Stderr
- cmd.Dir = sourceDir()
- err = cmd.Run()
+ err = Link(sourceDir(), spec.Linker, ldflags...)
if err != nil {
return &commandError{"failed to link", executable, err}
}
diff --git a/targets/wasm.json b/targets/wasm.json
index 7deb29a31..d7eab5a53 100644
--- a/targets/wasm.json
+++ b/targets/wasm.json
@@ -4,13 +4,12 @@
"goos": "js",
"goarch": "wasm",
"compiler": "clang-7",
- "linker": "ld.lld-7",
+ "linker": "wasm-ld-7",
"cflags": [
"--target=wasm32",
"-Oz"
],
"ldflags": [
- "-flavor", "wasm",
"-allow-undefined"
],
"emulator": ["cwa"]