假设我有两个编译器,甚至是一个带有两个不同选项集的编译器。每个编译器将一些C代码编译成一个对象,我尝试将两个.o文件与一个公共链接器链接起来。这会成功吗?
我最初的想法是:并非总是如此。如果编译器使用相同的目标文件格式并具有兼容的选项,那么它将成功。但是,如果编译器具有冲突的选项,或者(并且这很容易)使用两种不同的目标文件格式,它将无法正常工作。
有没有人对此有更多了解?目标文件需要符合哪些标准才能确信这将起作用?
答案 0 :(得分:1)
* nix操作系统的大多数版本都有明确定义和开放ABI,并且大多使用ELF目标文件格式,因此对于* nix来说根本不是问题。
Windows的定义不太严格,不同的编译器在某些调用约定中可能会有所不同(例如某些编译器可能不支持__fastcall,或者可能有不同的行为,请参阅https://en.wikipedia.org/wiki/X86_calling_conventions)。但主要的调用约定集(__stdcall,_cdecl等)足以确保成功调用一个编译器从另一个编译器编译的函数,否则该程序根本无法工作,因为与Linux不同,Windows中的每个系统调用都被包装来自DLL的函数,您需要成功调用。
另一个问题是目标文件没有标准的通用格式。虽然大多数工具(MS,Intel,GCC(MinGW),Clang)使用COFF格式,但有些可能使用OMF(Watcom)或ELF(TinyC)。
另一个问题是所谓的“名称修改”。虽然它是为了支持使用相同名称重载C ++函数而引入的,但C编译器采用它来防止使用不同调用约定定义的函数的链接。例如,function int _cdecl fun(void);将获得编译名称_fun而int __stdcall fun(void);将获得名称_fun @ 0。有关名称修改的更多信息,请参阅此处:https://en.wikipedia.org/wiki/Name_mangling。
最后,某些编译器的默认行为可能不同,所以是的,选项可能会阻止不同编译器甚至同一编译器生成的目标文件的成功链接。例如,TinyC使用默认约定_cdecl,而CLang使用__stdcall。具有默认选项的TinyC可能不会生成可能与其他链接的代码,因为它不会通过下划线符号添加名称。为了使其可交叉链接,需要使用-fleading-underscore选项。
但请记住上面所说的所有代码可能会成功混合。例如,我成功地将Visual Studio,Intel Parallel Studio,GCC(MinGW),Clang,TinyC,NASM生成的代码链接在一起。