学习笔记:编译与makefile

本文详细介绍了GCC编译器的编译过程,包括预处理、编译、汇编和链接四个阶段,以及各阶段的功能和常用参数。预处理处理宏定义、头文件和特殊符号;编译阶段将源代码翻译成汇编代码并进行优化;汇编阶段将汇编代码转换为目标文件;链接阶段将目标文件组合成可执行文件,涉及静态和动态链接。此外,还提到了动态库的管理和使用,以及Makefile的相关知识。
摘要由CSDN通过智能技术生成

概念

编译:把源代码翻译成机器语言的目标文件
链接:把众多目标文件链接成可执行文件

编译预处理

gcc -E -o test.i test.c

对伪指令(或预处理指令,以#号开头的代码行)和特殊符号进行处理

  1. 宏定义,#define
  2. 条件编译指令,#ifdef,#ifndef,#endif,#if,#else,#elif,#endif
  3. 头文件,#include,预处理将头文件的定义加入到输出文件中!!!!只有这一步需要头文件!!!
  4. 特殊符号,__FILE__,__LINE__,__DATE__,__STDC__,__TIME__

https://blog.csdn.net/kz_java/article/details/104632270
https://www.cnblogs.com/rusty/archive/2011/03/27/1996806.html

编译

gcc -S -o test.s test.c

通过词法分析和语法分析,在确认所有的指令都符合语法规则后,翻译成汇编代码。
这一步是最耗时间的。
以及相关优化
https://www.cnblogs.com/wangsens/p/7612803.html
https://blog.csdn.net/qq100440110/article/details/51289786
https://www.cnblogs.com/plus666/p/14135246.html

汇编

gcc -c -o test.o test.c

把汇编语言翻译成机器指令的目标文件

链接

gcc -o test test.o

把有关目标文件链接成可执行文件

除了将多个.o文件链接这种方式外,还有静态链接和动态链接。

  1. 静态链接
ar -rcs libtest.a test1.o test2.o test3.o
ar -t libtest.a #查看
  1. 动态链接
gcc -fpic -c -o test.o test.c
gcc -shared -o libtest.so test.o

区别:静态链接和动态链接最大区别在于链接的时机不一样,静态链接是形成在可执行程序前,而动态链接是在程序执行时。

  1. 动态库的搜索,用ldd查看动态库依赖关系(是否找不到动态库)
    3.1 将动态库放入/lib路径中
    3.2 将动态库路径加入/etc/ld.so.conf,调用命令 ldconfig 生效
    3.3 将动态库路径加入到LD_LIBRARY_PATH环境变量中

动态链接的时候,动态库加载到Memory Mapping Segment
图片地址 http://static.duartes.org/img/blogPosts/linuxFlexibleAddressSpaceLayout.png
avatar

gcc的几个参数

  1. -I,指定头文件路径
  2. -l,库名
  3. -L,库路径
  4. -Wall,提示更多警告信息
  5. -On,n=0~3编译优化,n越大优化得越多
  6. -g,包含调试信息,配合gdb使用
  7. -D xx,向程序中“动态”注册宏定义,#ifdef xx

makefile

1个规则,2个函数,3个变量

规则

目标:依赖
	命令
main: main.o
	gcc -o main main.o
main.o:main.c
	gcc -c -o main.o main.c

函数

wildcard 通配符,patsubst 替换

src = $(wildcard *.c)               #将.c文件名组成列表,赋值给src
obj = $(patsubst %.c, %.o, $(src))  #将src变量中所有后缀为.c的文件替换为.o

#特殊路径
src = $(wildcard ./src/*.c)
obj = $(patsubst ./src/%.c, ./obj/%.o, $(src))

变量

$@: 表示规则中的目标(只能出现在命令的位置上)
$<:表示第一个依赖条件(只能出现在命令的位置上)
$^:表示所有依赖条件(只能出现在命令的位置上)

all: first second third #在当前路径创建这三个文件
	@echo "\$$@ = $@"
	@echo "$$< = $<"
	@echo "$$^ = $^"
#$@ = all
#$< = first
#$^ = first second third

模式规则

%.o:%.c
	gcc -c -o $@ $<

静态模式

<targets ...>: <target-pattern>: <prereq-patterns ...>
	<commands>  
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
	$(CC) -c $(CFLAGS) $< -o $@

伪对象(伪目标)

.PHONY,防止当前目录有对应文件,导致make失败,比如当前目录存在clean文件

.PHONY: clean ALL #表示clean, ALL是伪目标

特殊符号-

表示如果执行失败, 则忽略, 继续执行之后的操作

clean:
	-rm $(obj)

=, :=, ?=, +=区别

https://www.cnblogs.com/zgq0/p/8716150.html
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值

=和:=的区别

x = foo
y = $(x) bar #xyz bar
x = xyz
x := foo
y := $(x) bar #foo bar
x := xyz

http://c.biancheng.net/view/7051.html

vpath目标文件搜索

VPATH 和 vpath 的区别:VPATH 是变量,更具体的说是环境变量,Makefile 中的一种特殊变量,使用时需要指定文件的路径;vpath 是关键字,按照模式搜索,也可以说成是选择搜索。搜索的时候不仅需要加上文件的路径,还需要加上相应限制的条件。

VPATH

VPATH := src

我们可以这样理解,把 src 的值赋值给变量 VPATH,所以在执行 make 的时候会从 src 目录下找我们需要的文件。

当存在多个路径的时候我们可以这样写:

VPATH := src car

或者是

VPATH := src:car

使用 VPATH 的情况是前路径下的文件较少,或者是搜索的文件不能使用通配符表示,比如执行文件在bin目录下,这些情况下使用VPATH最好。

.SUFFIXES

# .
# ├── include
# │   ├── add.h
# │   └── sub.h
# ├── main
# ├── Makefile
# ├── obj
# │   ├── add.o
# │   ├── main.o
# │   └── sub.o
# └── src
#     ├── add.c
#     ├── main.c
#     └── sub.c

CFLAGS := -O -Wall
INC    := -I ./include
LIBS   :=  

BIN    := main
#SRC    := $(wildcard ./src/*.c)
SRC    := main.c add.c sub.c
ODIR   := obj
OBJS   := $(patsubst %.c, $(ODIR)/%.o, $(SRC))

CC     := gcc

all: $(BIN)

$(BIN): $(OBJS) 
	$(CC) -o $@ $^ $(LIBS)


$(OBJS): $(ODIR)

$(ODIR):
	@mkdir -p $@

$(ODIR)/%.o:%.c
#$(OBJS): ./obj/%.o : %.c
	$(CC) -c $(CFLAGS) -o $@ $< $(INC)

clean:
	-rm $(OBJS) $(BIN)

.PHONY: all clean 

#.SUFFIXES

vpath %.c  src
vpath %.h  include
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值