Gcc

Gcc

程序编译过程

1. 预处理
在这一阶段,源码中所有的预处理语句得到处理,例如
#include语句所包含的文件内容替换掉语句本身
所有已定义的宏被展开
根据#ifdef #if等语句的条件是否成立取舍相应部分
gcc预处理阶段可以生成.i文件,
通过选项-E可以使编辑器在预处理结束时停止编译。例如:
gcc -E -o  hello.i  hello.c
2. 编译
在这一阶段,编译器对源码进行语法分析,优化等操作,最后生成汇编代码。
这是整个过程中最重要的一部。
可以通过选项-S使GCC在进行完编译后停止,生成.s的汇编程序。例如:
gcc -S -o hello.s hello.c   
3. 汇编
这一阶段使用汇编器对汇编代码进行处理,生成机器语言代码,保存为后缀为.o的目标文件中。
当程序由多个代码文件构成时,每个文件都要进行汇编工作,生成.o目标文件后,才能进行下一步链接工作。
目标文件已经是最终程序的某一部分了,只是在链接之前还不能执行。可以通过-c选项生成目标文件:
gcc -c -o hello.o hello.c    
4. 链接
经过汇编后的机器码不能直接运行,为使操作系统能正确加载可执行文件,
文件中必须包含固定格式的信息头。
还必须与系统提供的启动代码链接起来才能正常运行,这些工作都由链接器来完成。
gcc -o hello hello.c   

在这里插入图片描述

Gcc基本用法

	1. gcc [-Wall] [-O1..3] [-o name] file [-D 预先定义的变量][-L 目录][-lname][-fpic][-static/shared]
	-Wall:打开所有警告项
	-O 设置优化级别, O0表示关闭优化功能
	-g 将调试信息编译到目标文件中
	-o name:指定输出文件的名字是name
	file:被编译(链接)的文件。
	[-lname]:链接到libname.a或者libname.so
	[-fpic] : 生成相对
	2. 静态库
	gcc -c add.c    //编译 add.c 源文件生成 add.o 目标文件
	ar  crsv  libadd.a  add.o  //对目标文件*.o 进行归档, 生成 lib*.a,
	此处 lib 必须要写的
	然后就是在编译其他文件时,链接静态库。
	gcc  -o mian  main.c  -L./  –ladd –I./
	//不要忘记-L 后面的那个. (即在库文件的搜索路径中添加当前路径 -ladd 表示链接库文件 libadd.a/.so     
	-I./表示包含在当前目录中的头文件)
	3. 动态库
	gcc -fPIC -Wall -c add.c
	gcc -shared -o libadd.so add.o
	最后编译链接动态库: gcc -o main main.c -L. –ladd
	在运行 main 前, 需要注册动态库的路径。常采用的方法有:
	cp  libadd.so  /lib   //通常采用的方法, cp  lib*.so /lib  将其copy到系统的/lib文件夹下
	创建动态链接库之后, 以后就可以使用该动态链接库了
	例如在 test.c 里面调用了原来库中的函数, 则执行 gcc  test.c –o test    –ladd 就可以了。较方便

Gcc2

	# 中间插入一段关于gcc 的前戏
	gcc –E –o main.i mian.c    # -E是预处理展开宏,生成详细c文件, -o是输出
	gcc –S –o main.s main.i    # -S 是编译阶段, 将c文件生成汇编语言
	gcc –c –o main.o main.s    # -c 是汇编阶段, 生成机器码
	gcc –o main.exe main.o     # 链接阶段, -o 生成目标执行程序
	
	gcc –g      # 编译中加入调试信息, 方便gdb调试, 还有-ggdb3 支持宏调试等
	gcc –Wall    # 输出所有警告信息
	gcc –O2        # 开启调优, O2等级调优
	
	gcc –I(i大写)            # 导入头文件目录,方便 *.h文件查找
	gcc –L(l 大写)          # 导入库文件目录,方便 *.so和*.a文件查找
	gcc –l(l 小写)           # 导入库文件, 例如-lpthread, 相当于依次查找导入 libpthread.so/libpthread.a 文件
	gcc –static –l(l 小写)   # 指定只查找 静态库 lib*.a 文件, linux约定库文件都是 lib开头
	
	
	ar rc libheoo.a hello.o world.o                    # 将*.o 文件打包成 libheoo.a 静态库
	gcc –fPIC –shared –o libheoo.so hello.o world.o    # 将*.o 文件打包成 libheoo.so 动态库

