在链接时弱定义函数,并测试覆盖

时间:2012-02-01 23:25:56

标签: c++ gcc linker c++11 binutils

(环境:gcc 4.6,c ++ 11,glibc 2.13,binutils 2.21)

请考虑以下“关联”演示背景:

foo.h中

#pragma once
#include <iostream>

void foo();

foo1.cpp

#include "foo.h"

void foo()
{
    std::cout << "foo1";
}

foo2.cpp

#include "foo.h"

void foo()
{
    std::cout << "foo2";
}

的main.cpp

#include "foo.h"

int main()
{
    foo();
}

生成文件

compile: main.o foo1.o foo2.o

case1: compile
    g++ -o case1.x main.o

case2: compile
    g++ -o case2.x main.o foo1.cpp

case3: compile
    g++ -o case3.x main.o foo1.o foo2.o

clean:
    rm *.o *.x

我们有一个函数声明如下:

void foo();

我们有多个定义,一个在foo1.cpp中,另一个在foo2.cpp中。

我们将.cpp文件编译成.o文件:

$ make compile

没问题,生成了main.o,foo1.o和foo2.o。

案例1

然后我们尝试链接main.o:

$ make case1
error: undefined reference to 'foo()'

好的,main.o引用了foo但没有定义链接。

案例2

现在我们尝试链接main.o和foo1.o

$ make case2

foo1.o中有一个foo的定义,所以链接没有错误。

案例3

现在我们尝试链接main.o foo1.o和foo2.o

$ make case3
error: multiple definition of 'foo()'

链接器在foo1.o和foo2.o中找到foo的两个定义,因此它不是一个随机的,而是快速失败并且没有链接。

问题

我的问题是:

  1. 是否可以将foo1.cpp的foo版本(可能带有某种gcc属性或pragma)的定义标记为“weak”?特别是我希望案例1和案例2的行为保持不变,而案例3的行为更改为成功链接而没有警告或错误,并且foo2.cpp中foo的定义被链接(覆盖“弱”定义在foo1.cpp)。

  2. 是否可以在运行时测试(并分配给一个布尔变量)foo的弱版本是否被链接,还是强版本(显然没有执行该函数)。即在main中实现如下函数。

    template<typename FunctionPtr>
    bool is_weak_linked(FunctionPtr fp);
    
  3. is_weak_linked(foo)应该在案例2中返回true而在案例3中应该返回false。

1 个答案:

答案 0 :(得分:1)

至#1:

void foo() __attribute__((weak));
void foo()
{
    ...
}

#2:我不相信,不是你正在做的静态链接。该信息在链接时丢失。

修改

你总能抽象出你的方式#2。一些例子:

// Foo.h
extern void foo();
extern "C" void default_foo();
extern const bool is_weak_foo_linked;
template <void (*)()> bool is_weak_linked();

// Foo1.cc
extern "C" void default_foo() {...}
void foo() __attribute__((weak, alias("default_foo")));

extern const bool __attribute__((weak)) is_weak_foo_linked=true;
template <> bool is_weak_linked<foo>() __attribute__((weak));
template <> bool is_weak_linked<foo>() {return true;}

// Foo2.cc
void foo() {...}
extern const bool is_weak_foo_linked=false;
template <> bool is_weak_linked<foo>() {return false;}

// main.cc
#include "foo.h"
#include <iostream>
int main() {
    foo();
    std::cout<<is_weak_foo_linked<<std::endl;
    std::cout<<is_weak_linked<foo>()<<std::endl;
    std::cout<<(foo==default_foo)<<std::endl;
}