【linux系统】基础开发工具(gcc/g++、make/Makefile)

1. 编译器gcc/g++

1.1 背景知识

  1. 预处理(进⾏宏替换/去注释/条件编译/头⽂件展开等)
  2. 编译(⽣成汇编)
  3. 汇编(⽣成机器可识别代码)
  4. 连接(⽣成可执⾏⽂件或库⽂件)

1.2 gcc编译选项

格式 gcc [选项] 要编译的⽂件 [选项] [⽬标⽂件]

1.2.1 预处理(进行宏替换) 

  • 预处理功能主要包括宏定义,⽂件包含,条件编译,去注释等。
  • 预处理指令是以#号开头的代码⾏。
  • 实例: gcc –E hello.c –o hello.i
  • 选项“-E”,该选项的作⽤是让 gcc 在预处理结束后停⽌编译过程。
  • 选项“-o”是指⽬标⽂件,“.i”⽂件为已经过预处理的C原始程序。

1.2.2 编译(生成汇编) 

  • 在这个阶段中,gcc ⾸先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的⼯作, 在检查⽆误后,gcc 把代码翻译成汇编语⾔。
  • 用户可以使⽤“-S”选项来进⾏查看,该选项只进行编译而不进行汇编,生成汇编代码。
  • 实例: gcc –S hello.i –o hello.s

1.2.3 汇编(生成机器可识别代码) 

  • 汇编阶段是把编译阶段⽣成的“.s”⽂件转成⽬标⽂件
  • 读者在此可使⽤选项“-c”就可看到汇编代码已转化为“.o”的⼆进制⽬标代码了
  • 实例: gcc –c hello.s –o hello.o

1.2.4 连接(生成可执行文件或库文件) 

  • 在成功编译之后,就进⼊了链接阶段。
  • 实例: gcc hello.o –o hello

1.3 动态链接和静态链接 

在我们的实际开发中,不可能将所有代码放在⼀个源文件中,所以会出现多个源文件,而且多个源文件之间不是独立的,而会存在多种依赖关系,如⼀个源⽂件可能要调⽤另⼀个源文件中定义的函数,但是每个源文件都是独立编译的,即每个*.c⽂件会形成⼀个*.o⽂件,为了满⾜前⾯说的依赖关系,则需要将这些源文件产⽣的目标文件进⾏链接,从而形成⼀个可以执行的程序。这个链接的过程就是静态链接。静态链接的缺点很明显:
  • 浪费空间:因为每个可执⾏程序中对所有需要的目标文件都要有⼀份副本,所以如果多个程序对同⼀个目标⽂件都有依赖,如多个程序中都调⽤了printf()函数,则这多个程序中都含有printf.o,所以同⼀个目标文件都在内存存在多个副本;
  • 更新比较困难:因为每当库函数的代码修改了,这个时候就需要重新进行编译链接形成可执行程序。但是静态链接的优点就是,在可执⾏程序中已经具备了所有执行程序所需要的任何东西,在执行的时候运行速度快。
动态链接的出现解决了静态链接中提到问题。动态链接的基本思想是把程序按照模块拆分成各个相对独立部分,在程序运行时才将它们链接在⼀起形成⼀个完整的程序,而不是像静态链接⼀样把所有程序模块都链接成⼀个单独的可执⾏⽂件。
动态链接其实远⽐静态链接要常用得多。比如我们查看下 hello 这个可执行程序依赖的动态库,会发现它就⽤到了⼀个c动态链接库:
$ ldd hello
    linux-vdso.so.1 => (0x00007fffeb1ab000)
    libc.so.6 => /lib64/libc.so.6 (0x00007ff776af5000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff776ec3000)

# ldd命令⽤于打印程序或者库⽂件所依赖的共享库列表。
在这里涉及到⼀个重要的概念: 库
  • 我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该 函数的声明,而没有定义函数的实现,那么,是在哪⾥实“printf”函数的呢?
  • 最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库⽂件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进⾏查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用

1.4 静态库和动态库

  • 静态库是指编译链接时,把库⽂件的代码全部加⼊到可执⾏⽂件中,因此⽣成的⽂件⽐较⼤,但在运行时也就不再需要库⽂件了。其后缀名⼀般为“.a”
  • 动态库与之相反,在编译链接时并没有把库⽂件的代码加⼊到可执⾏⽂件中,⽽是在程序执⾏时由运行时链接⽂件加载库,这样可以节省系统的开销。动态库⼀般后缀名为“.so”,如前⾯所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以⽣成可执行文件,如下所⽰。 gcc hello.o –o hello
  • gcc默认生成的⼆进制程序,是动态链接的,这点可以通过 file 命令验证。
