我有一个嵌入式IoT项目,我希望首先通过使用Visual Studio等PC工具进行开发。我的嵌入式项目只有一个用于文件系统的闪存,我想将fopen
fread
等重定向到我在Windows上自己的私有实现。但是我遇到的是无法让我的私有CRT库优先于内置CRT(例如,由/MD
编译器开关驱动的内置行为)。
我有一个简单的三个项目解决方案。
项目1是测试可执行文件。它有一个主行:
int main()
{
test();
}
项目2和3是静态库。项目2具有:
#include <string.h>
#include <stdio.h>
void test()
{
printf("%s\n", strchr("x", 'x'));
}
项目3具有:
char * strchr(const char * s, int c) // exact signature of MSVC
{
return "overridden";
}
我希望输出为overridden
,但实际上是
x
但是如果我将其添加到项目1中:
printf("%s\n", strchr("y", 'y'));
输出将为
overridden
overridden
第一个来自库中test()
,第二个直接来自可执行文件main()
。
有什么建议吗?
答案 0 :(得分:1)
链接器在第一个匹配的基础上解析符号-优先级是分别链接的.obj文件,然后是.lib文件,其显示顺序是提交给命令行链接器的顺序。因此,通常只需链接您自己的替换符号即可覆盖库符号。我从未尝试过使用MSVC,但这是一种残酷的方法。
一种不依赖于特定链接器行为的替代解决方案是使用预处理器将标准符号替换为您自己的替代方案。例如:
#if defined _WIN32
#define fopen test_fopen
FILE* test_fopen( const char * filename, const char * mode ) ;
#endif
在名为testlib.h的头文件中添加所需的其他宏和声明,然后使用“强制包含”(MSVC中的/FI testlib.h
)将测试接口无处不在 。然后,当在Windows上构建时,所有fopen
调用将替换为test_fopen
调用替换函数。
答案 1 :(得分:1)
如果问题仅是由静态库中的CRT使用引起的,并且链接器在找到私有CRT静态库之前先找到MSVCRT DLL导出库,则解决方法可能是强制在可执行源文件中引用私有CRT
上面的匹配代码示例,以全局形式放置在main中:
static char * (*p_strchr)(const char *, int) = strchr;
这不理想,但是它以可靠的方式更改了链接程序的搜索顺序。
更多发现
链接器将发出LNK1169“一个或多个乘以定义的符号”(多个定义)链接器错误(可能不完全了解)。例如,可能会说fopen
被定义了多次,并且如果您在命令行上颠倒了私有库和MS库的顺序,那么可能会说fread
被定义了多次。可能是由于具有DLL导出签名的MSVC lib和私有lib是导入符号引起的。这种行为很难确定,因为它不会在所有被覆盖的函数上出错。
如果可以将所有专用库都切换到/MT
编译器开关(使用静态CRT),则LNK1169问题得到解决。