Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

This is exactly an example found online if not mistaken. When compiling the plugin, if gcc prompts that some of the libraries are not found, rather than using -I to specify each library one by one when compiling the plugin, can we use a Makefileto specify all these directories instead? Thanks

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top