diff options
| author | Carlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au> | 2012-10-15 17:10:06 +1100 | 
|---|---|---|
| committer | Carlo Zancanaro <carlo@pc-4w14-0.cs.usyd.edu.au> | 2012-10-15 17:10:06 +1100 | 
| commit | be1de4be954c80875ad4108e0a33e8e131b2f2c0 (patch) | |
| tree | 1fbbecf276bf7c7bdcbb4dd446099d6d90eaa516 /clang/examples | |
| parent | c4626a62754862d20b41e8a46a3574264ea80e6d (diff) | |
| parent | f1bd2e48c5324d3f7cda4090c87f8a5b6f463ce2 (diff) | |
Merge branch 'master' of ssh://bitbucket.org/czan/honours
Diffstat (limited to 'clang/examples')
| -rw-r--r-- | clang/examples/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | clang/examples/Makefile | 14 | ||||
| -rw-r--r-- | clang/examples/PrintFunctionNames/CMakeLists.txt | 15 | ||||
| -rw-r--r-- | clang/examples/PrintFunctionNames/Makefile | 28 | ||||
| -rw-r--r-- | clang/examples/PrintFunctionNames/PrintFunctionNames.cpp | 71 | ||||
| -rw-r--r-- | clang/examples/PrintFunctionNames/PrintFunctionNames.exports | 1 | ||||
| -rw-r--r-- | clang/examples/PrintFunctionNames/README.txt | 16 | ||||
| -rw-r--r-- | clang/examples/analyzer-plugin/CMakeLists.txt | 14 | ||||
| -rw-r--r-- | clang/examples/analyzer-plugin/MainCallChecker.cpp | 53 | ||||
| -rw-r--r-- | clang/examples/analyzer-plugin/Makefile | 20 | ||||
| -rw-r--r-- | clang/examples/clang-interpreter/CMakeLists.txt | 34 | ||||
| -rw-r--r-- | clang/examples/clang-interpreter/Makefile | 26 | ||||
| -rw-r--r-- | clang/examples/clang-interpreter/README.txt | 17 | ||||
| -rw-r--r-- | clang/examples/clang-interpreter/main.cpp | 156 | 
14 files changed, 472 insertions, 0 deletions
diff --git a/clang/examples/CMakeLists.txt b/clang/examples/CMakeLists.txt new file mode 100644 index 0000000..19d8869 --- /dev/null +++ b/clang/examples/CMakeLists.txt @@ -0,0 +1,7 @@ +if(NOT CLANG_BUILD_EXAMPLES) +  set(EXCLUDE_FROM_ALL ON) +endif() + +add_subdirectory(analyzer-plugin) +add_subdirectory(clang-interpreter) +add_subdirectory(PrintFunctionNames) diff --git a/clang/examples/Makefile b/clang/examples/Makefile new file mode 100644 index 0000000..d8d9028 --- /dev/null +++ b/clang/examples/Makefile @@ -0,0 +1,14 @@ +##===- examples/Makefile -----------------------------------*- Makefile -*-===## +# +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := .. + +PARALLEL_DIRS := analyzer-plugin clang-interpreter PrintFunctionNames + +include $(CLANG_LEVEL)/Makefile diff --git a/clang/examples/PrintFunctionNames/CMakeLists.txt b/clang/examples/PrintFunctionNames/CMakeLists.txt new file mode 100644 index 0000000..86793ce --- /dev/null +++ b/clang/examples/PrintFunctionNames/CMakeLists.txt @@ -0,0 +1,15 @@ +set(MODULE TRUE) + +set( LLVM_USED_LIBS +  clangFrontend +  clangAST +  ) + +set( LLVM_LINK_COMPONENTS support mc) + +add_clang_library(PrintFunctionNames PrintFunctionNames.cpp) + +set_target_properties(PrintFunctionNames +  PROPERTIES +  LINKER_LANGUAGE CXX +  PREFIX "") diff --git a/clang/examples/PrintFunctionNames/Makefile b/clang/examples/PrintFunctionNames/Makefile new file mode 100644 index 0000000..23a5305 --- /dev/null +++ b/clang/examples/PrintFunctionNames/Makefile @@ -0,0 +1,28 @@ +##===- examples/PrintFunctionNames/Makefile ----------------*- Makefile -*-===## +#  +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +#  +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME = PrintFunctionNames + +# If we don't need RTTI or EH, there's no reason to export anything +# from the plugin. +ifneq ($(REQUIRES_RTTI), 1) +ifneq ($(REQUIRES_EH), 1) +EXPORTED_SYMBOL_FILE = $(PROJ_SRC_DIR)/PrintFunctionNames.exports +endif +endif + +LINK_LIBS_IN_SHARED = 0 +SHARED_LIBRARY = 1 + +include $(CLANG_LEVEL)/Makefile + +ifeq ($(OS),Darwin) +  LDFLAGS=-Wl,-undefined,dynamic_lookup +endif diff --git a/clang/examples/PrintFunctionNames/PrintFunctionNames.cpp b/clang/examples/PrintFunctionNames/PrintFunctionNames.cpp new file mode 100644 index 0000000..ce8f208 --- /dev/null +++ b/clang/examples/PrintFunctionNames/PrintFunctionNames.cpp @@ -0,0 +1,71 @@ +//===- PrintFunctionNames.cpp ---------------------------------------------===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Example clang plugin which simply prints the names of all the top-level decls +// in the input file. +// +//===----------------------------------------------------------------------===// + +#include "clang/Frontend/FrontendPluginRegistry.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/AST.h" +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + +class PrintFunctionsConsumer : public ASTConsumer { +public: +  virtual bool HandleTopLevelDecl(DeclGroupRef DG) { +    for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) { +      const Decl *D = *i; +      if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) +        llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n"; +    } + +    return true; +  } +}; + +class PrintFunctionNamesAction : public PluginASTAction { +protected: +  ASTConsumer *CreateASTConsumer(CompilerInstance &CI, llvm::StringRef) { +    return new PrintFunctionsConsumer(); +  } + +  bool ParseArgs(const CompilerInstance &CI, +                 const std::vector<std::string>& args) { +    for (unsigned i = 0, e = args.size(); i != e; ++i) { +      llvm::errs() << "PrintFunctionNames arg = " << args[i] << "\n"; + +      // Example error handling. +      if (args[i] == "-an-error") { +        DiagnosticsEngine &D = CI.getDiagnostics(); +        unsigned DiagID = D.getCustomDiagID( +          DiagnosticsEngine::Error, "invalid argument '" + args[i] + "'"); +        D.Report(DiagID); +        return false; +      } +    } +    if (args.size() && args[0] == "help") +      PrintHelp(llvm::errs()); + +    return true; +  } +  void PrintHelp(llvm::raw_ostream& ros) { +    ros << "Help for PrintFunctionNames plugin goes here\n"; +  } + +}; + +} + +static FrontendPluginRegistry::Add<PrintFunctionNamesAction> +X("print-fns", "print function names"); diff --git a/clang/examples/PrintFunctionNames/PrintFunctionNames.exports b/clang/examples/PrintFunctionNames/PrintFunctionNames.exports new file mode 100644 index 0000000..0ff590d --- /dev/null +++ b/clang/examples/PrintFunctionNames/PrintFunctionNames.exports @@ -0,0 +1 @@ +_ZN4llvm8Registry* diff --git a/clang/examples/PrintFunctionNames/README.txt b/clang/examples/PrintFunctionNames/README.txt new file mode 100644 index 0000000..23ab5f0 --- /dev/null +++ b/clang/examples/PrintFunctionNames/README.txt @@ -0,0 +1,16 @@ +This is a simple example demonstrating how to use clang's facility for +providing AST consumers using a plugin. + +Build the plugin by running `make` in this directory. + +Once the plugin is built, you can run it using: +-- +Linux: +$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns some-input-file.c +$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c +$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.so -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c + +Mac: +$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns some-input-file.c +$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns help -plugin-arg-print-fns --example-argument some-input-file.c +$ clang -cc1 -load ../../Debug+Asserts/lib/libPrintFunctionNames.dylib -plugin print-fns -plugin-arg-print-fns -an-error some-input-file.c diff --git a/clang/examples/analyzer-plugin/CMakeLists.txt b/clang/examples/analyzer-plugin/CMakeLists.txt new file mode 100644 index 0000000..2b9d825 --- /dev/null +++ b/clang/examples/analyzer-plugin/CMakeLists.txt @@ -0,0 +1,14 @@ +set(MODULE TRUE) + +set( LLVM_USED_LIBS +  clangStaticAnalyzerCore +  ) + +set( LLVM_LINK_COMPONENTS support mc) + +add_clang_library(SampleAnalyzerPlugin MainCallChecker.cpp) + +set_target_properties(SampleAnalyzerPlugin +  PROPERTIES +  LINKER_LANGUAGE CXX +  PREFIX "") diff --git a/clang/examples/analyzer-plugin/MainCallChecker.cpp b/clang/examples/analyzer-plugin/MainCallChecker.cpp new file mode 100644 index 0000000..48a9795 --- /dev/null +++ b/clang/examples/analyzer-plugin/MainCallChecker.cpp @@ -0,0 +1,53 @@ +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/CheckerRegistry.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" + +using namespace clang; +using namespace ento; + +namespace { +class MainCallChecker : public Checker < check::PreStmt<CallExpr> > { +  mutable OwningPtr<BugType> BT; + +public: +  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; +}; +} // end anonymous namespace + +void MainCallChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { +  const ProgramStateRef state = C.getState(); +  const LocationContext *LC = C.getLocationContext(); +  const Expr *Callee = CE->getCallee(); +  const FunctionDecl *FD = state->getSVal(Callee, LC).getAsFunctionDecl(); + +  if (!FD) +    return; + +  // Get the name of the callee. +  IdentifierInfo *II = FD->getIdentifier(); +  if (!II)   // if no identifier, not a simple C function +    return; + +  if (II->isStr("main")) { +    ExplodedNode *N = C.generateSink(); +    if (!N) +      return; + +    if (!BT) +      BT.reset(new BugType("call to main", "example analyzer plugin")); + +    BugReport *report = new BugReport(*BT, BT->getName(), N); +    report->addRange(Callee->getSourceRange()); +    C.EmitReport(report);     +  } +} + +// Register plugin! +extern "C" +void clang_registerCheckers (CheckerRegistry ®istry) { +  registry.addChecker<MainCallChecker>("example.MainCallChecker", "Disallows calls to functions called main"); +} + +extern "C" +const char clang_analyzerAPIVersionString[] = CLANG_ANALYZER_API_VERSION_STRING; diff --git a/clang/examples/analyzer-plugin/Makefile b/clang/examples/analyzer-plugin/Makefile new file mode 100644 index 0000000..8b83bef --- /dev/null +++ b/clang/examples/analyzer-plugin/Makefile @@ -0,0 +1,20 @@ +##===- examples/analyzer-plugin/Makefile -------------------*- Makefile -*-===## +#  +#                     The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +#  +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. +LIBRARYNAME = SampleAnalyzerPlugin + +LINK_LIBS_IN_SHARED = 0 +LOADABLE_MODULE = 1 + +include $(CLANG_LEVEL)/Makefile + +ifeq ($(OS),Darwin) +  LDFLAGS=-Wl,-undefined,dynamic_lookup +endif diff --git a/clang/examples/clang-interpreter/CMakeLists.txt b/clang/examples/clang-interpreter/CMakeLists.txt new file mode 100644 index 0000000..809e324 --- /dev/null +++ b/clang/examples/clang-interpreter/CMakeLists.txt @@ -0,0 +1,34 @@ +set(LLVM_USED_LIBS +    clangFrontend +    clangSerialization +    clangDriver +    clangCodeGen +    clangSema +    clangStaticAnalyzerFrontend +    clangStaticAnalyzerCheckers +    clangStaticAnalyzerCore +    clangAnalysis +    clangRewrite +    clangAST +    clangParse +    clangLex +    clangBasic +    ) + +set(LLVM_LINK_COMPONENTS +    jit +    interpreter +    nativecodegen +    asmparser +    bitreader +    bitwriter +    codegen +    ipo +    linker +    selectiondag +  ) + +add_clang_executable(clang-interpreter +  main.cpp +  ) +add_dependencies(clang-interpreter clang-headers) diff --git a/clang/examples/clang-interpreter/Makefile b/clang/examples/clang-interpreter/Makefile new file mode 100644 index 0000000..420a066 --- /dev/null +++ b/clang/examples/clang-interpreter/Makefile @@ -0,0 +1,26 @@ +##===- 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. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../.. + +TOOLNAME = clang-interpreter +NO_INSTALL = 1 + +# No plugins, optimize startup time. +TOOL_NO_EXPORTS = 1 + +LINK_COMPONENTS := jit interpreter nativecodegen bitreader bitwriter ipo \ +	linker selectiondag asmparser instrumentation +USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangCodeGen.a \ +           clangParse.a clangSema.a clangStaticAnalyzerFrontend.a \ +           clangStaticAnalyzerCheckers.a clangStaticAnalyzerCore.a \ +           clangAnalysis.a clangRewrite.a \ +           clangEdit.a clangAST.a clangLex.a clangBasic.a + +include $(CLANG_LEVEL)/Makefile diff --git a/clang/examples/clang-interpreter/README.txt b/clang/examples/clang-interpreter/README.txt new file mode 100644 index 0000000..7dd45fa --- /dev/null +++ b/clang/examples/clang-interpreter/README.txt @@ -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. diff --git a/clang/examples/clang-interpreter/main.cpp b/clang/examples/clang-interpreter/main.cpp new file mode 100644 index 0000000..c39468a --- /dev/null +++ b/clang/examples/clang-interpreter/main.cpp @@ -0,0 +1,156 @@ +//===-- 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/CodeGen/CodeGenAction.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Tool.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/Module.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ExecutionEngine/JIT.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetSelect.h" +using namespace clang; +using namespace clang::driver; + +// This function isn't referenced outside its translation unit, but it +// can't use the "static" keyword because its address is used for +// GetMainExecutable (since some platforms don't support taking the +// address of main, and some platforms can't implement GetMainExecutable +// without being given the address of a function in the main executable). +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); +} + +static int Execute(llvm::Module *Mod, char * const *envp) { +  llvm::InitializeNativeTarget(); + +  std::string Error; +  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 = +    new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + +  IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); +  DiagnosticsEngine Diags(DiagID, DiagClient); +  Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(), +                   "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"); +  OwningPtr<Compilation> C(TheDriver.BuildCompilation(Args)); +  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())) { +    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(); +  OwningPtr<CompilerInvocation> CI(new CompilerInvocation); +  CompilerInvocation::CreateFromArgs(*CI, +                                     const_cast<const char **>(CCArgs.data()), +                                     const_cast<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.setInvocation(CI.take()); + +  // Create the compilers actual diagnostics engine. +  Clang.createDiagnostics(int(CCArgs.size()),const_cast<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. +  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; +}  | 
