VC带的编译器名字叫cl.exe,它有这么几个与标准程序库有关的选项: /ML、/MLd、/MT、/MTd、/MD、/MDd。这些选项告诉编译器应用程序想使用什么版本的C标准程序库。/ML(缺省选项)对应单线程静态版的标准程序库(libc.lib);
/MT对应多线程静态版标准库(libcmt.lib),此时编译器会自动定义_MT宏;
/MD对应多线程DLL版(导入库msvcrt.lib,DLL是msvcrt.dll),编译器自动定义_MT和_DLL两个宏。
后面加d的选项都会让编译器自动多定义一个_DEBUG宏,表示要使用对应标准库的调试版,因此/MLd对应调试版单线程静态标准库(libcd.lib),/MTd对应调试版多线程静态标准库(libcmtd.lib),/MDd对应调试版多线程DLL标准库(导入库msvcrtd.lib,DLL是msvcrtd.dll)。
虽然我们的确在编译时明白无误地告诉了编译器应用程序希望使用什么版本的标准库,可是当编译器干完了活,轮到链接器开工时它又如何得知一个个目标文件到底在思念谁?为了传递相思,我们的编译器就干了点秘密的勾当。在cl编译出的目标文件中会有一个专门的区域(关心这个区域到底在文件中什么地方的朋友可以参考COFF和PE文件格式)存放一些指导链接器如何工作的信息,其中有一种就叫缺省库(default library),这些信息指定了一个或多个库文件名,告诉链接器在扫描的时候也把它们加入到输入文件列表中(当然顺序位于在命令行中被指定的输入文件之后)。说到这里,我们先来做个小实验。写个顶顶简单的程序,然后保存为main.c :
/* main.c */
int main() { return 0; }
用下面这个命令编译main.c(什么?你从不用命令行来编译程序?这个......) :
cl /c main.c
/c是告诉cl只编译源文件,不用链接。因为/ML是缺省选项,所以上述命令也相当于: cl /c /ML main.c 。如果没什么问题的话(要出了问题才是活见鬼!当然除非你的环境变量没有设置好,这时你应该去VC的bin目录下找到vcvars32.bat文件然后运行它。),当前目录下会出现一个main.obj文件,这就是我们可爱的目标文件。随便用一个文本编辑器打开它(是的,文本编辑器,大胆地去做别害怕),搜索"defaultlib"字符串,通常你就会看到这样的东西: "-defaultlib:LIBC -defaultlib:OLDNAMES"。啊哈,没错,这就
是保存在目标文件中的缺省库信息。我们的目标文件显然指定了两个缺省库,一个是单线程静态版标准库libc.lib(这与/ML选项相符),另外一个是oldnames.lib(它是为了兼容微软以前的C/C++开发系统)。
VC的链接器是link.exe,因为main.obj保存了缺省库信息,所以可以用
link main.obj libc.lib
或者
link main.obj
来生成可执行文件main.exe,这两个命令是等价的。但是如果你用
link main.obj libcd.lib
的话,链接器会给出一个警告: "warning LNK4098: defaultlib "LIBC" conflicts with use of other libs; use /NODEFAULTLIB:library",因为你显式指定的标准库版本与目标文件的缺省值不一致。通常来说,应该保证链接器合并的所有目标文件指定的缺省标准库版本一致,否则编译器一定会给出上面的警告,而LNK2005和LNK1169链接错误则有时会出现有时不会。那么这个有时到底是什么时候?呵呵,别着急,下面的一切正是为喜欢追根究底的你准备的。
建一个源文件,就叫mylib.c,内容如下:
/* mylib.c */
#include
void foo()
{
printf("%s","I am from mylib!\n");
}
用
cl /c /MLd mylib.c
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。