Chris J. Kiick
Chris J. Kiick

Reputation: 1505

Is this correct usage of weakref?

I want to allow the redefinition of a function in a .c file that is already defined in a header file. According to GCC manual on the weakref attribute:

The effect is equivalent to moving all references to the alias to a separate translation unit, renaming the alias to the aliased symbol, declaring it as weak, compiling the two separate translation units and performing a reloadable link on them.

Which sounds like exactly what I want to do. However, the following example does not compile with error:

tpp.c:18:13: error: redefinition of ‘foo’ tpp.c:6:13: note: previous definition of ‘foo’ was here

#include <sys/types.h>
#include <stdio.h>

/* this will be in a header file */
static void foo(void) __attribute__ ((weakref ("_foo")));

static void _foo(void)
{
    printf("default foo\n");
}

/* in a .c file #including the header mentioned above */
#define CUSTOM_FOO

#ifdef CUSTOM_FOO
static void foo(void)
{ 
    printf("user defined foo.\n");
}
#endif

int main(int argc, char **argv)
{
    printf("calling foo.\n");
    foo();
}

Am I using this correctly? What am I missing?

gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)

Upvotes: 7

Views: 3420

Answers (2)

David G.
David G.

Reputation: 690

Since I wanted to use weak or weakref, and the existing answer seemed incomplete, I decided to write up the options, and try to explain.

There are apparently three basic options:

  1. Use weakref. In this case, you write a static definition of a different name referencing the name you want, and it may or may not be null. You need to test the function before calling it. In this case, the alias option must be included either explicitly or as a parameter on weakref.
  2. Use weak without alias. In this case, things are simple and public. Again, it may or may not be null, and you must test it before calling it.
  3. Use weak and alias. In this case, the call and the declared alias must (apparently) be in the same source file. In this case, there is always a definition for the symbol, so you don't need to test for it. If there is an external definition of the name, you will get that in leiu of the alias.

In C++, when providing an alias name, the name must be the mangled form. (This was relevant to me, not to OP.)

My test sources are:

cat weakref.c :

#include <stdio.h>

static void fooref(void) __attribute__((weakref("foo")));

int main(int argc, char **argv)
{
    if (fooref) {
        printf("calling foo.\n");
        fooref();
    } else {
        printf("no foo to call. (do something default-ish)\n");
    }
}

cat weak.c :

#include <stdio.h>
#include "header.h"

int main(int argc, char **argv)
{
    if (foo) {
        printf("calling foo.\n");
        foo();
    } else {
        printf("no foo to call. (do something default-ish)\n");
    }
}

cat weakalias.c :

#include <stdio.h>
#include "header.h"

extern void foo(void) __attribute__ ((weak, alias ("defaultfoo")));

void defaultfoo(void)
{
    printf("default foo\n");
}

int main(int argc, char **argv)
{
    printf("calling foo.\n");
    foo();
}

cat header.h :

extern void foo(void) __attribute__ ((weak));

cat Makefile :

EXES = weakref weakreffoo weakalias weakaliasfoo weak weakfoo
all : ${EXES}

clean :
        -rm ${EXES} *.o

weakref : weakref.o 
        gcc -o $@ $^

weakreffoo : weakref.o foo.o
        gcc -o $@ $^

weakalias : weakalias.o header.h
        gcc -o $@ $^

weakaliasfoo : weakalias.o foo.o header.h
        gcc -o $@ $^

weak : weak.o header.h
        gcc -o $@ $^

weakfoo : weak.o foo.o header.h
        gcc -o $@ $^

cat foo.c :

#include <sys/types.h>
#include <stdio.h>

void foo(void)
{
    printf("custom foo\n");
}

My output reads:

$ ./weakref
no foo to call. (do something default-ish)
$ ./weakreffoo
calling foo.
custom foo
$ ./weak
no foo to call. (do something default-ish)
$ ./weakfoo
calling foo.
custom foo
$ ./weakalias
calling foo.
default foo
$ ./weakaliasfoo
calling foo.
custom foo
$

I initially decided on weakref, but am now leaning towards weak.

Upvotes: 2

Willi
Willi

Reputation: 327

As far as I understand that you need to define that function as extern. Then it work for me as follows:

user@horst:$ cat weakref.c

#include <sys/types.h>
#include <stdio.h>

/* this will be in a header file */
extern void foo(void) __attribute__ ((weak, alias ("_foo")));

void _foo(void)
{
    printf("default foo\n");
}

int main(int argc, char **argv)
{
    printf("calling foo.\n");
    foo();
}

user@horst:$ gcc weakref.c 
user@horst:$ ./a.out 
calling foo.
default foo
user@horst:$ cat weakrefUser.c
#include <stdio.h>
/* in a .c file #including the header mentioned above */
#define CUSTOM_FOO

#ifdef CUSTOM_FOO
void foo(void)
{ 
    printf("user defined foo.\n");
}
#endif
user@horst:$ gcc -c weakrefUser.c 
user@horst:$ gcc -c weakref.c 
user@horst:$ gcc weakref.o weakrefUser.o 
user@horst:$ ./a.out 
calling foo.
user defined foo.

Note1: It does not work with static functions, for the weak attribute, it need to be global.

Note2: Weak symbols are "only" supported for ELF targets.

Upvotes: 2

Related Questions