visual studio c链接器包装选项?

时间:2015-11-18 21:09:31

标签: c visual-studio linker cmocka

从这篇文章Unit testing with mock objects in C

  

这是通过使用--wrap链接器选项完成的,该选项将包装函数的名称作为参数。如果使用gcc编译测试,则调用可能如下所示:

     

$ gcc -g -Wl,--wrap=chef_cook waiter_test.c chef.c

在visual studio中编译C项目时如何做到这一点?

1 个答案:

答案 0 :(得分:1)

--wrap 中的 ld 可以通过 MSVC 链接器中的 /ALTERNATENAME 选项进行模拟。

我们从两个编译单元开始,比如从 foo.o 编译的 foo.c,其外部函数在 foo.h 中声明,main.o 来自 main.c。 (如果 foo 已编译为库,则情况不会有太大变化。)

// foo.h
int foo();

// foo.c
int foo() {
    return 0;
}

// main.c
#include <stdio.h>
#include "foo.h"
int main() {
    int x = foo();
    printf("%s\n", x ? "wrapped" : "original");
}

int foo() 的返回值为 0,因此上面的代码片段将输出“原始”。

现在我们用别名覆盖实际实现:#include "foo.h" 中的 main.c 被替换为

#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")

让我解释一下这里发生了什么:

  1. 通过#define foo real_foofoo.h 中的函数声明被修改为int real_foo()
  2. 然而,foo.o 中的符号仍然以 int foo() 命名,而不是别名 int real_foo()。这就是我们需要 /alternatename 链接器开关的原因。
  3. "/alternatename:real_foo=foo" 告诉链接器,如果找不到名为 real_foo 的符号,请在抛出错误之前再次尝试 foo
  4. 显然没有 int real_foo() 的定义。 MSVC 链接器将搜索 int foo() 并在每次出现 int real_foo() 时链接它。

由于之前的实现已被别名化,现在我们通过宏将 int foo() 重定向到我们的新实现:

int wrap_foo() {
    return real_foo() + 1;
}
#define foo wrap_foo

到此我们就完成了。最后 main.cpp 看起来像:

#include <stdio.h>

#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")

int wrap_foo() {
    return real_foo() + 1;
}
#define foo wrap_foo

int main() {
    int x = foo();
    printf("%s\n", x ? "wrapped" : "original");
}

内置于 MSVC,它会输出“wrapped”。