VC 带的编译器名字叫 cl.exe 。
其中/ML 、 /MLd 、 /MT 、 /MTd 、 /MD 、 /MDd 。
这些选项告诉编译器应用程序想使用什么版本的 C 标准程序库。
/ML 对应单线程静态版的标准程序库 (libc.lib)
目标文件到底该链接谁呢,
在 cl 编译出的目标文件中会有一个专门的区域存放一些指导链接器如何工作的信息
在缺省库 (default library) 中指定了一个或多个库文件名
将告诉链接器在扫描的时候也把它们加入到输入文件列表中
写简单的程序,然后保存为 main.c :
/* main.c */
int main() { return 0; }
用下面这个命令编译 main.c:
cl /c main.c
【/c 】是告诉 cl 只编译源文件,不用链接。
上述命令也相当于 : cl /c /ML main.c 。
【目标文件】main.obj
搜索 "defaultlib" 字符串,通常你就会看到这样的东西 :
"-defaultlib:LIBC -defaultlib:OLDNAMES" 。
这就是保存在目标文件中的缺省库信息。
我们的目标文件显然指定了两个缺省库,
一个是单线程静态版标准库 libc.lib( 这与 /ML 选项相符 ) ,
另外一个是 oldnames.lib( 它是为了兼容微软以前的 C/C++ 开发系统 ) 。
VC 的链接器是 link.exe ,因为 main.obj 保存了缺省库信息,所以可以用
link main.obj或者 link main.obj libc.lib 来生成可执行文件
main.exe ,这两个命令是等价的。
但是如果你用
但是如果你用 link main.obj libcd.lib 的话,链接器会给出一个警告 : "warning LNK4098: defaultlib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library" ,因为你显式指定的标准库版本与目标文件的缺省值不一致。
通常来说,应该保证链接器合并的所有目标文件指定的缺省标准库版本一致,否则编译器一定会给出上 面的警告,
建一个源文件,就叫 mylib.c ,内容如下 :
/* mylib.c */
#include <stdio.h>
void foo()
{
printf("%s","I am from mylib!
");
}
用 cl /c /MLd mylib.c
lib.exe 是 VC 自带的用于将目标文件打包成程序库的命令,所以我们可以用lib /OUT:my.lib mylib.obj 将 mylib.obj 打包成库,输出的库文件名是 my.lib.
接下来把 main.c 改成 :
/* main.c */
void foo();
int main()
{
foo();
return 0;
}
用 cl /c main.c 编译,然后用 link main.obj my.lib
"warning LNK4098: defaultlib "LIBCD" conflicts with use of other libs; use /NODEFAULTLIB:library" 。
是我们粗心地把缺省标准库版本不一致的目标文件 (main.obj) 与程序库 (my.lib) 链接起来,导致了大灾难。解决办法很简单,要么用 /MLd 选项来重编译 main.c ;要么用 /ML 选项重编译 mylib.c 。