github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/builder/clang.cpp (about) 1 //go:build byollvm 2 3 #include <clang/Basic/DiagnosticOptions.h> 4 #include <clang/CodeGen/CodeGenAction.h> 5 #include <clang/Driver/Compilation.h> 6 #include <clang/Driver/Driver.h> 7 #include <clang/Frontend/CompilerInstance.h> 8 #include <clang/Frontend/CompilerInvocation.h> 9 #include <clang/Frontend/FrontendDiagnostic.h> 10 #include <clang/Frontend/TextDiagnosticPrinter.h> 11 #include <clang/FrontendTool/Utils.h> 12 #include <llvm/ADT/IntrusiveRefCntPtr.h> 13 #include <llvm/Option/Option.h> 14 #include <llvm/TargetParser/Host.h> 15 16 using namespace llvm; 17 using namespace clang; 18 19 #include "cc1as.h" 20 21 // This file provides C wrappers for the builtin tools cc1 and cc1as 22 // provided by Clang, and calls them as the driver would call them. 23 24 extern "C" { 25 26 bool tinygo_clang_driver(int argc, char **argv) { 27 std::vector<const char*> args(argv, argv + argc); 28 29 // The compiler invocation needs a DiagnosticsEngine so it can report problems 30 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts = new clang::DiagnosticOptions(); 31 clang::TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts); 32 clang::DiagnosticsEngine Diags(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new clang::DiagnosticIDs()), &*DiagOpts, &DiagnosticPrinter, false); 33 34 // Create the clang driver 35 clang::driver::Driver TheDriver(args[0], llvm::sys::getDefaultTargetTriple(), Diags); 36 37 // Create the set of actions to perform 38 std::unique_ptr<clang::driver::Compilation> C(TheDriver.BuildCompilation(args)); 39 if (!C) { 40 return false; 41 } 42 const clang::driver::JobList &Jobs = C->getJobs(); 43 44 // There may be more than one job, for example for .S files 45 // (preprocessor + assembler). 46 for (auto Cmd : Jobs) { 47 // Select the tool: cc1 or cc1as. 48 const llvm::opt::ArgStringList &CCArgs = Cmd.getArguments(); 49 50 if (strcmp(*CCArgs.data(), "-cc1") == 0) { 51 // This is the C frontend. 52 // Initialize a compiler invocation object from the clang (-cc1) arguments. 53 std::unique_ptr<clang::CompilerInstance> Clang(new clang::CompilerInstance()); 54 bool success = clang::CompilerInvocation::CreateFromArgs( 55 Clang->getInvocation(), 56 CCArgs, 57 Diags); 58 if (!success) { 59 return false; 60 } 61 62 // Create the actual diagnostics engine. 63 Clang->createDiagnostics(); 64 if (!Clang->hasDiagnostics()) { 65 return false; 66 } 67 68 // Execute the frontend actions. 69 success = ExecuteCompilerInvocation(Clang.get()); 70 if (!success) { 71 return false; 72 } 73 74 } else if (strcmp(*CCArgs.data(), "-cc1as") == 0) { 75 // This is the assembler frontend. Parse the arguments. 76 AssemblerInvocation Asm; 77 ArrayRef<const char *> Argv = llvm::ArrayRef<const char*>(CCArgs); 78 if (!AssemblerInvocation::CreateFromArgs(Asm, Argv.slice(1), Diags)) 79 return false; 80 81 // Execute the invocation, unless there were parsing errors. 82 bool failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags); 83 if (failed) { 84 return false; 85 } 86 87 } else { 88 // Unknown tool, print the tool and exit. 89 fprintf(stderr, "unknown tool: %s\n", *CCArgs.data()); 90 return false; 91 } 92 } 93 94 // Commands executed successfully. 95 return true; 96 } 97 98 } // extern "C"