前言
MinGW是一个在Windows系统上运行的GNU编译器套件,支持C和C++语言的编译。可以进行跨平台开发,生成可在Windows、Linux等多种操作系统上运行的代码,还可以对项目进行性能优化。在学习MinGW后,我们将对代码的编译链接有更多的了解,也会对静态链接库和动态链接库有一个清晰的认知
MinGW之编译文件
首先我们得先简单的对可执行文件以及MinGW命令进行简单的了解
1.使用MinGW编译代码分为对C++文件以及对C文件两种。针对C++文件,在MinGW中以g++开头,针对C文件则以gcc开头
gcc 文件名.c //编译C文件
g++ 文件名.cpp //编译CPP文件
2.Windows下编译生成的可执行文件为以.exe为后缀的文件,Linux下编译生成的可执行文件以.out为后缀的文件
3.Windows下运行可执行文件直接在MinGW命令行中输入可执行文件名,Linux下运行则需要以”./文件名.out”的方式运行
//Windows下运行可执行的main.exe文件
main
//Linux下运行可执行的main.out文件
./main.out
接下来,我们将使用-o命令(o为小写)进行编译文件并产生指定名称的可执行文件
//编译C文件生成可执行的exe文件
gcc -o 生成的可执行文件名 文件名.c
//编译CPP文件生成可执行的exe文件
g++ 文件名.cpp -o 生成的可执行的文件名
![](http://wild-pointer.top/wp-content/uploads/2024/06/1.png)
图1.使用g++编译生成的可执行文件main.exe
MinGW之编译过程
针对编译过程,分为预处理,编译,汇编以及链接四种阶段,在每一个阶段生成的文件都不同,接下来将对每一个阶段执行的命令进行解析,并且分析每一个阶段代码的变化
1.预处理阶段:
了解预处理阶段,MinGW所做的事:
1.预处理阶段将产生后缀为.i的文件
2.预处理阶段将处理#include预编译命令,将被包含的文件插入指令位置
3.处理所有的条件预编译命令(如#if,#ifdef,#elid等等)
4.将#define宏定义删除,并替代所有的宏定义指令
5.删除文件中所有注释
6.添加行号和标识,以便编译时产生调试用的行号和编译警告或错误的行号
7.保留所有的#pragma编译器指令
使用-E命令生成预处理文件
//使用-E指令生成预处理文件,其中必须定义生成的预处理文件名
g++ -E 进行预处理的文件.cpp -o 生成的预处理文件名.i
![](http://wild-pointer.top/wp-content/uploads/2024/06/2-1024x588.png)
图2.使用-E命令生成预处理文件的对比
2.编译阶段:
了解编译阶段,MinGW所做的事:
1.生成后缀为.s的编译文件
2.MinGW将对预处理后生成的.i文件进行词法分析,语法分析和优化等操作
使用-S命令生成编译后的文件
//使用-S指令生成编译文件,其中无须定义生成的编译文件名
g++ -S 预处理文件.i
![](http://wild-pointer.top/wp-content/uploads/2024/06/3-1024x572.png)
图3.使用-S命令生成编译文件的对比
3.汇编阶段:
了解汇编阶段,MinGW所做的事:
1.生成后缀为.o的二进制文件
2.使用汇编器将后缀为.s的文件翻译成机器语言指令,然后把指令打包成可重定位目标程序的格式
使用-c命令(小写)生成二进制文件
//使用-c指令生成二进制文件
g++ -c 汇编文件.s
![](http://wild-pointer.top/wp-content/uploads/2024/06/4-1024x554.png)
图4.使用-c命令生成二进制文件的对比
4.链接阶段:
了解链接阶段,MinGW所做的事:
1.生成后缀为.exe的可执行文件(Windows下)
2.文件中调用了其他库的函数,将在这个阶段将其与源码进行连接
使用-o命令(小写)生成可执行文件
//使用-o指令生成可执行文件,需要定义可执行文件名称
g++ -o 可执行文件名 二进制文件.o
![](http://wild-pointer.top/wp-content/uploads/2024/06/5-1024x479.png)
图5.使用-o命令生成可执行文件
5.快速编译文件到指定的阶段以及指定编译器使用静态链接(默认为动态链接):
1.快速编译文件到指定的阶段:
需要执行操作到哪一个阶段,就直接使用对应的指令即可
//将.CPP文件直接执行到汇编阶段,生成.o文件
g++ -c 文件名.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/6-1024x518.png)
图6.将文件执行到指定阶段
2.指定编译器使用静态链接:
使用-static命令指定编译器使用静态链接的方式链接文件
//使用静态链接的方式链接文件
g++ -static 源文件名.cpp -o 生成的可执行文件名
![](http://wild-pointer.top/wp-content/uploads/2024/06/7-1024x377.png)
图7.使用静态链接的方式链接文件
MinGW之编码
由于常用的如VSCode,VS等编译器的编码方式一般为UTF-8,而在使用MinGW一般是在命令行窗口,支持的是GBK编码,所以导致文件中若存在中文等字符的话,可能会出现乱码的现象。下面将会从编译器以及命令行的方式修改编码格式:
1.将使用的编译器中的编码方式改为GBK
![](http://wild-pointer.top/wp-content/uploads/2024/06/8.png)
图8.修改VSCode中的编码格式
2.将命令行窗口中的编码格式改为UTF-8
//在命令行中输入
chcp 65001
![](http://wild-pointer.top/wp-content/uploads/2024/06/9.png)
图9.修改命令行窗口中的编码格式
3.使用-finput-charset命令和-fexec-charset命令修改文件的编码格式
//使用-finput-charset设置文件编码格式
g++ -o 可执行文件名 -finput-charset=UTF-8 -fexec-charset=GBK 源文件.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/10-1024x354.png)
图10.使用-finput-charset命令和-fexec-charset命令修改编码格式
MinGW之警告与优化
警告提示和优化,一般都是必不可少的部分,在编译期间若文件存在错误,可读性强的警告或错误能有利于自己排查和修改,下面将针对警告和优化两个方面进行讲解:
1.使用-W命令开启编译生成期间的警告
//开启编译生成期间的警告
g++ -o 可执行文件名 -W 源文件.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/11-1024x494.png)
图11.使用-W命令开启警告
2.使用-Wall命令开启编译生成期间的所有警告
//开启编译生成期间的所有警告
g++ -o 可执行文件名 -Wall 源文件.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/12-1024x637.png)
图12.使用-Wall命令开启警告
3.使用-Wunused-variable命令开启指定的Wunuser-variable警告和默认警告(其他指定的警告也可以通过修改-Wunused-variable的类型来修改)
//开启指定的wunuser-variable警告和默认警告
g++ -o 可执行文件名 -Wunused-variable 源文件.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/13-1024x524.png)
图13.使用-Wunused-variable命令开启默认警告和指定警告
4.使用-Wno命令关闭编译期间的指定警告
//关闭指定的return-local-addr警告和默认警告
g++ -o 可执行文件名 -Wno-return-local-addr 源文件.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/14.png)
图14.使用-Wno命令关闭指定的return-local-addr警告
5.使用Werroe命令将编译生成期间的警告当作错误提示
//使用Werroe命令将编译生成期间的警告当作错误提示
g++ -o 生成的可执行文件名 -Werror 源文件.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/15-1024x509.png)
图15.使用-Werror命令将编译生成期间的警告当作错误提示
6.使用-O命令(大写)设置文件优化等级,其中优化等级共分为3个,优先级从1到3
//在编译生成期间对文件进行优化,优化等级为1
g++ -o 可执行文件名 -O1 源文件.cpp
//在编译生成期间对文件进行优化,优化等级为2
g++ -o 可执行文件名 -O2 源文件.cpp
//在编译生成期间对文件进行优化,优化等级为3
g++ -o 可执行文件名 -O3 源文件.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/16-1024x401.png)
图16.对编译源文件进行等级为1的优化
MinGW之多个文件编译
在显示情况中,我们的项目往往会有多个源文件,而且每一个源文件可能会分布在不同的路径下,这时我们就需要了解对多个文件进行编译以及编译指定路径下的文件,针对以上情况有以下做法:
1.针对多个文件编译,可以把文件名依次列出
//同时编译多个文件
g++ -o 可执行文件名 源文件1.cpp 源文件2.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/17-1024x486.png)
图17.同时编译多个文件
2.使用通配符*来编译多个文件(文件全部处于当前路径下)
//使用通配符*来编译多个文件(文件全部处于当前路径下)
g++ -o 可执行文件名 *.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/18.png)
图18.使用通配符同时编译多个文件
3.分别对源文件进行编译,再对编译生成的.o文件进行链接
//对编译生成的.o文件进行链接
g++ -o 可执行文件名 文件1.o 文件2.o
![](http://wild-pointer.top/wp-content/uploads/2024/06/19.png)
图19.使用对编译生成的.o文件进行链接
4.当头文件路径不同时,可指定头文件路径,生成可执行文件
//指定头文件路径,生成可执行文件
g++ -I"文件路径" -o 可执行文件名 源文件.cpp 源文件2.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/20-1024x433.png)
图20.指定头文件路径编译
5.当头文件和源文件路径都不同时,也可以指定源文件路径生成可执行文件
//指定头文件和源文件路径,编译生成可执行文件
g++ -I"头文件路径" -o 可执行文件名 源文件.cpp 源文件2路径
![](http://wild-pointer.top/wp-content/uploads/2024/06/21.png)
图21.指定头文件和源文件路径进行编译
6.当头文件路径不同时,也可以指定多个头文件路径进行编译
//指定多个头文件路径进行编译
g++ -I"头文件1路径" -I"头文件2路径" -o 可执行文件名 源文件.cpp 源文件2.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/22-1024x432.png)
图22.指定多个头文件路径进行编译
MinGW之静态链接库编译
静态链接库在程序运行时不会被加载到内存中,而是其内容在编译时期就已经被复制到了最终的可执行文件里,所以导致静态链接生成的可执行文件相较于动态链接库的可执行文件大。在了解静态链接库之前,先了解以下静态链接库:
1.静态链接库的命名规则为lib+文件名+.a,所以以.a结尾的文件,一般可以视为静态链接库的文件
编译静态链接库的步骤:
1.使用-c命令生成汇编文件
//使用-c命令生成汇编文件
g++ -c -I"头文件路径" *.cpp
2.使用ar命令打包生成静态链接库
//使用ar命令生成静态链接库
ar rcs 静态链接库名.a 汇编文件.o
//ar rcs libfun.a fun.o
//其中r代表替换.o文件,c代表库不存在则生成,s代表生成索引文件
![](http://wild-pointer.top/wp-content/uploads/2024/06/23-1024x434.png)
图23.生成静态链接库
3.将源文件与静态链接库链接产生可执行文件
//方法1
g++ 源文件.o -o 可执行文件名 静态链接库路径
//方法2
g++ 源文件.o -o 可执行文件名 -L静态链接库路径
//方法3,其中静态链接库名为除去lib和.a的名称
//例如libfun.a,其静态链接库名就为fun
g++ 源文件.o -o 可执行文件名 -L静态链接库路径 -l静态链接库名
![](http://wild-pointer.top/wp-content/uploads/2024/06/24.png)
图24.多种方法链接静态链接库
MinGW之动态链接库编译
先前讲了静态链接库的操作方法,而动态链接库也是相似:
1.Windows下的动态链接库的命名规则为lib+文件名+.dll,所以以.dll结尾的文件,一般可以视为动态链接库的文件
2.Linux下的动态链接库的命名规则为lib+文件名+.so,所以Linux中以.so结尾的文件,一般可以视为动态链接库的文件
编译动态链接库的步骤:
1.使用-c命令生成汇编文件
//使用-c命令生成汇编文件
g++ -c -I"头文件路径" *.cpp
2.使用-shared命令生成动态链接库
//使用-shared命令生成动态链接库
g++ -o 动态链接库.dll -I"头文件路径" -fPIC -shared *.cpp
![](http://wild-pointer.top/wp-content/uploads/2024/06/25-1024x420.png)
图25.生成动态链接库
3.将源文件与动态链接库链接产生可执行文件
//方法1
g++ 源文件.o -o 可执行文件名 动态链接库路径
//方法2
g++ 源文件.o -o 可执行文件名 -L动态链接库路径
//方法3,其中动态链接库名为除去lib和.dll的名称
//例如libfun.dll,其静态链接库名就为fun
g++ 源文件.o -o 可执行文件名 -L动态链接库路径 -l动态链接库名
![](http://wild-pointer.top/wp-content/uploads/2024/06/26.png)
图26.链接动态链接库