3. 编写第一个GCC插件

编写第一个GCC插件 学习卡片

任务目标

编写一个GCC插件,在GCC每次编译C源文件时,于编译流程中输出一条自定义消息(例如“Hello from GCC Plugin”)。插件通过GCC的插件机制注册,并在PLUGIN_START_UNIT事件触发时打印消息。

环境与依赖

  • GCC 4.5+(需支持-fplugin选项),建议GCC 10+
  • 安装GCC插件开发头文件:gcc-<version>-plugin-dev(Debian/Ubuntu)或等价包
  • Linux环境(或任何支持GCC插件的类Unix系统)

实现代码

创建插件源文件 first_plugin.c:

#include <gcc-plugin.h>
#include <plugin-version.h>
#include <stdio.h>

/* 声明插件兼容性版本 */
int plugin_is_GPL_compatible;

/* 回调函数:在编译单元开始时被调用 */
static void handle_start_unit(void *gcc_data, void *user_data) {
    printf("Hello from GCC Plugin\n");
}

/* 插件初始化入口 */
int plugin_init(struct plugin_name_args *plugin_info,
                struct plugin_gcc_version *version) {
    /* 检查GCC版本兼容性 */
    if (!plugin_default_version_check(version, &gcc_version)) {
        fprintf(stderr, "Plugin version mismatch\n");
        return 1;
    }

    /* 注册回调:PLUGIN_START_UNIT 在解析编译单元开始时触发 */
    register_callback(plugin_info->base_name,
                      PLUGIN_START_UNIT,
                      handle_start_unit,
                      NULL);
    return 0;
}

编译与运行

  1. 编译插件为共享库:
gcc -fPIC -shared -o first_plugin.so first_plugin.c $(gcc -print-file-name=plugin)/include
  1. 编写一个测试C文件 test.c:
int main() { return 0; }
  1. 使用插件编译测试文件:
gcc -fplugin=./first_plugin.so -c test.c

验证方法

执行上述编译命令后,若终端输出以下内容,则插件工作正常:

Hello from GCC Plugin

同时会生成目标文件 test.o,说明编译流程未被插件中断。若未看到输出,请检查插件编译时头文件路径是否正确(使用gcc -print-file-name=plugin确认),以及GCC版本是否支持插件。

常见问题

  • 版本不匹配:插件编译所用GCC必须与运行插件的GCC完全一致(包括版本号和配置)。使用gcc -v查看版本。
  • 头文件缺失:若编译插件时报找不到gcc-plugin.h,说明未安装插件开发包。
  • 回调未触发:确认注册的是PLUGIN_START_UNIT事件,该事件在语法分析开始前触发,适合打印消息。