Makefile1

	make和makefile
	一个软件中通常包含很多文件,每次都进行编译会很麻烦而且效率低下。
	在Windows平台上的VC、VB都有工程概念,一旦建立一个工程,这些开发平台会自动地维护其中的各种文件,从而高效编译。
	在Linux中,使用make完成这一功能。
	1. makefile文件说明
	使用make工具,首先要编写makefile文件,一个makefile文件包含5个方面:
	- 具体规则  
	- 隐含规则 
	- 定义变量    
	- 指令   
	- 注释 
	2. makefile的规则:
	诸如Autoconf和Automake的工具可以自动生成makefile文件。
	makefile的内容核心是一系列的规则。规则的基本格式是:
	target:dependency(tab字符)command
	- target(目标):通常是要产生的文件的名称
	- dependency(依赖):指用来输入从而产生目标的文件。
	- command(命令):是make执行的动作,一个规则可以有多条命令,每个命令一行。命令行首字符是TAB
	3. makefile的实例:
	objects = main.o mouse.o command.o display.o
	CC = gcc
	CFLAGS = -Wall -O2 -g               //相当于C中定义变量
	game : $(objects)                         //定义game生成规则
    $(CC) -o edit $(objects)   
	main.o : defs.h                             //定义main.o生成规则,包含隐含规则
	mouse.o : defs.h command.h
	command.o : defs.h command.h
	display.o : defs.h buffer.h
	.PHONY : clean
	clean :                                          //定义clean的规则,无依赖
      $(RM) edit $(objects)  

	game的生成规则包含了规则的三个基本要素:
	目标、依赖、命令;
	main.o等规则没有命令,属于隐含规则(implicit rule)。
	clean规则没有依赖,不属于编译的内容,只是完成一个指定的动作。      

	隐含规则能够告诉make使用传统的标准方法完成任务。
	例如,生成一个目标文件的方法是使用C编译器编译C语言源程序,
	这个步骤所用到的命令基本都是相同的。
	使用隐含规则就无须详细指定这些命令,
	而make能按照文件名的后缀的变化,决定所采用的规则。 

在这里插入图片描述

变量是makefile中定义的名字,用来代替一个文本中的字符串 ,该文本字符串称为该变量的值。
Makefile中常见预定义变量有:
(a)CC  默认值cc(gcc)是C编译器的名称。
(b)CPP 默认是$(CC) -E 是C与预编译器的名称。
(c)CXX默认值是g++,是C++编译器的名称、
(d)RM 默认值 rm -f 是删除程序的名称。
(f)$@ 用在生成规则中,表示当前目标。
(g)$< 用在生成规则中,表示当前目标的第一个依赖目标。
(h)$^ 用在生成规则中,表示当前目标的所有依赖目标。
 使用变量的方式:$(变量名)变量名只是字符时,()可省略
 常用的变量赋值操作:
	:= 直接赋值,信值覆盖原来的值。
	?= 条件赋值,如果原来无值则赋值。否则保持原来的值。
	+= 加法赋值,新值附加在原来值后面。
	= 递归赋值,如果右侧包含其他变量,当这些变量的值变化时,被赋值变量的值也变化。

make 工具的基本用法如下:
make [-C dir] [-f file] [target]
-C dir:执行时进入dir目录,默认当前目录
-f file:使用file作为makefile
target:要完成的目标,目标在makefile中定义,默认是定义的第一个目标。

Makefile2

target: dependency_files //目标项:依赖项
< TAB >command           //必须以 tab 开头, command为编译命令
编写好Makefile之后,就可以直接使用  make 编译了。
若写了clean,可make clean 清理,重新编译。
如下:

在这里插入图片描述

特殊处理与伪目标:
		.PHONY 是 Makefile 文件的关键字, 表示它后面列表中的目标均为伪目标。
		伪目标通常用在清理文件、 强制重新编译等情况下。
		eg:      
		.PHONY:clean
		clean:
     		rm main  main.o

变量、 函数与规则
	通过make支持的变量定义、规则和内置函数,
	可以写出通用性较强的makefile文件,
	使得同一个makefile文件能够适应不能的项目是重要的。
