前回: http://d.hatena.ne.jp/shinichiro_h/20080803#1217701533
GEM のこと見てたら plugin branch なんてあるんだなーと気付きました。 GEM 同様実装はすごい簡単で、要所要所で適当に dlopen した共有オブジェクトの関数呼ぶだけみたいです。技術的には全く問題ないけど RMS がプロプライエタリなのを助けてしまわないかと懸念してそんなことないべと言ったりとかそんな感じ。
http://gcc.gnu.org/ml/gcc/2007-11/msg00180.html
あまり深く考えず使ってみます。
% svn co svn://gcc.gnu.org/svn/gcc/branches/plugin gcc-plugin % cd gcc-plugin % mkdir obj % cd obj % ../configure --prefix=/usr/local/stow/gcc-plugin --disable-multilib --enable-languages=c,c++ % make % sudo make install
とかで。ビルドはとかはお好みで。
例のごとく assign_hook.c:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include "config.h" #include "system.h" #include "coretypes.h" #include "tree.h" #include "tree-plugin.h" #include "c-tree.h" static tree get_fndecl(char* name) { tree fndecl; fndecl=get_identifier(name); if (fndecl!=NULL_TREE) { fndecl=lookup_name(fndecl); } if (fndecl==NULL_TREE) { printf("unable to find %s\n", name); abort(); } return fndecl; } static tree walk_assign_hook(tree* t, int* walk_subtrees, void* dummy_data) { if (TREE_CODE(*t) != MODIFY_EXPR) { return NULL; } puts("assign_hook"); //dump_node(*t, 0, stdout); tree type = TREE_TYPE(*t); tree lhs = TREE_OPERAND(*t, 0); tree rhs = TREE_OPERAND(*t, 1); // We only hook integral type assignments. if (!INTEGRAL_TYPE_P(TREE_TYPE(lhs)) || !INTEGRAL_TYPE_P(TREE_TYPE(lhs))) { return NULL; } // Ignore artificial assignments. if (!DECL_NAME(lhs)) { return NULL; } tree arglist = build_tree_list(NULL_TREE, rhs); *t = build2(MODIFY_EXPR, type, lhs, build_function_call_expr(get_fndecl("assign_hook"), arglist)); return NULL; } void transform_ctrees(int argc, struct plugin_argument* argv, tree fndecl) { //dump_node(fndecl, 0, stdout); walk_tree(&DECL_SAVED_TREE(fndecl), &walk_assign_hook, NULL, NULL); }
前回とほとんど同じだけど、 GEM と違って関数定義の根っこを受け取る感じなので、自分でトラバースしないといけない。まぁ walk_tree で。ちなみにフックかけられる場所一覧:
void (*pre_translation_unit) (int argc, struct plugin_argument* argv); void (*transform_ctrees) (int argc, struct plugin_argument* argv, tree fndecl); void (*transform_gimple) (int argc, struct plugin_argument* argv); void (*transform_cgraph) (int argc, struct plugin_argument* argv); void (*transform_rtl) (int argc, struct plugin_argument* argv); void (*post_translation_unit) (int argc, struct plugin_argument* argv);
assign_hook_lib.c と assign_hook_test.c は前回と同じで、ビルドは、
#!/bin/sh set -ex gcc -g -shared assign_hook.c -Igcc -Iinclude -Iobj/gcc -Ilibcpp/include -o assign_hook.so -fPIC /usr/local/stow/gcc-plugin/bin/gcc -g -c assign_hook_lib.c /usr/local/stow/gcc-plugin/bin/gcc -g assign_hook_test.c assign_hook_lib.o -ftree-plugin=./assign_hook.so
とかいう shell script で行ないました。ヘッダのパスとかは適当に。まぁ普通の共有オブジェクトで良くて、 -ftree-plugin=./assign_hook.so などとしてプラグインを指定、って感じ。
これは公式に入るといいですね。
そういえば実行結果はちょっと変わってた。 i++ が modify expr じゃなくなったみたい。