Visual Studio C 链接器换行选项?

pog*_*man 8 c linker visual-studio cmocka

从这篇文章中使用 C 中的模拟对象进行单元测试

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

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

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

小智 5

可以通过MSVC --wrapLinker中的选项来模拟。ld/ALTERNATENAME

我们从两个编译单元开始,例如foo.o从 编译,其外部函数在和中foo.c声明。(如果已经编译为库,事情不会有太大变化。)foo.hmain.omain.cfoo

// 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");
}
Run Code Online (Sandbox Code Playgroud)

返回值int foo()是0,所以上面的代码片段将输出“original”。

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

#define foo real_foo
#include "foo.h"
#undef foo
#pragma comment(linker, "/alternatename:real_foo=foo")
Run Code Online (Sandbox Code Playgroud)

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

  1. 通过#define foo real_foo, 中的函数声明foo.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()int foo()MSVC 链接器将在每次出现 时搜索并链接它int real_foo()

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

int wrap_foo() {
    return real_foo() + 1;
}
#define foo wrap_foo
Run Code Online (Sandbox Code Playgroud)

我们到这里就完成了。最后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");
}
Run Code Online (Sandbox Code Playgroud)

内置MSVC,它将输出“wrapped”。