变量: 用来代替一个文本字符串
    变量名:=变量值     简单变量展开(类似于 C++的赋值)   //通常采用这种形式
	使用变量的一般方法: 
	$(变量名)=??? 赋值        
	???=$(变量名) 引用
	例如:--

在这里插入图片描述

	变量分为:
 	- 用户自定义变量, 
 	- 预定义变量( CFLAGS), 
 	- 自动变量, 
 	- 环境变量
	自动变量: 指在使用的时候, 自动用特定的值替换。
	常见的有: 
	$@ 当前规则的目标文件(重点) 
    $^ 当前规则的所有依赖文件, 以空格分隔(重点)
	eg:用自动变量      CFLAGS:= -Wall -O2 –fpic

	预定义变量: 
	内部事先定义好的变量, 但是它的值是固定的, 并且有些的值是为空的。
	AR: 库文件打包程序默认为 ar             
	CC: c编译器默认为 cc
	CPP: c预编译器, 默认为$(CC) –E        
	CFLAGS: c编译器选项, 无默认
	CXXFLAGS: c++编译器选项

在这里插入图片描述

	规则分为: 
	- 普通规则, 
	- 隐含规则, 
	- 模式规则
	
	隐含规则:  
	*.o 文件自动依赖*.c 或*.cc 文件, 所以可以省略main.o:main.cpp 等

	模式规则: 
	通过匹配模式找字符串, 
	%匹配 1 或多个任意字符串    
	%.o: %.cpp 任何目标文件的依赖文件是与目标文件同名的并且扩展名为.cpp 的文件
	
	函数:
	1. wildcard 搜索当前目录下的文件名, 展开成一列所有符合由其参数描述的文件名,文件间以空格间隔。 	
	SOURCES = $(wildcard *.cpp)把当前目录下所有'.cpp'文件存入变量 SOURCES 里。
	2. 字符串替换函数:(patsubst 要查找的子串,替换后的目标子串, 源字符串)。
	将源字符串(以空格分隔)中的所有要查找的子串替换成目标子串。 如
	OBJS = $(patsubst %.cpp,%.o,$(SOURCES))   可以和上一步对应起来看。即把 SOURCES 中'.cpp' 替换为'.o'3. (addprefix 前缀, 源字符串)函数把第二个参数列表的每一项前缀加上第一个参数值

	Makefile举例:
	SOURCES:=$(wildcard *.c)
	OBJS:=$(patsubst %.c,%.o,$(SOURCES))
	ELF:=main
	CC:=gcc
	CFLAGS:=-g -Wall
	$(ELF):$(OBJS)
        gcc $^ -o $@
	.PHONY:clean
	clean:
        rm $(OBJS) $(ELF)

Makefile3

GDB

GDB是GNU的调试工具,它可以跟踪被调试的程序,进行设置断点、单步执行等操作。当程序暂停执行时,可以使用命令查看程序中的变量值、CPU的寄存器值、内存的值以及函数调用栈等信息。    
被调试的应用程序在编译时最好使用-g参数将调试信息编入目标文件中:
gcc -g app.c -o app
用以下命令启动对程序app的调试:
gdb app
如果程序app运行时需要参数,则用以下命令:
gdb --args app arg1 arg2  // arg1和arg2被视为app的参数,而不是gdb的参数   
启动后进入GDB交互界面,可以输入GDB的命令进行调试,常用命令如下(回车是重复上一条命令):

在这里插入图片描述

GDB2

gdb 常用命令
首先程序编译时加 -g 选项才可打开调试选项 
eg:
gcc –o filename –Wall filename.c –g //进入调试
gdb filename //进入调试
l    //显示代码 (list)
b  4    //在第四行设置断点 相当于 Windows 的 F9 (break)           
//若为 b  main  则表示断点打在main处
r    //运行   相当于 Windows 的 F5 (run)
n //下一步不进入函数 相当于 Windows 的 F10  (next)
s //表示单步进入函数, 相当于 Windows 的 F11 (step)
p  I  //打印变量 I 相当于 Windows 的 Watch 窗口(print)
c     //运行到最后(continue)
q     //退出 相当于 Windows 的   Shift+F5 (quit)

在这里插入图片描述

参考

1. https://blog.csdn.net/iotflh/article/details/86499259
2. https://blog.csdn.net/smilejiasmile/article/details/74946733
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

raindayinrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值