aboutsummaryrefslogtreecommitdiffhomepage
path: root/builder/clang.cpp
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2019-12-04 16:14:39 +0100
committerRon Evans <[email protected]>2019-12-11 20:17:35 +0100
commit8d32a7c3a399ce62564f66c75e9553caf7327264 (patch)
tree67d93ff9d55c13b7b21e5ecfe2204be1ed98b982 /builder/clang.cpp
parent49eb414530b0b5bbe07579a9b11e03839787dac0 (diff)
downloadtinygo-8d32a7c3a399ce62564f66c75e9553caf7327264.tar.gz
tinygo-8d32a7c3a399ce62564f66c75e9553caf7327264.zip
builder: use builtin Clang when building statically
This will be a huge help for people installing TinyGo that don't have LLVM/Clang 9 already installed and in the $PATH variable.
Diffstat (limited to 'builder/clang.cpp')
-rw-r--r--builder/clang.cpp97
1 files changed, 97 insertions, 0 deletions
diff --git a/builder/clang.cpp b/builder/clang.cpp
new file mode 100644
index 000000000..e0993bf6e
--- /dev/null
+++ b/builder/clang.cpp
@@ -0,0 +1,97 @@
+// +build byollvm
+
+#include <clang/Basic/DiagnosticOptions.h>
+#include <clang/CodeGen/CodeGenAction.h>
+#include <clang/Driver/Compilation.h>
+#include <clang/Driver/Driver.h>
+#include <clang/Frontend/CompilerInstance.h>
+#include <clang/Frontend/CompilerInvocation.h>
+#include <clang/Frontend/FrontendDiagnostic.h>
+#include <clang/Frontend/TextDiagnosticPrinter.h>
+#include <clang/FrontendTool/Utils.h>
+#include <llvm/ADT/IntrusiveRefCntPtr.h>
+#include <llvm/Option/Option.h>
+
+using namespace llvm;
+using namespace clang;
+
+#include "cc1as.h"
+
+// This file provides C wrappers for the builtin tools cc1 and cc1as
+// provided by Clang, and calls them as the driver would call them.
+
+extern "C" {
+
+bool tinygo_clang_driver(int argc, char **argv) {
+ std::vector<const char*> args(argv, argv + argc);
+
+ // The compiler invocation needs a DiagnosticsEngine so it can report problems
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = new clang::DiagnosticOptions();
+ clang::TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ clang::DiagnosticsEngine Diags(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new clang::DiagnosticIDs()), &*DiagOpts, &DiagnosticPrinter, false);
+
+ // Create the clang driver
+ clang::driver::Driver TheDriver(args[0], llvm::sys::getDefaultTargetTriple(), Diags);
+
+ // Create the set of actions to perform
+ std::unique_ptr<clang::driver::Compilation> C(TheDriver.BuildCompilation(args));
+ if (!C) {
+ return false;
+ }
+ const clang::driver::JobList &Jobs = C->getJobs();
+
+ // There may be more than one job, for example for .S files
+ // (preprocessor + assembler).
+ for (auto Cmd : Jobs) {
+ // Select the tool: cc1 or cc1as.
+ const llvm::opt::ArgStringList &CCArgs = Cmd.getArguments();
+
+ if (strcmp(*CCArgs.data(), "-cc1") == 0) {
+ // This is the C frontend.
+ // Initialize a compiler invocation object from the clang (-cc1) arguments.
+ std::unique_ptr<clang::CompilerInstance> Clang(new clang::CompilerInstance());
+ bool success = clang::CompilerInvocation::CreateFromArgs(
+ Clang->getInvocation(),
+ const_cast<const char **>(CCArgs.data()),
+ const_cast<const char **>(CCArgs.data()) + CCArgs.size(),
+ Diags);
+ if (!success) {
+ return false;
+ }
+
+ // Create the actual diagnostics engine.
+ Clang->createDiagnostics();
+ if (!Clang->hasDiagnostics()) {
+ return false;
+ }
+
+ // Execute the frontend actions.
+ success = ExecuteCompilerInvocation(Clang.get());
+ if (!success) {
+ return false;
+ }
+
+ } else if (strcmp(*CCArgs.data(), "-cc1as") == 0) {
+ // This is the assembler frontend. Parse the arguments.
+ AssemblerInvocation Asm;
+ if (!AssemblerInvocation::CreateFromArgs(Asm, llvm::ArrayRef<const char*>(CCArgs).slice(1), Diags))
+ return false;
+
+ // Execute the invocation, unless there were parsing errors.
+ bool failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags);
+ if (failed) {
+ return false;
+ }
+
+ } else {
+ // Unknown tool, print the tool and exit.
+ fprintf(stderr, "unknown tool: %s\n", *CCArgs.data());
+ return false;
+ }
+ }
+
+ // Commands executed successfully.
+ return true;
+}
+
+} // extern "C"