【发布时间】:2017-08-25 11:58:37
【问题描述】:
我正在尝试使用cmocka 单元测试框架,该框架建议使用弱链接来选择用户定义的实现而不是函数的实际实现。在我的环境中,我有一个共享对象,我想对其进行单元测试。我在一个单独的文件中实现了单元测试,我编译并链接到共享对象。我的问题是,在共享对象中调用函数bar,然后在该共享对象中调用函数foo,总是会导致foo 的真正实现,而不是自定义的。我创建了共享对象和单元测试的简化实现。
共享库,a.c:
#include <stdio.h>
void foo(void); __attribute__((weak))
void bar(void); __attribute__((weak))
void foo(void) {
printf("called real foo\n");
}
void bar(void) {
printf("called real bar calling\n");
foo();
}
单元测试,b.c:
#include <stdio.h>
#include <stdbool.h>
bool orig_foo;
bool orig_bar;
void __wrap_foo(void) {
printf("in foo wrapper\n");
if (orig_foo)
__real_foo();
else
printf("called wrapped foo\n");
}
void __wrap_bar() {
printf("in bar wrapper\n");
if (orig_bar)
__real_bar();
else
printf("called wrapped bar\n");
}
int main(void) {
orig_bar = true;
orig_foo = false;
printf("calling foo from main\n");
foo();
printf("\n");
printf("calling bar from main\n");
bar();
return 0;
}
最后,Makefile:
all: a.out
a.out: b.c a.so
gcc -Wall b.c a.so -Wl,--wrap=foo -Wl,--wrap=bar
a.so: a.c
gcc -Wall -c a.c -shared -o a.so
clean:
rm -f a.so a.out
运行 a.out 会产生以下输出:
# ./a.out
calling foo from main
in foo wrapper
called wrapped foo
calling bar from main
in bar wrapper
called real bar
called real foo
从 main 中,直接调用 foo 会导致调用 __wrap_foo,正如预期的那样。
接下来,我从 main 调用 bar,这正确地导致 __wrap_bar 被调用,我将调用重定向到 bar (__real_bar) 的实际实现。 bar 然后调用 foo 但使用的是真正的实现,而不是包装的。为什么在这种情况下不调用 foo 的包装实现?看起来问题与函数调用的来源有关。
在函数bar 中,如果我用__wrap_foo 替换对foo 的调用,我确实得到了预期的行为,但我不认为这是一个优雅的解决方案。
我已经设法使用普通链接和dlopen(3) 和朋友绕过了这个问题,但是我很好奇为什么弱链接在我的情况下不起作用。
【问题讨论】:
-
共享库代码中的弱属性被破坏。
-
a.so的 Makefile 行已完全损坏。您创建一个对象文件而不是共享库。 -
确实,我修复了从
a.o生成a.so的makefile(使用-fpic编译),但我得到了完全相同的行为。 -
如果我将
foo和bar拆分为单独的文件并将所有内容编译在一起,我的示例将有效。
标签: c unit-testing shared-libraries dynamic-linking weak-linking