-
Notifications
You must be signed in to change notification settings - Fork 64
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds the first plugin, the first test, LIT config scripts and updates README.
- Loading branch information
1 parent
9ef3f97
commit 297a4ba
Showing
8 changed files
with
344 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
cmake_minimum_required(VERSION 3.4.3) | ||
project(clang-tutor) | ||
|
||
#=============================================================================== | ||
# 1. VERIFY CLANG INSTALLATION DIR | ||
#=============================================================================== | ||
# Set this to a valid LLVM installation dir | ||
set(CT_LLVM_INSTALL_DIR "" CACHE PATH "LLVM installation directory") | ||
|
||
# A bit of a sanity checking | ||
set(CT_LLVM_INCLUDE_DIR "${CT_LLVM_INSTALL_DIR}/include/llvm") | ||
if(NOT EXISTS "${CT_LLVM_INCLUDE_DIR}") | ||
message(FATAL_ERROR | ||
" CT_LLVM_INSTALL_DIR (${CT_LLVM_INCLUDE_DIR}) is invalid.") | ||
endif() | ||
|
||
set(CT_LLVM_CMAKE_FILE "${CT_LLVM_INSTALL_DIR}/lib/cmake/clang/ClangConfig.cmake") | ||
if(NOT EXISTS "${CT_LLVM_CMAKE_FILE}") | ||
message(FATAL_ERROR | ||
" CT_LLVM_CMAKE_FILE (${CT_LLVM_CMAKE_FILE}) is invalid.") | ||
endif() | ||
|
||
#=============================================================================== | ||
# 2. LOAD CLANG CONFIGURATION | ||
# For more: http://llvm.org/docs/CMake.html#embedding-llvm-in-your-project | ||
#=============================================================================== | ||
list(APPEND CMAKE_PREFIX_PATH "${CT_LLVM_INSTALL_DIR}/lib/cmake/llvm/") | ||
list(APPEND CMAKE_PREFIX_PATH "${CT_LLVM_INSTALL_DIR}/lib/cmake/clang/") | ||
|
||
find_package(Clang REQUIRED CONFIG) | ||
message(STATUS "Found Clang ${LLVM_PACKAGE_VERSION}") | ||
message(STATUS "Using ClangConfig.cmake in: ${CT_LLVM_INSTALL_DIR}") | ||
|
||
message("CLANG STATUS: | ||
Includes (clang) ${CLANG_INCLUDE_DIRS} | ||
Includes (llvm) ${LLVM_INCLUDE_DIRS}" | ||
) | ||
|
||
# Compiler flags | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall\ | ||
-fdiagnostics-color=always") | ||
|
||
include_directories("${LLVM_INCLUDE_DIRS};${CLANG_INCLUDE_DIRS}") | ||
|
||
#=============================================================================== | ||
# 3. CLANG-TUTOR BUILD CONFIGURATION | ||
#=============================================================================== | ||
# Use the same C++ standard as LLVM does | ||
set(CMAKE_CXX_STANDARD 14 CACHE STRING "") | ||
|
||
# Build type | ||
if (NOT CMAKE_BUILD_TYPE) | ||
set(CMAKE_BUILD_TYPE Debug CACHE | ||
STRING "Build type (default Debug):" FORCE) | ||
endif() | ||
|
||
# Compiler flags | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall\ | ||
-fdiagnostics-color=always") | ||
|
||
# LLVM/Clang is normally built without RTTI. Be consistent with that. | ||
if(NOT LLVM_ENABLE_RTTI) | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") | ||
endif() | ||
|
||
# -fvisibility-inlines-hidden is set when building LLVM and on Darwin warnings | ||
# are triggered if llvm-tutor is built without this flag (though otherwise it | ||
# builds fine). For consistency, add it here too. | ||
include(CheckCXXCompilerFlag) | ||
check_cxx_compiler_flag("-fvisibility-inlines-hidden" SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG) | ||
if (${SUPPORTS_FVISIBILITY_INLINES_HIDDEN_FLAG} EQUAL "1") | ||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility-inlines-hidden") | ||
endif() | ||
|
||
# Set the build directories | ||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") | ||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") | ||
|
||
#=============================================================================== | ||
# 4. ADD SUB-TARGETS | ||
# Doing this at the end so that all definitions and link/include paths are | ||
# available for the sub-projects. | ||
#=============================================================================== | ||
add_subdirectory(test) | ||
add_subdirectory(lib) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
clang-tutor | ||
========= | ||
[![Build Status](https://github.com/banach-space/clang-tutor/workflows/x86-Ubuntu/badge.svg?branch=master)](https://github.com/banach-space/clang-tutor/actions?query=workflow%3Ax86-Ubuntu+branch%3Amaster) | ||
[![Build Status](https://github.com/banach-space/clang-tutor/workflows/x86-Darwin/badge.svg?branch=master)](https://github.com/banach-space/clang-tutor/actions?query=workflow%3Ax86-Darwin+branch%3Amaster) | ||
|
||
|
||
Example Clang plugins - based on **Clang 10** | ||
|
||
**clang-tutor** is a collection of self-contained reference Clang plugins. It's a | ||
tutorial that targets novice and aspiring Clang developers. Key features: | ||
* **Complete** - includes `CMake` build scripts, LIT tests and CI set-up | ||
* **Out of source** - builds against a binary Clang/LLVM installation (no | ||
need to build Clang from sources) | ||
* **Modern** - based on the latest version of Clang/LLVM (and updated with | ||
every release) | ||
|
||
Status | ||
====== | ||
**Work in progress** | ||
|
||
Everything builds fine and all tests pass. This project is under active | ||
development. More content to be added soon. | ||
|
||
Building & Testing | ||
=================== | ||
You can build **clang-tutor** (and all the provided plugins) as follows: | ||
```bash | ||
cd <build/dir> | ||
cmake -DCT_LLVM_INSTALL_DIR=<installation/dir/of/llvm/10> <source/dir/clang-tutor> | ||
make | ||
``` | ||
|
||
The `CT_LLVM_INSTALL_DIR` variable should be set to the root of either the | ||
installation or build directory of LLVM 10. It is used to locate the | ||
corresponding `LLVMConfig.cmake` script that is used to set the include and | ||
library paths. | ||
|
||
In order to run the tests, you need to install **llvm-lit** (aka **lit**). It's | ||
not bundled with LLVM 10 packages, but you can install it with **pip**: | ||
```bash | ||
# Install lit - note that this installs lit globally | ||
pip install lit | ||
``` | ||
Running the tests is as simple as: | ||
```bash | ||
$ lit <build_dir>/test | ||
``` | ||
Voilà! You should see all tests passing. | ||
|
||
License | ||
======== | ||
This is free and unencumbered software released into the public domain. | ||
|
||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this | ||
software, either in source code form or as a compiled binary, for any purpose, | ||
commercial or non-commercial, and by any means. | ||
|
||
In jurisdictions that recognize copyright laws, the author or authors of this | ||
software dedicate any and all copyright interest in the software to the public | ||
domain. We make this dedication for the benefit of the public at large and to | ||
the detriment of our heirs and successors. We intend this dedication to be an | ||
overt act of relinquishment in perpetuity of all present and future rights to | ||
this software under copyright law. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
|
||
For more information, please refer to http://unlicense.org/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
# THE LIST OF PLUGINS AND THE CORRESPONDING SOURCE FILES | ||
# ====================================================== | ||
add_library( | ||
HelloWorld | ||
SHARED | ||
HelloWorld.cpp | ||
) | ||
|
||
# CONFIGURE THE PLUGIN LIBRARIES | ||
# ============================== | ||
target_link_libraries( | ||
HelloWorld | ||
"$<$<PLATFORM_ID:Darwin>:-undefined dynamic_lookup>" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
//============================================================================== | ||
// FILE: | ||
// HelloWorld.cpp | ||
// | ||
// DESCRIPTION: | ||
// | ||
// USAGE: | ||
// | ||
// License: The Unlicense | ||
//============================================================================== | ||
#include "clang/Frontend/FrontendPluginRegistry.h" | ||
#include "clang/AST/ASTConsumer.h" | ||
#include "clang/AST/RecursiveASTVisitor.h" | ||
#include "clang/Frontend/CompilerInstance.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
||
using namespace clang; | ||
|
||
//----------------------------------------------------------------------------- | ||
// HelloWorld implementation | ||
//----------------------------------------------------------------------------- | ||
class HelloWorld : public RecursiveASTVisitor<HelloWorld> { | ||
public: | ||
explicit HelloWorld(ASTContext *Context) : Context(Context) {} | ||
bool VisitCXXRecordDecl(CXXRecordDecl *Decl); | ||
|
||
private: | ||
ASTContext *Context; | ||
}; | ||
|
||
bool HelloWorld::VisitCXXRecordDecl(CXXRecordDecl *Declaration) { | ||
FullSourceLoc FullLocation = Context->getFullLoc(Declaration->getBeginLoc()); | ||
if (FullLocation.isValid()) | ||
llvm::outs() << "(clang-tutor) Hello from: " << Declaration->getName() | ||
<< "\n" | ||
<< "(clang-tutor) location: " | ||
<< FullLocation.getSpellingLineNumber() << ":" | ||
<< " " << FullLocation.getSpellingColumnNumber() << "\n" | ||
<< "(clang-tutor) number of virtual bases classes " | ||
<< Declaration->getNumBases() << "\n"; | ||
return true; | ||
} | ||
|
||
class HelloWorldASTConsumer : public clang::ASTConsumer { | ||
public: | ||
explicit HelloWorldASTConsumer(ASTContext *Ctx) : Visitor(Ctx) {} | ||
|
||
void HandleTranslationUnit(clang::ASTContext &Ctx) override { | ||
Visitor.TraverseDecl(Ctx.getTranslationUnitDecl()); | ||
} | ||
|
||
private: | ||
HelloWorld Visitor; | ||
}; | ||
|
||
//----------------------------------------------------------------------------- | ||
// FrotendAction | ||
//----------------------------------------------------------------------------- | ||
class FindNamedClassAction : public clang::PluginASTAction { | ||
public: | ||
std::unique_ptr<clang::ASTConsumer> | ||
CreateASTConsumer(clang::CompilerInstance &Compiler, | ||
llvm::StringRef InFile) override { | ||
return std::unique_ptr<clang::ASTConsumer>( | ||
std::make_unique<HelloWorldASTConsumer>(&Compiler.getASTContext())); | ||
} | ||
bool ParseArgs(const CompilerInstance &CI, | ||
const std::vector<std::string> &args) override { | ||
return true; | ||
} | ||
}; | ||
|
||
//----------------------------------------------------------------------------- | ||
// Registration | ||
//----------------------------------------------------------------------------- | ||
static FrontendPluginRegistry::Add<FindNamedClassAction> | ||
X(/*Name=*/"hello-world", /*Description:=*/"The HelloWorld plugin"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
set(CT_TEST_SHLIBEXT "${CMAKE_SHARED_LIBRARY_SUFFIX}") | ||
|
||
set(CT_TEST_SITE_CFG_INPUT "${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in") | ||
set(CT_TEST_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") | ||
|
||
set(LIT_SITE_CFG_IN_HEADER "## Autogenerated from ${CT_TEST_SITE_CFG_INPUT}\n## Do not edit!") | ||
|
||
configure_file("${CT_TEST_SITE_CFG_INPUT}" | ||
"${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py" @ONLY | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// RUN: clang -cc1 -load %shlibdir/libHelloWorld%shlibext -plugin hello-world %s 2>&1 | FileCheck %s | ||
|
||
class Base1 { | ||
}; | ||
|
||
class Base2 { | ||
}; | ||
|
||
class Derived1 : public Base1 { | ||
}; | ||
|
||
class Derived2 : public Base1, public Base2 { | ||
}; | ||
|
||
// CHECK: (clang-tutor) Hello from: Base1 | ||
// CHECK: (clang-tutor) location: 3: 1 | ||
// CHECK: (clang-tutor) number of virtual bases classes 0 | ||
// CHECK: (clang-tutor) Hello from: Base2 | ||
// CHECK: (clang-tutor) location: 6: 1 | ||
// CHECK: (clang-tutor) number of virtual bases classes 0 | ||
// CHECK: (clang-tutor) Hello from: Derived1 | ||
// CHECK: (clang-tutor) location: 9: 1 | ||
// CHECK: (clang-tutor) number of virtual bases classes 1 | ||
// CHECK: (clang-tutor) Hello from: Derived2 | ||
// CHECK: (clang-tutor) location: 12: 1 | ||
// CHECK: (clang-tutor) number of virtual bases classes 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# -*- Python -*- | ||
|
||
# Configuration file for the 'lit' test runner. | ||
|
||
import platform | ||
|
||
import lit.formats | ||
# Global instance of LLVMConfig provided by lit | ||
from lit.llvm import llvm_config | ||
from lit.llvm.subst import ToolSubst | ||
|
||
# name: The name of this test suite. | ||
# (config is an instance of TestingConfig created when discovering tests) | ||
config.name = 'CLANG-TUTOR' | ||
|
||
# testFormat: The test format to use to interpret tests. | ||
# As per shtest.py (my formatting): | ||
# ShTest is a format with one file per test. This is the primary format for | ||
# regression tests (...) | ||
# I couldn't find any more documentation on this, but it seems to be exactly | ||
# what we want here. | ||
config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell) | ||
|
||
# suffixes: A list of file extensions to treat as test files. This is overriden | ||
# by individual lit.local.cfg files in the test subdirectories. | ||
config.suffixes = ['.cpp'] | ||
|
||
# test_source_root: The root path where tests are located. | ||
config.test_source_root = os.path.dirname(__file__) | ||
|
||
# excludes: A list of directories to exclude from the testsuite. The 'Inputs' | ||
# subdirectories contain auxiliary inputs for various tests in their parent | ||
# directories. | ||
config.excludes = ['Inputs'] | ||
|
||
# The list of tools required for testing - prepend them with the path specified | ||
# during configuration (i.e. LT_LLVM_TOOLS_DIR/bin) | ||
tools = ["FileCheck", "clang"] | ||
llvm_config.add_tool_substitutions(tools, config.llvm_tools_dir) | ||
|
||
# The LIT variable to hold the file extension for shared libraries (this is | ||
# platform dependent) | ||
config.substitutions.append(('%shlibext', config.llvm_shlib_ext)) | ||
# The LIT variable to hold the location of plugins/libraries | ||
config.substitutions.append(('%shlibdir', config.llvm_shlib_dir)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import sys | ||
|
||
config.llvm_tools_dir = "@CT_LLVM_INSTALL_DIR@/bin" | ||
config.llvm_shlib_ext = "@CT_TEST_SHLIBEXT@" | ||
config.llvm_shlib_dir = "@CMAKE_LIBRARY_OUTPUT_DIRECTORY@" | ||
|
||
import lit.llvm | ||
# lit_config is a global instance of LitConfig | ||
lit.llvm.initialize(lit_config, config) | ||
|
||
# test_exec_root: The root path where tests should be run. | ||
config.test_exec_root = os.path.join("@CMAKE_CURRENT_BINARY_DIR@") | ||
|
||
# Let the main config do the real work. | ||
lit_config.load_config(config, "@CT_TEST_SRC_DIR@/lit.cfg.py") |