📌 注意1:
  • Linux下,动态库XXX.so, 静态库XXX.a
  • Windows下,动态库XXX.dll, 静态库XXX.lib
📌 注意2:
  • 课堂这块需要举例说明,纯理论太⽣涩。 网吧/网咖的例⼦

⼀般我们的云服务器,C/C++的静态库并没有安装,可以采⽤如下方法安装

# Centos
yum install glibc-static libstdc++-static -y

#ubuntu
略

 1.5 gcc其他常⽤选项 - 了解即可

  • -E 只激活预处理,这个不⽣成⽂件,你需要把它重定向到⼀个输出⽂件⾥⾯
  • -S 编译到汇编语⾔不进⾏汇编和链接
  • -c 编译到⽬标代码
  • -o ⽂件输出到 ⽂件
  • -static 此选项对⽣成的⽂件采⽤静态链接
  • -g ⽣成调试信息。GNU 调试器可利⽤该信息。
  • -shared 此选项将尽量使⽤动态库,所以⽣成⽂件⽐较⼩,但是需要系统由动态库.
  • -O0
  • -O1 
  • -O2
  • -O3 编译器的优化选项的4个级别,-O0表⽰没有优化,-O1为缺省值,-O3优化级别最⾼
  • -w 不⽣成任何警告信息。
  • -Wall ⽣成所有警告信息。

2. 自动化构建-make/Makefile 

2.1 背景

  • 会不会写makefile,从⼀个侧面说明了⼀个人是否具备完成大型工程的能⼒
  • ⼀个⼯程中的源文件不计数,其按类型、功能、模块分别放在若干个⽬录中,makefile定义了⼀系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些⽂件需要重新编译,甚至于进行更复杂的功能操作
  • makefile带来的好处就是⸺“自动化编译”,⼀旦写好,只需要⼀个make命令,整个⼯程完全⾃动编译,极⼤的提⾼了软件开发的效率。
  • make是⼀个命令工具,是⼀个解释makefile中指令的命令工具,⼀般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可⻅,makefile 都成为了⼀种在⼯程⽅⾯的编译方法。
  • make是⼀条命令,makefile是⼀个文件,两个搭配使⽤,完成项目自动化构建。

2.2 理解 

依赖例⼦ - ⽉底要钱的例子

2.3 基本使用 

实例代码
#include <stdio.h>

int main()
{
        printf("hello Makefile!\n");
        return 0;
}

Makefile文件 

myproc:myproc.c
    gcc -o myproc myproc.c

.PHONY:clean
clean:
    rm -f myproc
依赖关系
  • 上面的文件myproc,它依赖myproc.c

依赖方法 

  • gcc -o myproc myproc.c ,就是与之对应的依赖关系

项目清理 

  • 工程是需要被清理的
  • 像clean这种,没有被第⼀个目标⽂件直接或间接关联,那么它后⾯所定义的命令将不会被自动执行,不过,我们可以显示要make执⾏。即命令⸺“make clean”,以此来清除所有的目标⽂件,以便重编译。
  • 但是⼀般我们这种clean的目标⽂件,我们将它设置为伪目标,⽤ .PHONY 修饰,伪目标的特性是,总是被执行的。
  • 可以将我们的 hello 目标文件声明成伪目标,测试⼀下。

什么叫做总是被执行?

$ stat XXX
    File: ‘XXX’
    Size: 987 Blocks: 8 IO Block: 4096 regular file

Device: fd01h/64769d Inode: 1321125 Links: 1
Access: (0664/-rw-rw-r--) Uid: ( 1000/ whb) Gid: ( 1000/ whb)
Access: 2024-10-25 17:05:30.430619002 +0800
Modify: 2024-10-25 17:05:25.940595116 +0800
Change: 2024-10-25 17:05:25.940595116 +0800

⽂件 = 内容 + 属性
Modify: 内容变更,时间更新
Change:属性变更,时间更新
Access:常指的是⽂件最近⼀次被访问的时间。在Linux的早期版本中,每当⽂件被访问时,其atime都会更新。但这种机制会导致⼤量的IO操作。具体更新原则,不做过多解释。

📌 结论:
.PHONY:让make忽略源文件和可执行目标文件的M时间对比

这篇文章介绍了linux下的基本开发工具,编译器gcc/g++、自动化构建-make/Makefile。欢迎评论交流。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值