关于Windows下C/C++的编译
文章目录
一、前提
在 编译器中,我们编译程序的过程主要分成以下四个阶段。
- 预处理
- 编译
- 汇编
- 链接
具体的实现过程是按照以下的方式来进行的。接下来我们以 这个编译器为例,以及 这个文件为源文件完成对以上过程的理解。
(一)预处理
这一阶段的过程主要是对包含源代码的文本文件进行处理。主要的处理内容就是将在源文件中包含的头文件加载到文件中,替换宏定义等等。最终生成的文件是以 结尾的文本文件。
clang++ -E test.cpp -o test.i
(二)编译
这个阶段是将预处理得到的文件经由编译器变成汇编语言。汇编语言中的每一条语句都以一种标准的文本格式准确的描述一条地址机器指令。在这个阶段生成的文件才是机器相关的代码。这个阶段生成以 结尾的汇编文本文件。
clang++ -S test.i -o test.s
(三)汇编
这个阶段就是将上一步得到的汇编文件汇编成机器指令,从而把这些指令打包成为一种可重定向的目标程序格式。这个时候生成以 结尾的二进制文件。
clang++ -c test.s -o test.o
(四)链接
这个阶段主要是处理在文件中调用了系统库例如 等函数,那么就需要将系统库中的 合并到我们生成的 中。生成可执行的以结尾的 二进制文件。
clang++ test.o -o test.exe
二、使用clang命令
了解了以上的编译过程之后,就有人产生疑问了,那么为什么我们在通常进行编译的时候采用的命令只有以下的一行:
clang++ test.cpp -o test.exe
其实, 早已经将我们以上的四个步骤全部整合为以上的一条命令。这样就使得我们在进行编译的时候不必要生成过多的对运行没有意义的文件。只有在有需求的时候我们才去生成指定文件。
(一)包含外部的头文件
这个问题其实是在我的一个项目中用到的。在那个项目中我需要使用到 这个外部库。可是网上一搜全部是以 或者其他的 为载体来完成的。这对于我这种不喜欢繁重编译器的人来说这简直就是折磨。于是我自己在命令行配置了 并成功运行。
那么我们现在说一说关于怎样包含外部库。其实很简单,假设我们在编写 的时候,需要用到一个 的库,但是这个库并不在我们的标准库文件中。我们需要做的仅仅是在编译的时候在 后加上一个参数就好。如下:
clang++ --help
>> -I <dir> Add directory to include search path
// opencv.cpp
#include <opencv/opencv.hpp>
...
假设我们的以上包含的目录在 里,那么我们的编译命令变成了:
clang++ opencv.cpp -o opencv.exe -I D:/opencv/build/include
(二)包含外部的静态库
在 中,静态库是以 结尾的文件。有时候我们编译生成的文件也是需要使用到的。那么怎么将外部的 文件连接到我们的目标文件中呢?
我们仍然是借助 的 功能:
clang++ --help
>> -L <dir> Add directory to library search path
那么我们完全可以使用以下的命令对原来的数据进行编译:
假设我们的 文件在以下的文件夹 当中。
clang++ opencv.cpp -o test.exe -I D:/opencv/build/include -L D:/opencv/build/x64/vs15/lib
(三)连接静态库
到现在为止,我们静态库已经包含完成,但是怎么链接呢,这是个问题,因为不进行链接的话就无法完成外部库中函数的调用。会产生类似于以下的报错:
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_init,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_options,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_real_connect,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_error,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_query,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_use_result,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_fetch_row,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_num_fields,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_free_result,该符号在函数 main 中被引用
connect-bd0e58.o : error LNK2019: 无法解析的外部符号 mysql_close,该符号在函数 main 中被引用
也就是说会产生无法解析的外部符号的错,这就表明我们只是将数据包含进来,但是并没有链接成功。我们需要对其进行链接操作。对于静态库的链接有以下两种方式:
1.代码中链接
代码中链接是采用预处理的方式:
#pragma comment(lib, "libmysql")
这样就能实现链接到静态库的作用。
2.编译时命令行链接
编译时链接静态库方法就是, 就加静态库名字。
clang++ opencv.cpp -o test.exe -I D:/opencv/build/include -L D:/opencv/build/x64/vs15/lib -llibmysql
这样就完成了对静态库的链接。
(四)包含动态库
在 下,动态库一般是以 结尾的文件。那么怎样包含呢?实际上如果不包含动态库,在之前的各个阶段都不会有问题。因为动态库是运行时才用得到的库。因此在 界面中,往往会提示你缺少动态库请重新安装后使用。但是在命令行下就十分的狡猾,他甚至不提示任何东西,代码一行也不执行!甚至连最简单的写在 函数的第一行的输出 都不执行。而且表面上看起来没有任何异常。随之就程序结束了。我昨天在这个上吃了很多亏。因此需要注意的就是将 文件夹中的 文件复制到自己 下的这两个目录之下就可以运行了。
C:\Windows\System32
C:\Windows\SysWOW64
以上,送给一个像我一样,爱装逼又爱折腾的你!