Linux开发工具

1.Linux编译器-gcc/g++使用

1、背景知识

  1. 预处理(进行宏替换...)
  2. 编译(生成汇编)
  3. 汇编(生成机器可识别代码)
  4. 链接(生成可执行文件或库文件)

我们为什么能在Windows/Linux上进行C/C++/其他形式开发,我们系统中一定要提前或后续安装C/C++开发相关的头文件和库文件。C/C++开发环境不仅仅指的是vs,gcc,g++,更重要的是语言本身的头文件和库文件。安装vs等时,在安装的时候,选择对应的开发包时,同步也在下载C/C++的头文件和库文件。

2、gcc如何完成

格式:gcc 选项 要编译的文件 选项 目标文件

预处理(进行宏替换)

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

编译(生成汇编)

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

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

  • 汇编阶段是将编译阶段生成".s"文件转成目标文件
  • 可以使用"-c"看到汇编代码转化成".o"的二进制目标代码
  • 实例:gcc -c hello.i -o hello.o,hello.o可重定位目标二进制文件,简称目标文件,.obj文件,不可以独立运行,虽然已经是二进制了,需要经过链接(链接库)才能执行

链接(生成可执行文件或者库文件)

  • 在成功编译之后就进入了链接阶段
  • 实例:gcc hello.o -o hello,将可重定位目标二进制文件,和库进行链接形成可执行程序

在这里涉及到一个重要的概念:函数库

  • 我们的C程序中,并没有定义"printf"的函数实现,且在预编译中包含的"stdio.h"中也只有该函数的声明,而没有定义函数的实现,那么是在哪里实现printf函数的?
  • 答案是:系统把这些函数实现都做到了名为libc.so.6的库文件中去了,在没有特别指定时,gcc回到系统默认的搜索路径"user/lib"下进行查找,也就是链接到libc.soo.6库函数中去,这样就能实现函数"printf"了,而这也就是链接的作用。

函数库一般分为静态库和动态库两种

  • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不需要库文件了。其后缀名一般为".a"
  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样就可以节省系统的开销。动态库一般后缀名为".so",如前面所述的libc.so.6就是动态库。gcc在编译时默认使用动态库。完成了链接之后,gcc就可以生成可执行文件,如下:gcc hello.o -o hello
  • gcc默认生成的二进制程序,是动态链接的,这点可以通过file命令验证

ldd命令是Linux系统中用于显示一个可执行文件或共享库所依赖的共享库(动态链接库)以及这些库的实际加载路径的工具。
Linux中,编译形成可执行程序,默认采用的就是动态链接--提供动态库

Linux中,如果要按照静态链接的方式,进行形成可执行程序,需要添加-static选项--提供静态库

动态库不能缺失,一旦对应的动态库缺失,影响的不知一个程序,可能导致很多程序都无法正常运行!

动VS静

优点:

  • 动态库因为是共享库,有效的节省资源(磁盘空间,内存空间,网络空间等)
  • 静态库不依赖库,程序可以独立运行

缺点:

  • 动态库一旦缺失,导致整个程序都无法运行
  • 体积大,比较消耗资源

gcc选项

  • -E 只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件中
  • -S 编译到汇编语言不进行汇编和链接
  • -c 编译到目标代码
  • -o 输出到可执行文件
  • -static 对生成的文件采用静态链接
  • -g 生成调试信息,GNU调试器可利用该信息
  • -shared 此选项将尽量使用动态库,所以生成的文件比较小,但是需要系统有动态库
  • -O0
  • -O1
  • -O2
  • -O3 编译器的优化选项的四个级别,-O0表示没有优化,-O1为缺省值,-O3级别最高
  • -w 不生成任何警告信息
  • -Wall 生成所有警告信息

2.Linux调试器-gdb使用

1、背景

  • 程序发布的方式有两种,debug模式和release模式
  • Linux gcc/g++出来的二进制程序,默认是release模式
  • 要使用gdb调试,必须在源代码生成二进制程序的时候,加上-g选项

2、使用

gdb binFill

退出:ctrl+d / quit

