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"