.. Copyright 2012 David Malcolm Copyright 2012 Red Hat, Inc. This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . .. _callbacks: Working with callbacks ====================== One way to work with GCC from the Python plugin is via callbacks. It's possible to register callback functions, which will be called when various events happen during compilation. For example, it's possible to piggyback off of an existing GCC pass by using :py:data:`gcc.PLUGIN_PASS_EXECUTION` to piggyback off of an existing GCC pass. .. py:function:: gcc.register_callback(event_id, function, [extraargs,] **kwargs) Wire up a python function as a callback. It will be called when the given event occurs during compilation. For some events, the callback will be called just once; for other events, the callback is called once per function within the source code being compiled. In the latter case, the plugin passes a :py:class:`gcc.Function` instance as a parameter to your callback, so that you can work on it:: import gcc def my_pass_execution_callback(*args, **kwargs): print('my_pass_execution_callback was called: args=%r kwargs=%r' % (args, kwargs)) gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION, my_pass_execution_callback) The exact arguments passed to your callback vary: consult the documentation for the particular event you are wiring up to (see below). You can pass additional arguments when registering the callback - they will be passed to the callback after any normal arguments. This is denoted in the descriptions of events below by `*extraargs`. You can also supply keyword arguments: they will be passed on as keyword arguments to the callback. This is denoted in the description of events below by `**kwargs`. The various events are exposed as constants within the `gcc` module and directly wrap GCC's plugin mechanism. The following GCC events are currently usable from the Python plugin via :py:func:`gcc.register_callback()`: =============================================== ========= ID Meaning =============================================== ========= :py:data:`gcc.PLUGIN_ATTRIBUTES` For :doc:`creating custom GCC attributes ` :py:data:`gcc.PLUGIN_PRE_GENERICIZE` For working with the AST in the C and C++ frontends :py:data:`gcc.PLUGIN_PASS_EXECUTION` Called before each pass is executed :py:data:`gcc.PLUGIN_FINISH_UNIT` At the end of working with a translation unit (aka source file) :py:data:`gcc.PLUGIN_FINISH_TYPE` After a type has been parsed :py:data:`gcc.PLUGIN_FINISH_DECL` After a declaration has been parsed (GCC 4.7 or later) :py:data:`gcc.PLUGIN_FINISH` Called before GCC exits =============================================== ========= .. py:data:: gcc.PLUGIN_ATTRIBUTES Called when GCC is creating attributes for use with its non-standard `__attribute__(()) syntax `_. If you want to create custom GCC attributes, you should register a callback on this event and call :py:func:`gcc.register_attribute()` from within that callback, so that they are created at the same time as the GCC's built-in attributes. No arguments are passed to your callback other than those that you supply yourself when registering it: (`*extraargs`, `**kwargs`) See :doc:`creating custom GCC attributes ` for examples and more information. .. py:data:: gcc.PLUGIN_PASS_EXECUTION Called when GCC is about to run one of its passes. Arguments passed to the callback are: (`ps`, `fun`, `*extraargs`, `**kwargs`) where `ps` is a :py:class:`gcc.Pass` and `fun` is a :py:class:`gcc.Function`. Your callback will typically be called many times: there are many passes, and each can be invoked zero or more times per function (in the code being compiled) More precisely, some passes have a "gate check": the pass first checks a condition, and only executes if the condition is true. Any callback registered with `gcc.PLUGIN_PASS_EXECUTION` will get called if this condition succeeds. The actual work of the pass is done after the callbacks return. In pseudocode:: if pass.has_gate_condition: if !pass.test_gate_condition(): return invoke_all_callbacks() actually_do_the_pass() For passes working on individual functions, all of the above is done per-function. To connect to a specific pass, you can simply add a conditional based on the name of the pass:: import gcc def my_callback(ps, fun): if ps.name != '*warn_function_return': # Not the pass we want return # Do something here print(fun.decl.name) gcc.register_callback(gcc.PLUGIN_PASS_EXECUTION, my_callback) .. py:data:: gcc.PLUGIN_PRE_GENERICIZE Arguments passed to the callback are: (`fndecl`, `*extraargs`, `**kwargs`) where `fndecl` is a :py:class:`gcc.Tree` representing a function declaration within the source code being compiled. .. py:data:: gcc.PLUGIN_FINISH_UNIT Called when GCC has finished compiling a particular translation unit. Arguments passed to the callback are: (`*extraargs`, `**kwargs`) .. py:data:: gcc.PLUGIN_FINISH_DECL .. note:: Only available in GCC 4.7 onwards. Called when GCC has finished compiling a declaration (variables, functions, parameters to functions, types, etc) Arguments passed to the callback are: (`decl`, `*extraargs`, `**kwargs`) where `decl` is a :py:class:`gcc.Declaration`. .. py:data:: gcc.PLUGIN_FINISH_TYPE Called when GCC has finished parsing a type. Arguments to the callback are: (`type`, `*extraargs`, `**kwargs`) where `type` is a :py:class:`gcc.Type`. .. py:data:: gcc.PLUGIN_FINISH Called before GCC exits. Arguments passed to the callback are: (`*extraargs`, `**kwargs`) The remaining GCC events aren't yet usable from the plugin; an attempt to register a callback on them will lead to an exception being raised. Email the `gcc-python-plugin's mailing list `_ if you're interested in working with these): =============================================== ========= ID Meaning =============================================== ========= :py:data:`gcc.PLUGIN_PASS_MANAGER_SETUP` To hook into pass manager :py:data:`gcc.PLUGIN_INFO` Information about the plugin :py:data:`gcc.PLUGIN_GGC_START` For interacting with GCC's garbage collector :py:data:`gcc.PLUGIN_GGC_MARKING` (ditto) :py:data:`gcc.PLUGIN_GGC_END` (ditto) :py:data:`gcc.PLUGIN_REGISTER_GGC_ROOTS` (ditto) :py:data:`gcc.PLUGIN_REGISTER_GGC_CACHES` (ditto) :py:data:`gcc.PLUGIN_START_UNIT` Called before processing a translation unit (aka source file) :py:data:`gcc.PLUGIN_PRAGMAS` For registering pragmas :py:data:`gcc.PLUGIN_ALL_PASSES_START` Called before the first pass of the :ref:`"all other passes" gcc.Pass catchall ` :py:data:`gcc.PLUGIN_ALL_PASSES_END` Called after last pass of the :ref:`"all other passes" gcc.Pass catchall ` :py:data:`gcc.PLUGIN_ALL_IPA_PASSES_START` Called before the first IPA pass :py:data:`gcc.PLUGIN_ALL_IPA_PASSES_END` Called after last IPA pass :py:data:`gcc.PLUGIN_OVERRIDE_GATE` Provides a way to disable a built-in pass :py:data:`gcc.PLUGIN_EARLY_GIMPLE_PASSES_START` :py:data:`gcc.PLUGIN_EARLY_GIMPLE_PASSES_END` :py:data:`gcc.PLUGIN_NEW_PASS` =============================================== ========= .. Notes on the other callback events .. py:data:: gcc.PLUGIN_PRAGMAS gcc_data=0x0 Called from: c_common_init () at ../../gcc/c-family/c-opts.c:1052 .. py:data:: gcc.PLUGIN_START_UNIT gcc_data=0x0 Called from: compile_file () at ../../gcc/toplev.c:573 .. py:data:: gcc.PLUGIN_PRE_GENERICIZE gcc_data is: tree fndecl; Called from: finish_function () at ../../gcc/c-decl.c:8323 .. py:data:: gcc.PLUGIN_OVERRIDE_GATE gcc_data:: &gate_status bool gate_status; Called from : execute_one_pass (pass=0x1011340) at ../../gcc/passes.c:1520 .. py:data:: gcc.PLUGIN_ALL_IPA_PASSES_START gcc_data=0x0 Called from: ipa_passes () at ../../gcc/cgraphunit.c:1779 .. py:data:: gcc.PLUGIN_EARLY_GIMPLE_PASSES_START gcc_data=0x0 Called from: execute_ipa_pass_list (pass=0x1011fa0) at ../../gcc/passes.c:1927 .. py:data:: gcc.PLUGIN_EARLY_GIMPLE_PASSES_END gcc_data=0x0 Called from: execute_ipa_pass_list (pass=0x1011fa0) at ../../gcc/passes.c:1930 .. py:data:: gcc.PLUGIN_ALL_IPA_PASSES_END gcc_data=0x0 Called from: ipa_passes () at ../../gcc/cgraphunit.c:1821 .. py:data:: gcc.PLUGIN_ALL_PASSES_START gcc_data=0x0 Called from: tree_rest_of_compilation (fndecl=0x7ffff16b1f00) at ../../gcc/tree-optimize.c:420 .. py:data:: gcc.PLUGIN_ALL_PASSES_END gcc_data=0x0 Called from: tree_rest_of_compilation (fndecl=0x7ffff16b1f00) at ../../gcc/tree-optimize.c:425 .. py:data:: gcc.PLUGIN_FINISH gcc_data=0x0 Called from: toplev_main (argc=17, argv=0x7fffffffdfc8) at ../../gcc/toplev.c:1970 .. py:data:: gcc.PLUGIN_FINISH_TYPE gcc_data=tree Called from c_parser_declspecs (parser=0x7fffef559730, specs=0x15296d0, scspec_ok=1 '\001', typespec_ok=1 '\001', start_attr_ok=, la=cla_nonabstract_decl) at ../../gcc/c-parser.c:2111 .. py:data:: gcc.PLUGIN_PRAGMA gcc_data=0x0 Called from: init_pragma at ../../gcc/c-family/c-pragma.c:1321 to "Allow plugins to register their own pragmas."