I am trying to build the simple gcc plugin. I am a newbie, but I want to implement more complicated plugins in the future. I read a lot of manuals, and it seems that I did everything right, but something is wrong. I can't build it. Every time I try to build my plugin I get an error:
/usr/lib/gcc/i686-linux-gnu/4.6/../../../i386-linux-gnu/crt1.o: In function `_start':
(.text+0x18): undefined reference to `main'
/tmp/ccjmG33v.o: In function `plugin_init':
plugin.c:(.text+0x9e): undefined reference to `register_callback'
plugin.c:(.text+0xc6): undefined reference to `register_callback'
collect2: ld returned 1 exit status
make: *** [plugin.o] Error 1
I have no idea what is wrong. I performed the same steps as described in all the manuals I found.
I have Ubuntu 12.04 with gcc-4.6.3 compiler.
I installed gcc-4.6-plugin-dev.
I even tried to build the plugin, based on gcc_4.6.4, that was carefully downloaded and built by myself. But the result is the same.
My Makefile:
PLUGINS_DIR = /usr/lib/gcc/i686-linux-gnu/4.6/plugin/include
INCLUDES = \
-I$(PLUGINS_DIR)
DEFINES = -Dbool=int -DTRUE=1 -DFALSE=0
plugin.so : plugin.o
gcc -shared -Wl,-export-dynamic -o plugin.so plugin.o
%.o : %.c
gcc $(DEFINES) $(INCLUDES) -fPIC -o $@ $^
clean :
rm *.o *.so
Plugin source code:
#include <aspell.h>
#include <gcc-plugin.h>
#include <coretypes.h>
#include <diagnostic.h>
#include <gimple.h>
#include <tree.h>
#include <tree-flow.h>
#include <tree-pass.h>
#define is_alpha(c) (((c)>64 && (c)<91) || ((c)>96 && (c)<123))
int plugin_is_GPL_compatible = 1;
static AspellSpeller *speller_g;
/* Help info about the plugin if one were to use gcc's --version --help */
static struct plugin_info speller_info =
{
.version = "42",
.help = "Hahahaha yeaaaaa....",
};
static struct plugin_gcc_version speller_ver =
{
.basever = "4.6",
};
/* We don't need to run any tests before we execute our plugin pass */
static bool speller_gate(void)
{
return true;
}
static const_tree is_str_cst(const_tree node)
{
/*
const_tree str = node;
// Filter out types we are ignoring
if (TREE_CODE(str) == VAR_DECL)
{
if (!(str = DECL_INITIAL(node)))
return NULL_TREE;
else if (TREE_OPERAND_LENGTH(str))
str = TREE_OPERAND(str, 0);
}
else if (TREE_CODE(str) == ADDR_EXPR &&
TREE_OPERAND_LENGTH(str) > 0)
str = TREE_OPERAND(str, 0);
if (TREE_CODE(str) != STRING_CST &&
TREE_OPERAND_LENGTH(str) > 0)
str = TREE_OPERAND(str, 0);
if (TREE_CODE(str) != STRING_CST)
return NULL_TREE;
else
return str;
*/
}
static AspellSpeller *init_spellchecker(void)
{
/*
AspellConfig *cfg;
AspellCanHaveError *err;
// Configure and instantiate a spell checker
cfg = new_aspell_config();
aspell_config_replace(cfg, "lang", "en_US");
err = new_aspell_speller(cfg);
if (aspell_error_number(err) != 0)
{
puts(aspell_error_message(err));
return NULL;
}
return to_aspell_speller(err);
*/
}
static void spell_check(const_gimple stmt, const_tree str)
{
/*
char buf[32] = {0};
const char *data, *end;
data = TREE_STRING_POINTER(str);
printf("Spell checking string: \'%s\'\n", data);
while (*data)
{
// Skip non alphas including whitespace
while (!is_alpha(data[0]))
{
if (data[0] == '\0')
return;
++data;
}
// Find the end of the word
end = data;
while (is_alpha(end[0]))
++end;
if ((end - data) > sizeof(buf))
return;
memcpy(buf, data, end - data);
buf[end-data] = '\0';
if (!(aspell_speller_check(speller_g, buf, end - data)))
warning_at(gimple_location(stmt), 0, "%s (bad spelling)", buf);
data = end;
}
*/
}
static unsigned speller_exec(void)
{
/*
unsigned i;
const_tree str, op;
basic_block bb;
gimple stmt;
gimple_stmt_iterator gsi;
FOR_EACH_BB(bb)
for (gsi=gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi))
{
stmt = gsi_stmt(gsi);
for (i=0; i<gimple_num_ops(stmt); ++i)
if ((op = gimple_op(stmt, i)) && (str = is_str_cst(op)))
spell_check(stmt, str);
}
return 0;
*/
}
/* See tree-pass.h for a list and desctiptions for the fields of this struct */
static struct gimple_opt_pass speller_pass =
{
.pass.type = GIMPLE_PASS,
.pass.name = "speller", /* For use in the dump file */
.pass.gate = speller_gate,
.pass.execute = speller_exec, /* Pass handler/callback */
};
/* Return 0 on success or error code on failure */
int plugin_init(struct plugin_name_args *info, /* Argument infor */
struct plugin_gcc_version *ver) /* Version of GCC */
{
struct register_pass_info pass;
if (strncmp(ver->basever, speller_ver.basever, strlen("4.6")))
return -1; /* Incorrect version of gcc */
pass.pass = &speller_pass.pass;
pass.reference_pass_name = "ssa";
pass.ref_pass_instance_number = 1;
pass.pos_op = PASS_POS_INSERT_AFTER;
/* Tell gcc we want to be called after the first SSA pass */
register_callback("speller", PLUGIN_PASS_MANAGER_SETUP, NULL, &pass);
register_callback("speller", PLUGIN_INFO, NULL, &speller_info);
/* Initilize our spell checker */
if (!(speller_g = init_spellchecker()))
return -1;
return 0;
}
The commented source code contains the function calls undefined for the linker too. As I understand, the problem is the same as for the register_callback
function.
Could someone help me to cope with this trouble? The good, detailed, not out-of-date, manual about gcc plugins writing would be very useful too. Any help would be greatly appreciated.
Try changing the second last line of the Makefile
to:
%.o : %.c
gcc $(DEFINES) $(INCLUDES) -fPIC -o $@ -c $^
Note the "-c" that I have added which tells it to compile, but not link during this phase.