Linux编译器-gcc/g++使用
1.设计样例
c语言:linux中用的std=c99版本--可能会出现其他问题
c++:Linux中用的std=c++11--使用c++11版本
Linux没有文件格式的区分,但是编译器区分
gcc编译器的文件格式是filename.c
g++编译器的文件格式是filename.cc或者filename.cpp
gcc完成格式
格式 gcc [选项] 要编译的文件 [选项] [目标文件]
gcc test.c -o my.exe -std=c99
或者
gcc -o my.exe test.c -std=c99
都可以打印出结果
查看g++版本属性
g++ -v或者g++ -version
g++的安装
安装的时候一定要以root的身份进行yum安装,普通用户则无法安装
安装的指令如下,普通用户下,不能用sudo命令的可以看我之前的博客
sudo yum install -y gcc-c++
2.程序的翻译过程
在c语言中,我们曾经说过,c语言的编译过程就分为四个过程
1.预处理
2.编译
3.汇编
4.链接
通常我们在编译c语言程序中,是会一步到位的编译出代码的结果,而在4个阶段不会停止,而现在可以将每一步停止,从而看到每一步的作用
预处理
预处理的作用:宏替换,去注释,头文件的展开,以及条件编译
gcc命令:
gcc -E test.c -o test.i
从现在开始程序的翻译,预处理完成就停下
去注释:
查看头文件的命令:
vim /usr/include/stdio.h
用来查看预处理是否是头文件的展开
条件编译:
如果编译成果第一个条件V1,则不会去进行编译下面的程序
编译
编译的作用:将c语言翻译成汇编语言
gcc命令:
gcc -S test.i -o test.s
从现在开始程序的编译,编译完成就停下
得到汇编语言:
汇编
汇编的作用:将汇编语言翻译成二进制语言
gcc命令:
gcc -c test.s -o my.exe
从现在开始程序的编译,汇编完成就停下
得到二进制文件:
链接
gcc命令:
gcc -o test.o -o test.c
1.链接是什么?
我们的程序需要与库结合,而语言是一定要具有自己的库的
2.为什么?
a.让开发站在巨人的肩膀上
b.提高开发效率
3.怎么办?
Linux中
动态库:.so 与动态库链接就是动态链接
静态库:.a 与静态库链接就是静态链接
ldd 可执行文件:可以查看所连接可库
由此可以看到时运用的时动态链接
在这里涉及到一个重要的概念:函数库
我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到
系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函
数“printf”了,而这也就是链接的作用
函数库一般分为静态库和动态库两种
静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a”
动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。gcc hello.o –o hello
gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证
注意:
c静态库时默认生成的
gcc默认生成的可执行程序,是默认采用动态链接
动态库和动态链接的优缺点:
1.不能丢失
2.节省资源
每一次程序编译时,都要与动态库链接
查看动态库版本属性
ls /lib64/lib.so.6 -l
静态库和静态库链接的优缺点:
1.一旦形成,与库无关
2.浪费资源
静态链接时将静态库拷贝到文件中去,占的内存较大
查看静态库版本属性
ls /lib64/libc.a -l
默认情况下,linux中是没有静态库的
动静态链接比较
动态链接会比静态链接产生文件会小很多,也更加节省资源
Linux项目自动化构建工具-make/Makefile
1.背景
个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率
make是一个命令工具,是一个解释makefile中指令的命令工具
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建
2.原理
makefile(Makefile)是和源代码同目录下的文件
如下,是一个makefile文件中的内容
、
mytest:目标文件 会默认形成第一个目标文件
test.c:依赖文件列表,可以多写文件,空格隔开,test1.c test2.c test3.c ...
gcc test.c -o mytest -std=c99:是依赖方法
.PJONY xxx:对应的方法总是要被执行的,如果没有.PHONY,此方法执行过一此后,若文件内容没有修改,则不会再次执行
a.为什么makefile对最新的可执行程序,默认不重新生成 ?
为了提高编译的效率
b.怎么做到的?
对比,可执行文件修改的时间和源文件最近修改的时间,如果可执行文件修改时间早于源文件,则重新生成,反之,则不生成。
3.我们自己的makefile
看一个新版的makefile
$:表示扩展打开中定义的变量
$@:表示包含的目标文件
$^:表示所有包含的依赖列表
makefile定义变量时,等号两边不能带空格
$@=mytest,$^=test.c
那要怎么隐藏我们所make命令后总是会出现的依赖方法
@依赖方法:可以隐藏打印过程
touch 文件名:是刷新文件,来让make可以重新编译
4.用程序运行的过程来用makefile运行
由上可以看出,我们写出的makefile文件和程序的运行过程是反过来的,依旧可以运行,原先运行时,只是默认运行第一个列表的依赖方法,但是这个make命令后却运行出来全部的命令。
原因:
目标文件需要依赖文件列表来实现,但是如上代码和程序运行顺序可知,要运行可执行程序my.exe需要test.o文件,之后再会向下查找有无文件,test.o文件也需要test.s文件,再向下查找,test.s文件也需要test.i文件,再向下查找,test.i文件需要test.c文件,找到test.c文件之后再逐层向上运行依赖方法,依次得到test.i,test.s,test.o,my.exe.