高效工具实战指南:MinGW从入门到链接库

本文详细介绍了MinGW编译器在Windows系统下的使用方法。主要内容包括:1)MinGW的基本编译命令(gcc/g++)和可执行文件生成;2)编译过程的四个阶段(预处理、编译、汇编、链接)及其对应的命令参数;3)编码格式问题的解决方案;4)警告选项(-W、-Wall)和优化等级(-O1/-O2/-O3)的使用;5)多文件编译和路径指定方法;6)静态链接库(.a文件)的创建与链接;7)动态链接库(.dll文件)的创建与链接。文章通过具体命令示例和图示,帮助开发者掌握MinGW编译工具链的各项功能。

作者
WildPointer
发布
2024.04.16
专栏
高效工具实战指南
阅读
约 8 分钟 / 3,272 次原文浏览
高效工具实战指南:MinGW从入门到链接库

前言

MinGW是一个在Windows系统上运行的GNU编译器套件,支持C和C++语言的编译。可以进行跨平台开发,生成可在Windows、Linux等多种操作系统上运行的代码,还可以对项目进行性能优化。在学习MinGW后,我们将对代码的编译链接有更多的了解,也会对静态链接库和动态链接库有一个清晰的认知。


MinGW之编译文件

首先我们得先简单的对可执行文件以及MinGW命令进行简单的了解

1.使用MinGW编译代码分为对C++文件以及对C文件两种。针对C++文件,在MinGW中以g++开头,针对C文件则以gcc开头

cpp
gcc    文件名.c         //编译C文件g++    文件名.cpp       //编译CPP文件

2.Windows下编译生成的可执行文件为以.exe为后缀的文件,Linux下编译生成的可执行文件以.out为后缀的文件

                  3.Windows下运行可执行文件直接在MinGW命令行中输入可执行文件名,Linux下运行则需要以"./文件名.out"的方式运行

cpp
//Windows下运行可执行的main.exe文件main//Linux下运行可执行的main.out文件./main.out

接下来,我们将使用-o命令(o为小写)进行编译文件并产生指定名称的可执行文件

cpp
//编译C文件生成可执行的exe文件gcc -o 生成的可执行文件名 文件名.c//编译CPP文件生成可执行的exe文件g++ 文件名.cpp -o 生成的可执行的文件名

图1.使用g++编译生成的可执行文件main.exe


MinGW之编译过程

        针对编译过程,分为预处理,编译,汇编以及链接四种阶段,在每一个阶段生成的文件都不同,接下来将对每一个阶段执行的命令进行解析,并且分析每一个阶段代码的变化

1.预处理阶段:

                了解预处理阶段,MinGW所做的事:

1.预处理阶段将产生后缀为.i的文件

2.预处理阶段将处理#include预编译命令,将被包含的文件插入指令位置

