一、gcc/g++
gcc/g++是编译器,gcc是GCC(GUN Compiler Collection,GUN编译器集合)中的C编译器;g++是GCC中的C++编译器。使用g++编译文件时会自动链接STL标准库,而gcc不会自动链接STL标准库。下面简单介绍一下Linux环境下(Windows差别不大),程序翻译的过程:
1.1 预处理(头文件展开,条件编译,宏替换,去注释等)
gcc -E filename.c -o filename.o
其中, -E
从现在开始进行程序的翻译,预处理做完,就停下来。
1.2 编译(C/C++语言 --> 汇编语言)
gcc -S filename.c
//默认生成filename.s文件
gcc -S filename.c -o filename.s
//亦可以
gcc -S filename.i
gcc -S filename.i -o filename.s
其中,参数 -S
从现在开始进行程序的翻译,当编译做完,就停下来。下图为程序预处理、编译过程中形成的目标文件test.i与test.s。
1.3 汇编(汇编 --> 可重定位目标二进制文件,不可以被执行的,bin.obj)
简单来说,汇编的具体功能,就是把我们自己的代码进行翻译形成二进制目标文件。
gcc -c filename.s
gcc -c filename.s -o filename.o
其中, -c
从现在开始进行程序的翻译,当汇编做完就停下来。
1.4 链接(将我们自己形成的.obj文件和库文件某种合并,形成可执行程序)
gcc filename.o -o filename//可自定义输出的文件名
gcc -o filename filename.o//亦可以
其中,-o
后面是指定生成的可执行程序的名称。
二、链接
指令ldd
能够检测当前被形成的可执行程序都依赖哪些库:
ldd 可执行程序名
为什么我们能够在Linux下进行C/C++代码的编写和编译?这是因为Linux系统默认已经携带了语言级别的头文件和语言对应的库。centos中,头文件一般在/usr/include/路径下:
此外,库本质上也是文件,其分为两种:静态库和动态库;
静态库:lib开头+库名+.a结尾;
例如libXXXXXXX.a
动态库:lib开头+库名+.so结尾;
例如libXXXXXXX.so
为了更直观地讲述静态/动态库名,进行了ldd指令检测当前可执行程序使用的依赖库,下图中,m-2.17为动态库名。Linux的指令相当一部分是用C语言编写的,因而指令就是程序、工具。
动静态库的小结:
库分为静态库(专门让编译器,对用户的程序进行静态链接的)和动态库(专门让编译器,对用户的程序进行动态链接的);
静态库和静态链接:链接的时候,如果是静态链接,找到静态库,拷贝静态库中的我们所需要的代码到自己的可执行程序中;
动态库和动态链接:链接的时候,如果是动态链接,找到动态库,拷贝动态库中我们所需要的代码的地址到自己的可执行程序中相关的位置;
静态链接成功:我们的程序,不依赖任何库,自己就可以独立运行;
动态链接成功:我们的程序,还是依赖动态库,一旦动态库缺失,我们的程序便无法运行;
静态库,因为自身拷贝的问题,比较浪费空间;
动态库,亦是共享库,因为可以做到被大家共享方法,所以真正的实现永远都在库中,程序内部只有地址,比较节省空间;
注意:Linux默认使用的是动态链接和动态库。
上图中,通过file test.cpp
可以确认test.cpp是一个C++代码,亦是一个文本类文件;file mytest
,ELF可执行程序,64-bit LSB executable表示64位的可执行程序,dynamically linked动态共享连接。
上图中,在使用静态库编译test.cpp时,出现了无法找到静态库的故障,这是因为Linux系统中,默认没有安装静态库,需要用户自行安装。C++静态库的安装指令:
sudo yum install glibc-static libstdc++-static -y
下图中,使用动态库生成的可执行程序myfile占用9064bit,使用静态库生成的可执行程序myfile-static明显比动态库生成的可执行程序占用空间大得多。
使用file
指令能够直接看出可执行程序myfile-static使用了静态库进行程序的链接。
三、自动化构建工具make/Makefile
在Linux中编写一个程序,每次编译时都需要一行一行地敲命令,对于小程序还好,而对大型程序就不是很友好,不但浪费时间还会输入命令错误。面对这些情况,Linux提供了make
命令和makefile文件来解决这类问题。make是一个命令,makefile是一个文件且其位于当前源代码路径下。
3.1 案例
在test_03_02目录下,创建myfile.cc的C++文件,以及Makefile文件:
下图为Makefile文件中的内容,其中myfile是形成可执行程序的目标文件,它需要依赖myfile.c文件。
make命令,自动在当前路径下查找Makefile
文件,执行文件中内置好的命令。
3.2 规则
makefile是一个围绕依赖关系和依赖方法构建的一个自动化编译的工具,包含了依赖关系和依赖方法:
注意:依赖关系中,目标文件对应的依赖文件列表可以空
直接使用make命令进行自动化编译,生成了myfile.i、myfile.s、myfile.o和myfile这四个文件。
文件有生成必然就有清理,make依然提供清理的能力:
使用了make指令后,继续使用make编译时却不被允许,而make clean却可以多次执行,这是因为清理使用了.PHONY
进行了欺骗,make的过程也可以。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yN2GfUxa-1677849319595)(https://gitee.com/joes_ju/personal_images/raw/master/img/202303031530148.png)]
.PHONY:目标文件
//总是被执行的
导致使用make命令后不能继续使用make命令,是由于源代码文件myfile.cc的修改时间早于目标文件myfile的修改时间,因此myfile比myfile.cc新,不需要再执行编译。
对于这种现象,除了使用.PHONY
欺骗外,亦可通过touch一个已经存在的文件,其作用是更新该文件的修改时间: