3. 编写第一个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;
}
编译与运行
- 编译插件为共享库:
gcc -fPIC -shared -o first_plugin.so first_plugin.c $(gcc -print-file-name=plugin)/include
- 编写一个测试C文件
test.c:
int main() { return 0; }
- 使用插件编译测试文件:
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事件,该事件在语法分析开始前触发,适合打印消息。