forked from OSchip/llvm-project
Add a minimal C interpreter example.
- Demonstrates how to build a standalone tool which loads source code using the Driver and Frontend libraries, and then uses CodeGen and the JIT to actually execute the code. - Still more complicated than it should be, but hey its only 153 lines. :) -- ddunbar@ozzy:tmp$ cat hello.c #include <stdio.h> int main() { printf("hello world\n"); return 0; } ddunbar@ozzy:tmp$ clang-interpreter hello.c hello world -- llvm-svn: 97133
This commit is contained in:
parent
a72e1af8bf
commit
0076d94466
|
@ -9,6 +9,6 @@
|
|||
|
||||
LEVEL = ../../..
|
||||
|
||||
PARALLEL_DIRS := PrintFunctionNames wpa
|
||||
PARALLEL_DIRS := clang-interpreter PrintFunctionNames wpa
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
##===- examples/clang-interpreter/Makefile -----------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../../../..
|
||||
|
||||
TOOLNAME = clang-interpreter
|
||||
CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include -I$(PROJ_OBJ_DIR)/../../include
|
||||
NO_INSTALL = 1
|
||||
TOOL_NO_EXPORTS = 1
|
||||
|
||||
# Include this here so we can get the configuration of the targets that have
|
||||
# been configured for construction. We have to do this early so we can set up
|
||||
# LINK_COMPONENTS before including Makefile.rules
|
||||
include $(LEVEL)/Makefile.config
|
||||
|
||||
LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \
|
||||
selectiondag
|
||||
USEDLIBS = clangFrontend.a clangDriver.a clangCodeGen.a clangSema.a \
|
||||
clangChecker.a clangAnalysis.a clangRewrite.a clangAST.a \
|
||||
clangParse.a clangLex.a clangBasic.a
|
||||
|
||||
include $(LLVM_SRC_ROOT)/Makefile.rules
|
|
@ -0,0 +1,17 @@
|
|||
This is an example of Clang based interpreter, for executing standalone C
|
||||
programs.
|
||||
|
||||
It demonstrates the following features:
|
||||
1. Parsing standard compiler command line arguments using the Driver library.
|
||||
|
||||
2. Constructing a Clang compiler instance, using the appropriate arguments
|
||||
derived in step #1.
|
||||
|
||||
3. Invoking the Clang compiler to lex, parse, syntax check, and then generate
|
||||
LLVM code.
|
||||
|
||||
4. Use the LLVM JIT functionality to execute the final module.
|
||||
|
||||
The implementation has many limitations and is not designed to be a full fledged
|
||||
C interpreter. It is designed to demonstrate a simple but functional use of the
|
||||
Clang compiler libraries.
|
|
@ -0,0 +1,152 @@
|
|||
//===-- examples/clang-interpreter/main.cpp - Clang C Interpreter Example -===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Frontend/CodeGenAction.h"
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/DiagnosticOptions.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Module.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ExecutionEngine/ExecutionEngine.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/System/Host.h"
|
||||
#include "llvm/System/Path.h"
|
||||
#include "llvm/Target/TargetSelect.h"
|
||||
using namespace clang;
|
||||
using namespace clang::driver;
|
||||
|
||||
llvm::sys::Path GetExecutablePath(const char *Argv0) {
|
||||
// This just needs to be some symbol in the binary; C++ doesn't
|
||||
// allow taking the address of ::main however.
|
||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||
return llvm::sys::Path::GetMainExecutable(Argv0, MainAddr);
|
||||
}
|
||||
|
||||
int Execute(llvm::Module *Mod, char * const *envp) {
|
||||
llvm::InitializeNativeTarget();
|
||||
|
||||
std::string Error;
|
||||
llvm::OwningPtr<llvm::ExecutionEngine> EE(
|
||||
llvm::ExecutionEngine::createJIT(Mod, &Error));
|
||||
if (!EE) {
|
||||
llvm::errs() << "unable to make execution engine: " << Error << "\n";
|
||||
return 255;
|
||||
}
|
||||
|
||||
llvm::Function *EntryFn = Mod->getFunction("main");
|
||||
if (!EntryFn) {
|
||||
llvm::errs() << "'main' function not found in module.\n";
|
||||
return 255;
|
||||
}
|
||||
|
||||
// FIXME: Support passing arguments.
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back(Mod->getModuleIdentifier());
|
||||
|
||||
return EE->runFunctionAsMain(EntryFn, Args, envp);
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv, char * const *envp) {
|
||||
void *MainAddr = (void*) (intptr_t) GetExecutablePath;
|
||||
llvm::sys::Path Path = GetExecutablePath(argv[0]);
|
||||
TextDiagnosticPrinter DiagClient(llvm::errs(), DiagnosticOptions());
|
||||
|
||||
Diagnostic Diags(&DiagClient);
|
||||
Driver TheDriver(Path.getBasename(), Path.getDirname(),
|
||||
llvm::sys::getHostTriple(),
|
||||
"a.out", /*IsProduction=*/false, Diags);
|
||||
TheDriver.setTitle("clang interpreter");
|
||||
|
||||
// FIXME: This is a hack to try to force the driver to do something we can
|
||||
// recognize. We need to extend the driver library to support this use model
|
||||
// (basically, exactly one input, and the operation mode is hard wired).
|
||||
llvm::SmallVector<const char *, 16> Args(argv, argv + argc);
|
||||
Args.push_back("-fsyntax-only");
|
||||
llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args.size(),
|
||||
Args.data()));
|
||||
if (!C)
|
||||
return 0;
|
||||
|
||||
// FIXME: This is copied from ASTUnit.cpp; simplify and eliminate.
|
||||
|
||||
// We expect to get back exactly one command job, if we didn't something
|
||||
// failed. Extract that job from the compilation.
|
||||
const driver::JobList &Jobs = C->getJobs();
|
||||
if (Jobs.size() != 1 || !isa<driver::Command>(Jobs.begin())) {
|
||||
llvm::SmallString<256> Msg;
|
||||
llvm::raw_svector_ostream OS(Msg);
|
||||
C->PrintJob(OS, C->getJobs(), "; ", true);
|
||||
Diags.Report(diag::err_fe_expected_compiler_job) << OS.str();
|
||||
return 1;
|
||||
}
|
||||
|
||||
const driver::Command *Cmd = cast<driver::Command>(*Jobs.begin());
|
||||
if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
|
||||
Diags.Report(diag::err_fe_expected_clang_command);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize a compiler invocation object from the clang (-cc1) arguments.
|
||||
const driver::ArgStringList &CCArgs = Cmd->getArguments();
|
||||
llvm::OwningPtr<CompilerInvocation> CI(new CompilerInvocation);
|
||||
CompilerInvocation::CreateFromArgs(*CI, (const char**) CCArgs.data(),
|
||||
(const char**) CCArgs.data()+CCArgs.size(),
|
||||
Diags);
|
||||
|
||||
// Show the invocation, with -v.
|
||||
if (CI->getHeaderSearchOpts().Verbose) {
|
||||
llvm::errs() << "clang invocation:\n";
|
||||
C->PrintJob(llvm::errs(), C->getJobs(), "\n", true);
|
||||
llvm::errs() << "\n";
|
||||
}
|
||||
|
||||
// FIXME: This is copied from cc1_main.cpp; simplify and eliminate.
|
||||
|
||||
// Create a compiler instance to handle the actual work.
|
||||
CompilerInstance Clang;
|
||||
Clang.setLLVMContext(new llvm::LLVMContext);
|
||||
Clang.setInvocation(CI.take());
|
||||
|
||||
// Create the compilers actual diagnostics engine.
|
||||
Clang.createDiagnostics(int(CCArgs.size()), (char**) CCArgs.data());
|
||||
if (!Clang.hasDiagnostics())
|
||||
return 1;
|
||||
|
||||
// Infer the builtin include path if unspecified.
|
||||
if (Clang.getHeaderSearchOpts().UseBuiltinIncludes &&
|
||||
Clang.getHeaderSearchOpts().ResourceDir.empty())
|
||||
Clang.getHeaderSearchOpts().ResourceDir =
|
||||
CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
|
||||
|
||||
// Create and execute the frontend to generate an LLVM bitcode module.
|
||||
llvm::OwningPtr<CodeGenAction> Act(new EmitLLVMOnlyAction());
|
||||
if (!Clang.ExecuteAction(*Act))
|
||||
return 1;
|
||||
|
||||
int Res = 255;
|
||||
if (llvm::Module *Module = Act->takeModule())
|
||||
Res = Execute(Module, envp);
|
||||
|
||||
// Shutdown.
|
||||
|
||||
llvm::llvm_shutdown();
|
||||
|
||||
return Res;
|
||||
}
|
Loading…
Reference in New Issue