MS VC链接器(link.exe):为什么没有警告32/64位CPU架构不匹配?

时间:2011-10-29 12:36:23

标签: visual-c++ linker linker-errors lnk2019

(更新:根据汉斯的建议,这里是suggestion to improve link.exe's behaviour,如果你在那边有帐户,你可以投票。)


好的,我是个傻瓜。 1月份,我在我的计算机上安装了Oracle,Win7 Pro 64 Bit。我安装了64位版本。昨天,使用MSVC Express,我尝试编译并链接一个小型测试程序oci1.coci.hoci.lib

cl /nologo /c /I%ORACLE_HOME%\oci\include oci1.c
link /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib

我的尝试一直在LNK2019, which means unresolved external symbol 'symbol' referenced in function 'function'失败。当然,有问题的符号(_OCIEnvCreate)由oci.lib提供,因此链接器应该能够解析它。

我终于意识到它无法工作,因为我的编译器只有32位,导入库是64位。如果你是个傻瓜并且你不知道或不记得,那么你可以使用dumpbin实用程序看到它:

$ dumpbin /headers %ORACLE_HOME%\oci\lib\msvc\oci.lib | head
File Type: LIBRARY
FILE HEADER VALUES
        8664 machine (x64)

$ dumpbin /headers oci1.obj | head
File Type: COFF OBJECT
FILE HEADER VALUES
         14C machine (x86)

到目前为止,这么好。但我浪费了一些时间,并希望避免重复这种经历。

虽然不是不正确,但LNK2019错误消息并未引导您朝正确的方向前进。没有警告您正在尝试链接不同CPU架构的二进制文件。

请注意,当您指定X64体系结构时,会提示您指定X86二进制文件:

$ link /machine:x64 /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib
oci1.obj : fatal error LNK1112:
Modul-Computertyp "X86" steht in Konflikt mit dem Zielcomputertyp "x64".

但是,当您明确或隐含地指定X86架构时,没有这样的精确警告:

$ link /machine:x86 /nologo oci1.obj /LIBPATH:%ORACLE_HOME%\oci\lib\msvc oci.lib
oci1.obj : error LNK2019: Verweis auf nicht aufgelöstes externes Symbol
  "_OCIEnvCreate" in Funktion "_main".
oci1.exe : fatal error LNK1120: 1 nicht aufgelöste externe Verweise.

我刚刚找到/VERBOSE switch to link.exe,当使用提示时,我的64位oci.lib中找不到符号。

是否还有其他选项可以启用更多链接过程,呃,万无一失?


更新:根据Hans的回答,我在32位导入库上运行dumpbin,名称如下所示:

$ dumpbin /exports D:\Opt\MySQL5.5\lib\libmysql.lib
_load_defaults
_myodbc_remove_escape@8
_mysql_affected_rows@4
_mysql_autocommit@8
_mysql_change_user@16
_mysql_character_set_name@4

而我在这里处理的64位OCI导入库中的名称似乎未修饰:

OCIXmlDbFreeXmlCtx
OCIXmlDbInitXmlCtx
ORLRconNativeInt
ORLRvalNativeInt
OraCoreIsPhysicalRawFile
OraMemAlloc

Wikipedia regarding X86 calling conventions

  

在Windows上下文中编译x64体系结构时(无论是否   使用Microsoft或非Microsoft工具),只有一个调用   约定 - 这里描述的那个,所以stdcall,thiscall,cdecl,   fastcall等现在都是一样的。

还与article on name mangling相关。

现在对我有意义。唯一的调用约定,因此没有必要进行名称修改,因此在编译X86时,cdecl没有前导下划线。

1 个答案:

答案 0 :(得分:1)

我认为它只是抱怨在开始检查二进制兼容性之前缺少符号。这通常会首先发生,x64符号没有前导下划线,因为x64没有任何调用约定。除非您使用Microsoft导入库,否则它们根本不会装饰符号。

但我非常同意,首先获得兼容性错误会更有成效。不知道实施有多难。询问知道并且可以使其工作的人,向connect.microsoft.com发布功能请求