调试命令:

  • list / l 行号:显示源代码,接着上次的位置往下列,每次列10行
  • list / l 函数名:列出某个函数的源代码
  • r / run:运行程序
  • break(b) 行号:在某一行设置断点:
  • n / next:单条执行(逐过程进行):
  • s / step:进入函数调用(逐语句进行):
  • break 函数名:在某个函数开头设置断点
  • info break(b):查看断点信息
    1.Num:断点编号。
    2.Type:断点类型(普通断点)。
    3.Disp:断点处置方式(keep 表示断点会一直保留,即使程序重新启动)。
    4.Enb:是否启用(y 表示启用)。
    5.Address:断点对应的内存地址。
    6.What:断点的具体位置。
  • finish:执行到当前函数返回,然后停下来等待命令(可以查看问题出现在哪个函数)
  • print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数
  • set var:修改变量的值,快速到达某次循环
  • continue(c):从当前位置开始连续而非单步执行(直接到下一个断点)
  • run(r):从开始连续而非单步执行
  • delete breakpoints:删除所有断点
  • delete breakpoint n:删除序号为n的断点
  • disable breakpoints:禁用断点
  • enable breakpoint:启动断点
  • info breakpoints(i b):查看当前设置了哪些断点
  • display 变量名:跟踪查看一个变量,每次停下来都显示它的值
  • undisplay:取消对先前设置的哪些变量的跟踪
  • until x行号:跳至x行(可以跳出循环)
  • breaktrace(bt):查看各级函数调用及参数
  • info(i) locals:查看当前栈帧局部变量的值
  • quit(q):退出gdb

3.Linux项目自动化构建工具-make/makefile

1、背景

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

2、实例

依赖关系

  • 上面的文件hello,它依赖hello.o
  • hello.o,它依赖hello.s
  • hello.s,它依赖hello.i
  • hello.i,它依赖hello.c

依赖方法

  • gcc hello.* -option hello.*,就是与之对应的依赖关系

3、原理

  • make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么,
    1. make会在当前目录下找名字叫"Makefile"或"makefile"的文件。
      2.对于不生成实际文件的目标(如 allclean),使用 .PHONY 明确声明。all 是伪目标,不生成实际文件,它的作用是触发 hello 的构建。 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到"hello"这个文件,
      并把这个文件作为最终的目标文件。
      3.如果hello文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成hello这个文件。
    2. 如果hello所依赖的hello.o文件不存在,那么make会在当前文件中找目标为hello.o文件的依赖性,如果找到则再根据那一个规则生成hello.o文件。(这有点像一个堆栈的过程)
    3. 当然,你的C文件和H文件是存在的啦,于是make会生成 hello.o 文件,然后再用 hello.o 文件声明make的终极任务,也就是执行文件hello了。
    4. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
    5. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
    6. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。
  • makefile 的核心:目标、依赖、命令。

不改变代码,只可以make一次

  • 因为提供编译效率
  • 怎么做到:一定是源文件形成可执行文件,先有源文件,才有可执行文件,一般而言,源文件的最近修改时间是比可执行文件要老的。
    如果我们更改了源文件,历史上曾经还有可执行文件,那么源文件的最近修改时间一定比可执行程序要新!
    只需要比较可执行程序的最近修改时间 和 源文件的最近可修改时间:
    .exe 新于 .c 源文件是老的,不需要重新编译
    .exe 老于 .c 源文件是新的,需要重新编译

4、项目清理

  • 像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令------"make clean",以此来清除所有的目标文件,以便重编译。
  • 但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。
相关推荐
.YYY1 小时前
Linux--普通文件的管理
linux
程序猿本员1 小时前
Linux多进程
linux·后端
小麦嵌入式1 小时前
Linux驱动开发实战(五):Qt应用程序点RGB灯(保姆级快速入门!)
linux·驱动开发·stm32·嵌入式硬件·mcu·qt·ubuntu
郭顺发_2 小时前
使用GitHub Actions实现Git推送自动部署到服务器
服务器·git·github
钡铼技术物联网关2 小时前
支持Linux、鸿蒙的工业AIOT智能终端在钢铁厂的应用
linux·arm开发·边缘计算
是花花呢2 小时前
华为hcia——Datacom实验指南——以太网帧和IPV4数据包格式(一)
运维·网络·数据库·安全·web安全·华为·华为hcia——datacom
不被定义的~wolf2 小时前
【Linux系统编程】管道
linux·服务器
西北大程序猿3 小时前
文件系统 linux ─── 第19课
linux·运维·服务器
GKDf1sh3 小时前
通过qemu仿真树莓派系统调试IoT固件和程序
linux·网络·物联网·qemu
一匹电信狗3 小时前
浅谈Linux中的Shell及其原理
linux·服务器·c语言·开发语言·c++·ssh·unix