文章目录
1.GCC常见命令
1.1 查看gcc版本号
Target: x86_64-linux-gnu :说明只能编译在X86架构上运行的程序
1.2 GCC输出目标文件
编译生成目标文件及错误提示
1.3 编译流程
GCC编译器的编译流程是:预处理、编译 、汇编和链接。预处理 就是展开所有的头文件、
替换程序中的宏、解析条件编译并添加到文件中。编译是将经过预编译处理的代码编译成汇编
代码,也就是我们常说的程序编译。汇编就是将汇编语言文件编译成二进制目标文件。链接就
是将汇编出来的多个二进制目标文件链接在一起,形成最终的可执行文件,链接的时候还会涉
及到静态库和动态库等问题。
引用自:《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6》
2.Makefile基础
2.1 编译多个文件
引入问题:如果项目有很多文件,一次编译时间非常长,如何之编译修改后的文件?
2.2 单独编译各个文件,最后链接
-c 命令为只编译不链接, 假如只修改了某个文件,只对该文件进行编译,最有再一起链接即可
问题:加入不记得自己修改了哪个文件该如何处理?
2.3 Makefile基础
上述代码中一共有5条规则,1、2行为第一条规则,3、4行为第二条规则,5~6行为第三条
规则,,7、8行为第四条规则,10~12为第五条规则,make命令在执行这个Makefile的时候其执
行步骤如下:
首先更新第一条规则中的main,第一条规则的目标成为默认目标,只要默认目标更新了那
么就认为Makefile的工作。在第一次编译的时候由于main还不存在,因此第一条规则会执行,
第一条规则依赖于文件main.o、input.o和calcu.o这个三个.o文件,这三个.o文件目前还都没
有,因此必须先更新这三个文件。make会查找以这三个.o文件为目标的规则并执行。以main.o为例,发现更新main.o的是第二条规则,因此会执行第二条规则,第二条规则里面的命令为“gcc–cmain.c”,这行命令很熟悉了吧,就是不链接编译main.c,生成main.o,其它两个.o文件同理。
最后一个规则目标是clean,它没有依赖文件,因此会默认为依赖文件都是最新的,所以其对应
的命令不会执行,当我们想要执行clean的话可以直接使用命令“makeclean”,执行以后就会删
命令列表中的每条命令必须以TAB键开始,不能使用空格!
引用自:《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6》
2.4 引入其他变量
常用自动化变量
3.Linux驱动中实际用到的Makefile文件
3.1 汇编驱动LED灯实验
led.bin:led.s
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
arm-linux-gnueabihf-objdump -D led.elf > led.dis
clean:
rm -rf *.o led.bin led.elf led.dis
-
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
-g产生调试信息
-c编译源文件不链接
-o指定编译产生的文件名
用到交叉编译器为arm-linux-gnueabihf-gcc -
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
arm-linux-gnueabihf-ld 用来将众多的.o 文件链接到一个指定的链接位置 -
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
“-O”选项指定以什么格式输出 binary为二进制 “-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息 -
arm-linux-gnueabihf-objdump -D led.elf > led.dis
上述代码中的“-D”选项表示反汇编所有的段
3.2 C语言驱动LED灯实验
- 第4行
arm-linux-gnueabihf-ld -Timx6ul.lds -o ledc.elf $^ 相当于arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf start.o main.o , ”S“”的意思是所有依赖文件的集合
- 第5行
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf @ 相 当 于 r m − l i n u x − g n u e a b i h f − o b j c o p y − O b i n a r y − S l e d c . e l f l e d c . b i n , " @ 相当于rm-linux-gnueabihf-objcopy -O binary -S ledc.elf ledc.bin," @相当于rm−linux−gnueabihf−objcopy−Obinary−Sledc.elfledc.bin,"@"的意思是所有目标文件集合
- 第8、9行
%.o:%.s #模式规则
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o $@ $< 相当于rm-linux-gnueabihf-gcc -Wall -nostdlib -c -O2 -o start.o start.s
3.3 官方SDK移植实验
- Makefile中赋值规则
3.4 bsp工程管理实验
Makefile指定头文件路径,需要-I。我们编译源码的时候需要指定头文件路径。比如
bsp/clk/bsp_clk.h 变为-I bsp/clk/bsp_clk.h
通过一堆的变量,将要编译的原材料准备好了。
Makefile静态模式
<targets …>: : <prereq-patterns …>
$(OBJS): obj/%.o : %.S 表示将所有的.S文件编译为.o并且存放到obj目录下去
CROSS_COMPILE ?= arm-linux-gnueabihf-
TARGET ?= bsp
CC := $(CROSS_COMPILE)gcc
LD := $(CROSS_COMPILE)ld
OBJCOPY := $(CROSS_COMPILE)objcopy
OBJDUMP := $(CROSS_COMPILE)objdump
INCDIRS := imx6ul \ #NCDIRS := imx6ul bsp/clk bsp/led bsp/delay 头文件路径
bsp/clk \
bsp/led \
bsp/delay
SRCDIRS := project \ #SRCDIRS := project bsp/clk bsp/led bsp/delay
bsp/clk \
bsp/led \
bsp/delay
#INCLUDE := -I imx6ul -I bsp/clk -I bsp/led -I bsp/delay
INCLUDE := $(patsubst %, -I %, $(INCDIRS))
#SFILES := project/start.S
SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
#CFILES = project/main.c bsp/clk/bsp_clk.c bsp/led/bsp_led.c bsp/delay/bsp_delay.c
CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
SFILENDIR := $(notdir $(SFILES))
CFILENDIR := $(notdir $(CFILES))
#目标文件存放路径
SOBJS := $(patsubst %, obj/%, $(SFILENDIR:.S=.o))
COBJS := $(patsubst %, obj/%, $(CFILENDIR:.c=.o))
OBJS := $(SOBJS) $(COBJS)
VPATH := $(SRCDIRS)
.PHONY: clean
$(TARGET).bin : $(OBJS)
$(LD) -Timx6ul.lds -o $(TARGET).elf $^
$(OBJCOPY) -O binary -S $(TARGET).elf $@
$(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
$(SOBJS) : obj/%.o : %.S
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
$(COBJS) : obj/%.o : %.c
$(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
clean:
rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS) $(SOBJS)