2011-07-25 54 views
10

我需要验证一些我有疑问的东西。如果共享库(.dll)用C语言编写,并使用C99标准编译并在编译器下编译。说MinGw。然后根据我的经验,它是二进制兼容的,因此可以从任何其他编译器使用。说MS Visual Studio。我以我的经验说过,因为我已经不止一次成功尝试过它。但我需要验证这是否是一条规则。交叉编译器在C中的二进制兼容性

另外我想问一下它是否确实如此,那么为什么完全用C编写的库,例如openCV就不会为每个不同的OS提供编译的二进制文件?我知道显而易见的原因是设置所有的编译时间参数,但除此之外没有一个是正确的?

编辑:我添加了一个额外的问题,我认为这是对原始的逻辑扩展。难道这不是如何去创建一个封闭的源代码库吗?由于给予源的选项不在窗口中,所以给二进制文件是唯一的选择。在这种情况下,为尽可能多的体系结构提供二进制文件是期望的结果,C是系统和编译器之间具有最佳可移植性的明显选择。对?

+0

非常有趣的问题。奇怪的是,即使我在80年代早期和80年代在UN * X的世界中担任调试人员,我从未真正给过这种深刻的想法。当然,我主要是使用符号表作为指导,但是仍然可能存在结构中的比特包装问题以及堆栈中的参数问题。我猜在这个世界上,大部分代码都是用制造商的编译器或GCC的一个或另一个版本编译的,所以它有一个固有的一致性,但这并不是你所要求的。 –

回答

6

在Windows世界中的C编译器(MSVC和GCC/MinGW)的具体情况下,您在假设二进制兼容性时是正确的。可以将由GCC编译的C接口DLL链接到Visual Studio中的程序。这是C99项目(如ffmpeg)允许开发人员使用Visual Studio编写应用程序的方式。只需要在DLL中的Microsoft工具链中创建带有lib.exe的导入库。反之亦然,使用mingw.org的pexports或更好的,mingw-w64的gendef工具,可以为MSVC生成的DLL创建一个GCC导入库。

当您进入C++界面世界时,MSVC和GCC的ABI不同且不兼容,这种方便的互操作性会出现问题。它可能工作,也可能不工作,没有保证,也没有努力(当前)正在改变这种情况。此外,调试信息显然是不同的,直到有人在GCC中写入与MSVC调试器兼容的调试信息生成器/写入器(当然还有gdb支持)。

我不认为C99特别改变了函数声明的任何内容,或者在符号定义中处理参数的方式,所以这里也没有问题。

请注意,正如Vijay所说,仍然存在体系结构差异,因此x86库无法在链接到AMD64库时使用。


还回答关于封闭源代码二进制文件和分发所有可用编译器/体系结构版本的附加问题。

这正是您创建封闭源代码二进制文件的方式。除了导入库之外,隐藏DLL的导出也很重要,这使得DLL本身无法用于链接(如果您不希望客户端代码在库中使用私有函数,请参阅例如dumpbin /exports的输出在MSOffice DLL上,有很多隐藏的东西)。你可以使用像__attribute(hidden)等这样的东西来达到与GCC相同的效果(我相信,从未使用或尝试过)......

一些编译器的特定点:

  1. MSVC带有四个通过/ MT,/ MD,和/ LD(好吧,其实只有三个在新版本中剩余的)不同的运行时库。除此之外,您必须为每个版本的Visual Studio(包括Service Pack)提供构建以确保兼容性。但是,这是封闭的源代码二进制文件和Windows ...

  2. GCC没有这个问题; MinGW总是链接到Windows(从Windows 98开始)提供的msvcrt.dll,等同于/ MD(也可能是与/ MDd相同的调试库)。但是我有两个版本的MinGW(mingw.org和mingw-w64),它们不保证二进制兼容性。后者更完整,因为它提供了64位选项以及32位,并提供了更完整的头文件/库集(包括DirectX和DDK的相当一部分)。

+0

感谢您的回答,当然不同的体系结构需要重新编译我想其他编译器。 C++接口是什么意思?在所有编译器中都不一样,如果将外部库“012”包含在外部“C”{...}中,可以从外部库调用C代码? 我的问题也延伸到你将如何开发一个封闭的源库。你将需要提供二进制文件,所以C无疑承认最好的二进制可移植性是一个明显的选择,对吗? – Lefteris

+0

Lefteris:看到我的更新,是的,'extern“C”{...}'是你需要提供一个C接口。一个C++接口可以通过编译g ++来完成,而忽略了这个部分,这个部分允许名字加入,这是交叉编译器兼容性的一个阻塞。 – rubenvb

+0

非常感谢您的回答,它非常详细。就我知道的名字而言,过去不幸的是我很多次都在我的脸上,而这正是我在我的一些项目中转而回到C的便携性的原因。 – Lefteris

2

编译到特定体系结构的共享库或dll可以链接到由其他编译器编译的应用程序,这些编译器以相同体系结构为目标。 (按架构,我的意思是一个处理器/操作系统组合)。但是,图书馆开发人员不可能针对所有可能的架构进行编译。而且,当一个库以源代码格式分发时,用户可以构建优化其特定需求的二进制文件。

4

的一般规则是,如果你的OS/CPU组合有一个标准的ABI,如果这个ABI是你的语言足够强大,大多数编译器将遵循ABI,结果将是二进制兼容的,允许您可以将使用不同编译器编译的库(共享或静态)链接到使用其他编译器编译的程序就好。

问题是大多数ABI都相当薄弱 - 它们是围绕像C和FORTRAN这样的低级语言设计的,可以追溯到面向对象语言(如C++)之前的日子。所以他们倾向于缺乏对函数重载,用户定义的运算符,异常,全局构造函数和析构函数,虚函数,继承等类似C++所需要的支持。

当C++被设计出来时,就认识到了这个缺点,这就是为什么C++有extern "C" - 这会导致编译器将自身限制为某些功能的标准ABI,同时禁用ABI通常不支持的所有额外C++功能。