3.处理所有的条件预编译命令(如#if,#ifdef,#elid等等)

4.将#define宏定义删除,并替代所有的宏定义指令

5.删除文件中所有注释

6.添加行号和标识,以便编译时产生调试用的行号和编译警告或错误的行号

7.保留所有的#pragma编译器指令

使用-E命令生成预处理文件

cpp
//使用-E指令生成预处理文件,其中必须定义生成的预处理文件名g++ -E 进行预处理的文件.cpp -o 生成的预处理文件名.i

图2.使用-E命令生成预处理文件的对比

2.编译阶段:

了解编译阶段,MinGW所做的事:s'c

1.生成后缀为.s的编译文件

1.MinGW将对预处理后生成的.i文件进行词法分析,语法分析和优化等操作

使用-S命令生成编译后的文件

cpp
//使用-S指令生成编译文件,其中无须定义生成的编译文件名g++ -S 预处理文件.i

图3.使用-S命令生成编译文件的对比

3.汇编阶段:

了解汇编阶段,MinGW所做的事:

1.生成后缀为.o的二进制文件

2.使用汇编器将后缀为.s的文件翻译成机器语言指令,然后把指令打包成可重定位目标程序的格式

使用-c命令(小写)生成二进制文件

cpp
//使用-c指令生成二进制文件g++ -c 汇编文件.s

图4.使用-c命令生成二进制文件的对比

4.链接阶段:

了解链接阶段,MinGW所做的事:

1.生成后缀为.exe的可执行文件(Windows下)

2.文件中调用了其他库的函数,将在这个阶段将其与源码进行连接

使用-o命令(小写)生成可执行文件

cpp
//使用-o指令生成可执行文件,需要定义可执行文件名称g++ -o 可执行文件名 二进制文件.o

图5.使用-o命令生成可执行文件

5.快速编译文件到指定的阶段以及指定编译器使用静态链接(默认为动态链接):

               1.快速编译文件到指定的阶段:

需要执行操作到哪一个阶段,就直接使用对应的指令即可

cpp
//将.CPP文件直接执行到汇编阶段,生成.o文件g++ -c 文件名.cpp 

图6.将文件执行到指定阶段

2.指定编译器使用静态链接:

使用-static命令指定编译器使用静态链接的方式链接文件

cpp
//使用静态链接的方式链接文件g++ -static 源文件名.cpp -o 生成的可执行文件名

图7.使用静态链接的方式链接文件


MinGW之编码

由于常用的如VSCode,VS等编译器的编码方式一般为UTF-8,而在使用MinGW一般是在命令行窗口,支持的是GBK编码,所以导致文件中若存在中文等字符的话,可能会出现乱码的现象。下面将会从编译器以及命令行的方式修改编码格式:

1.将使用的编译器中的编码方式改为GBK

图8.修改VSCode中的编码格式

2.将命令行窗口中的编码格式改为UTF-8

cpp
//在命令行中输入chcp 65001

图9.修改命令行窗口中的编码格式

3.使用-finput-charset命令和-fexec-charset命令修改文件的编码格式

cpp
//使用-finput-charset设置文件编码格式g++ -o 可执行文件名 -finput-charset=UTF-8 -fexec-charset=GBK 源文件.cpp

图10.使用-finput-charset命令和-fexec-charset命令修改编码格式


MinGW之警告与优化

        警告提示和优化,一般都是必不可少的部分,在编译期间若文件存在错误,可读性强的警告或错误能有利于自己排查和修改,下面将针对警告和优化两个方面进行讲解:

                1.使用-W命令开启编译生成期间的警告

cpp
//开启编译生成期间的警告g++ -o 可执行文件名 -W 源文件.cpp

图11.使用-W命令开启警告

2.使用-Wall命令开启编译生成期间的所有警告

cpp
//开启编译生成期间的所有警告g++ -o 可执行文件名 -Wall 源文件.cpp

图12.使用-Wall命令开启警告

3.使用-Wunused-variable命令开启指定的Wunuser-variable警告和默认警告(其他指定的警告也可以通过修改-Wunused-variable的类型来修改)

cpp
//开启指定的wunuser-variable警告和默认警告g++ -o 可执行文件名 -Wunused-variable 源文件.cpp

图13.使用-Wunused-variable命令开启默认警告和指定警告

4.使用-Wno命令关闭编译期间的指定警告

cpp
//关闭指定的return-local-addr警告和默认警告g++ -o 可执行文件名 -Wno-return-local-addr 源文件.cpp

图14.使用-Wno命令关闭指定的return-local-addr警告

5.使用Werroe命令将编译生成期间的警告当作错误提示

cpp
//使用Werroe命令将编译生成期间的警告当作错误提示g++ -o 生成的可执行文件名 -Werror 源文件.cpp

图15.使用-Werror命令将编译生成期间的警告当作错误提示

6.使用-O命令(大写)设置文件优化等级,其中优化等级共分为3个,优先级从1到3

cpp
//在编译生成期间对文件进行优化,优化等级为1g++ -o 可执行文件名 -O1 源文件.cpp//在编译生成期间对文件进行优化,优化等级为2g++ -o 可执行文件名 -O2 源文件.cpp//在编译生成期间对文件进行优化,优化等级为3g++ -o 可执行文件名 -O3 源文件.cpp

图16.对编译源文件进行等级为1的优化


MinGW之多个文件编译

        在显示情况中,我们的项目往往会有多个源文件,而且每一个源文件可能会分布在不同的路径下,这时我们就需要了解对多个文件进行编译以及编译指定路径下的文件,针对以上情况有以下做法:

1.针对多个文件编译,可以把文件名依次列出

cpp
//同时编译多个文件g++ -o 可执行文件名 源文件1.cpp 源文件2.cpp

图17.同时编译多个文件 

2.使用通配符*来编译多个文件(文件全部处于当前路径下)

cpp
//使用通配符*来编译多个文件(文件全部处于当前路径下)g++ -o 可执行文件名 *.cpp

图18.使用通配符同时编译多个文件 

3.分别对源文件进行编译,再对编译生成的.o文件进行链接

cpp
//对编译生成的.o文件进行链接g++ -o 可执行文件名 文件1.o 文件2.o

图19.使用对编译生成的.o文件进行链接

4.当头文件路径不同时,可指定头文件路径,生成可执行文件

cpp
//指定头文件路径,生成可执行文件g++ -I"文件路径" -o 可执行文件名 源文件.cpp 源文件2.cpp

图20.指定头文件路径编译

5.当头文件和源文件路径都不同时,也可以指定源文件路径生成可执行文件

cpp
//指定头文件和源文件路径,编译生成可执行文件g++ -I"头文件路径" -o 可执行文件名 源文件.cpp 源文件2路径

图21.指定头文件和源文件路径进行编译

6.当头文件路径不同时,也可以指定多个头文件路径进行编译

cpp
//指定多个头文件路径进行编译g++ -I"头文件1路径" -I"头文件2路径" -o 可执行文件名 源文件.cpp 源文件2.cpp

图22.指定多个头文件路径进行编译


MinGW之静态链接库编译

        静态链接库在程序运行时不会被加载到内存中,而是其内容在编译时期就已经被复制到了最终的可执行文件里,所以导致静态链接生成的可执行文件相较于动态链接库的可执行文件大。在了解静态链接库之前,先了解以下静态链接库:

1.静态链接库的命名规则为lib+文件名+.a,所以以.a结尾的文件,一般可以视为静态链接库的文件

编译静态链接库的步骤:

1.使用-c命令生成汇编文件

cpp
//使用-c命令生成汇编文件g++ -c -I"头文件路径" *.cpp

2.使用ar命令打包生成静态链接库

cpp
//使用ar命令生成静态链接库ar rcs 静态链接库名.a 汇编文件.o//ar rcs libfun.a fun.o//其中r代表替换.o文件,c代表库不存在则生成,s代表生成索引文件

图23.生成静态链接库

3.将源文件与静态链接库链接产生可执行文件

cpp
//方法1g++ 源文件.o -o 可执行文件名 静态链接库路径//方法2g++ 源文件.o -o 可执行文件名 -L静态链接库路径//方法3,其中静态链接库名为除去lib和.a的名称//例如libfun.a,其静态链接库名就为fung++ 源文件.o -o 可执行文件名 -L静态链接库路径 -l静态链接库名

图24.多种方法链接静态链接库


MinGW之动态链接库编译

        先前讲了静态链接库的操作方法,而动态链接库也是相似:

1.Windows下的动态链接库的命名规则为lib+文件名+.dll,所以以.dll结尾的文件,一般可以视为动态链接库的文件

2.Linux下的动态链接库的命名规则为lib+文件名+.so,所以Linux中以.so结尾的文件,一般可以视为动态链接库的文件

编译动态链接库的步骤:

1.使用-c命令生成汇编文件

cpp
//使用-c命令生成汇编文件g++ -c -I"头文件路径" *.cpp

2.使用-shared命令生成动态链接库

cpp
//使用-shared命令生成动态链接库g++ -o 动态链接库.dll -I"头文件路径" -fPIC -shared *.cpp

图25.生成动态链接库

3.将源文件与动态链接库链接产生可执行文件

cpp
//方法1g++ 源文件.o -o 可执行文件名 动态链接库路径//方法2g++ 源文件.o -o 可执行文件名 -L动态链接库路径//方法3,其中动态链接库名为除去lib和.dll的名称//例如libfun.dll,其静态链接库名就为fung++ 源文件.o -o 可执行文件名 -L动态链接库路径 -l动态链接库名

图26.链接动态链接库

22次原文点赞;这里的喜欢仅保存在本机
WildPointer

专注系统编程、工程实践与底层技术,记录 C++、Qt、OpenCV 与 VTK 的学习和实践。