gcc-plugin
1. Get Start
dnf install gcc-plugin-devel
cpp
// plugin.cc
#include <gcc-plugin.h>
#include <plugin-version.h>
int plugin_is_GPL_compatible;
int plugin_init(plugin_name_args *plugin_info, plugin_gcc_version *version) {
if (!plugin_default_version_check(version, &gcc_version)) {
printf("incompatible gcc/plugin versions\n");
return 1;
}
printf("Hello world!\n");
return 0;
}1.1. 直接编译
编译插件
sh
g++ plugin.cc -c -o plugin.o -I`g++ -print-file-name=plugin`/include -std=c++17 -Wall -fPIC
g++ plugin.o -fPIC -shared -o libplugin.so使用插件
sh
g++ test.cc -o test -fplugin=libplugin.so编译 test.cc 时会出现 Hello world!
1.2. cmake 构建
编译插件(plugin 目录)
cmake
cmake_minimum_required(VERSION 3.10)
project(plugin VERSION 1.0)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_library(${PROJECT_NAME} SHARED plugin.cc)
execute_process(COMMAND g++ "-print-file-name=plugin" OUTPUT_VARIABLE gcc_plugin_dir)
string(STRIP ${gcc_plugin_dir} gcc_plugin_dir)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -I${gcc_plugin_dir}/include)编译并使用插件
sh
mkdir -p build
cmake -B build . && cmake --build build -- "$@"
g++ test.cc -o build/test -fplugin=build/plugin/libplugin.so1.3. clang-format 修改
context.h 头文件不是自包含的,加上 SortIncludes: false 禁止头文件排序
2. 基本结构
cpp
int plugin_is_GPL_compatible; // 不用管
int plugin_init(plugin_name_args *plugin_info, plugin_gcc_version *version); // 插件加载时执行回调函数,在 plugin_init 里注册,注册函数 register_callback 的签名:
cpp
void register_callback(const char *plugin_name, int event, plugin_callback_func callback, void *user_data);3. 事件
3.1. 包含头文件
PLUGIN_INCLUDE_FILE
所有 #include 会触发
cpp
#include <gcc-plugin.h>
#include <plugin-version.h>
int plugin_is_GPL_compatible;
void file_included(void *gcc_data, void *user_data) {
printf("file included: %s\n", (char *)gcc_data);
}
int plugin_init(plugin_name_args *plugin_info, plugin_gcc_version *version) {
if (!plugin_default_version_check(version, &gcc_version)) {
printf("incompatible gcc/plugin versions\n");
return 1;
}
const char *plugin_name = plugin_info->base_name;
register_callback(plugin_name, PLUGIN_INCLUDE_FILE, file_included, NULL);
return 0;
}3.2. 声明
PLUGIN_FINISH_DECL
- 函数声明 function_decl
- 变量声明和定义 var_decl
cpp
#include <gcc-plugin.h>
#include <plugin-version.h>
#include <tree-pass.h>
#include <context.h>
#include <tree.h>
int plugin_is_GPL_compatible;
void finish_decl(void *event, void *__unused__) {
tree decl = (tree)event;
const char *file = DECL_SOURCE_FILE(decl);
int line = DECL_SOURCE_LINE(decl);
int column = DECL_SOURCE_COLUMN(decl);
const char *name = DECL_NAME(decl) != NULL_TREE
? IDENTIFIER_POINTER(DECL_NAME(decl))
: "<unamed>";
const char *type = get_tree_code_name(TREE_CODE(decl));
printf("%s:%d:%d: %s (%s)\n", file, line, column, name, type);
}
int plugin_init(plugin_name_args *plugin_info, plugin_gcc_version *version) {
if (!plugin_default_version_check(version, &gcc_version)) {
printf("incompatible gcc/plugin versions\n");
return 1;
}
const char *const plugin_name = plugin_info->base_name;
register_callback(plugin_name, PLUGIN_FINISH_DECL, finish_decl, NULL);
return 0;
}