makefile是用来管理工程的。
示例1:
1 exe: a.c b.c 2 gcc a.c b.c -o exe 3 4 clean: 5 rm exe
基本概念:
目标:顶格写,在:前面
依赖: 在:后面,用来产生目标的原材料
命令:前面一定是table,不能是多个空格。命令是生成目标所做的动作
示例2:
1 led.bin: start.o 2 arm-linux-ld -Ttext 0x0 -o led.elf $^ 3 arm-linux-objcopy -O binary led.elf led.bin 4 arm-linux-objdump -D led.elf > led_elf.dis 5 gcc mkv210_image.c -o mkx210 // 该处生成的mkx210是为了在Linux下执行的,这里的gcc和交叉编译工具链的gcc不相同 6 ./mkx210 led.bin 210.bin 7 8 %.o : %.S 9 arm-linux-gcc -o $@ $< -c 10 11 %.o : %.c 12 arm-linux-gcc -o $@ $< -c 13 14 clean: 15 rm *.o *.elf *.bin *.dis mkx210 -f
示例分析:
(1)Makefile有三个非常有用的变量。分别是$@,$^,$<代表的意义分别是:
$@--目标文件,$^--所有的依赖文件,$<--第一个依赖文件
(2)交叉编译工具链工具及作用
先决条件:linux系统下面有一个环境变量叫PATH,必须把该工具链的地址导入到该环境变量下面,export PATH=工具链地址:$PATH
最好是该语句加到~/.bash文件中,这样每次启动终端都会执行该语句。
arm-linux-gcc:
用来编译源文件
arm-linux-ld:
用来链接,其中,-Ttest是用来指定链接地址的,在该处也可以使用链接脚本来去进行链接。在该处生成的elf文件还不能烧录执行。
objcopy:
作用以led.elf为源材料为源材料制作镜像的工具。
解释:led.elf已经是可执行程序,在操作系统下已经可以执行,裸机中需要的是可以烧录的二进制文件(镜像image)。
以led.elf为源材料为源材料制作镜像
objdump:
作用:反汇编,将elf格式的可执行程序反过来得到其汇编源代码。
mkx210(由mkv210_image.c得到):
作用:以led.bin为源材料得到210.bin(为BL1添加校验头)
解释:usb启动时不需要头校验,SD卡启动时需要,让led.bin加上header(校验头)成为210.bin。
附:mkv210_image.c源程序:
1 /* 2 * mkv210_image.c的主要作用就是由usb启动时使用的led.bin制作得到由sd卡启动的镜像210.bin 3 * 4 * 本文件来自于友善之臂的裸机教程,据友善之臂的文档中讲述,本文件是一个热心网友提供,在此表示感谢。 5 */ 6 /* 在BL0阶段,Irom内固化的代码读取nandflash或SD卡前16K的内容, 7 * 并比对前16字节中的校验和是否正确,正确则继续,错误则停止。 8 */ 9 #include <stdio.h> 10 #include <string.h> 11 #include <stdlib.h> 12 13 #define BUFSIZE (16*1024) 14 #define IMG_SIZE (16*1024) 15 #define SPL_HEADER_SIZE 16 16 //#define SPL_HEADER "S5PC110 HEADER " 17 #define SPL_HEADER "****************" 18 19 int main (int argc, char *argv[]) 20 { 21 FILE *fp; 22 char *Buf, *a; 23 int BufLen; 24 int nbytes, fileLen; 25 unsigned int checksum, count; 26 int i; 27 28 // 1. 3个参数 29 if (argc != 3) 30 { 31 printf("Usage: %s <source file> <destination file> ", argv[0]); 32 return -1; 33 } 34 35 // 2. 分配16K的buffer,并且全部填充为0 36 BufLen = BUFSIZE; 37 Buf = (char *)malloc(BufLen); 38 if (!Buf) 39 { 40 printf("Alloc buffer failed! "); 41 return -1; 42 } 43 44 memset(Buf, 0x00, BufLen); 45 46 // 3. 读源bin到buffer 47 // 3.1 打开源bin 48 fp = fopen(argv[1], "rb"); 49 if( fp == NULL) 50 { 51 printf("source file open error "); 52 free(Buf); 53 return -1; 54 } 55 // 3.2 获取源bin长度 56 fseek(fp, 0L, SEEK_END); // 定位到文件尾 57 fileLen = ftell(fp); // 得到文件长度 58 fseek(fp, 0L, SEEK_SET); // 再次定位到文件头 59 // 3.3 源bin长度不得超过16K-16byte 60 count = (fileLen < (IMG_SIZE - SPL_HEADER_SIZE)) 61 ? fileLen : (IMG_SIZE - SPL_HEADER_SIZE); 62 // 3.4 buffer[0~15]存放"S5PC110 HEADER " 63 memcpy(&Buf[0], SPL_HEADER, SPL_HEADER_SIZE); 64 // 3.5 读源bin到buffer[16] 65 nbytes = fread(Buf + SPL_HEADER_SIZE, 1, count, fp); 66 if ( nbytes != count ) 67 { 68 printf("source file read error "); 69 free(Buf); 70 fclose(fp); 71 return -1; 72 } 73 fclose(fp); 74 75 // 4. 计算校验和 76 // 4.1 从第16byte开始统计buffer中共有几个1 77 // 4.1 从第16byte开始计算,把buffer中所有的字节数据加和起来得到的结果 78 a = Buf + SPL_HEADER_SIZE; 79 for(i = 0, checksum = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++) 80 checksum += (0x000000FF) & *a++; 81 // 4.2 将校验和保存在buffer[8~15] 82 a = Buf + 8; // Buf是210.bin的起始地址,+8表示向后位移2个字,也就是说写入到第3个字 83 *( (unsigned int *)a ) = checksum; 84 85 // 5. 拷贝buffer中的内容到目的bin 86 // 5.1 打开目的bin 87 fp = fopen(argv[2], "wb"); 88 if (fp == NULL) 89 { 90 printf("destination file open error "); 91 free(Buf); 92 return -1; 93 } 94 // 5.2 将16k的buffer拷贝到目的bin中 95 a = Buf; 96 nbytes = fwrite( a, 1, BufLen, fp); 97 if ( nbytes != BufLen ) 98 { 99 printf("destination file write error "); 100 free(Buf); 101 fclose(fp); 102 return -1; 103 } 104 105 free(Buf); 106 fclose(fp); 107 108 return 0; 109 }
(3)指令解释
-c: 只编译不链接
-o: 用来指定名字
-D: 表示反汇编(反汇编工具有多种用法,-D表示反汇编用法)
-Ttext: 指定代码段的起始地址(链接地址)
(4)其它
第8行到第12行叫做makefile的规则,当看到.S和.c文件会自动转化为.o文件。
printf移植中用到的makefile
1 CC = arm-linux-gcc 2 LD = arm-linux-ld 3 OBJCOPY = arm-linux-objcopy 4 OBJDUMP = arm-linux-objdump 5 AR = arm-linux-ar 6 7 INCDIR := $(shell pwd) 8 9 # c预处理器的flag,flag就是编译器可选的选项 10 CPPFLAGS := -nostdlib -nostdinc -I$(INCDIR)/include 11 # C编译器的flag 12 CFLAGS := -Wall -O2 -fno-builtin 13 14 # 导出这些变量到全局,其实就是给子文件下面的makefile使用 15 export CC LD OBJCOPY OBJDUMP AR CPPFLAGS CFLAGS 16 17 18 objs := start.o led.o clock.o uart.o main.o 19 objs += lib/libc.a 20 21 uart.bin: $(objs) 22 $(LD) -Tlink.lds -o uart.elf $^ 23 $(OBJCOPY) -O binary uart.elf uart.bin 24 $(OBJDUMP) -D uart.elf > uart_elf.dis 25 gcc mkv210_image.c -o mkx210 26 ./mkx210 uart.bin 210.bin 27 28 lib/libc.a: 29 cd lib; make; cd .. 30 31 32 33 %.o : %.S 34 $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c 35 36 %.o : %.c 37 $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ $< -c 38 39 clean: 40 rm *.o *.elf *.bin *.dis mkx210 -f 41 cd lib; make clean; cd ..
-nostdlib 不用标准库
-nostdinc 不用标准的头文件
-O2 编译器的优化等级
-Wall 显示所有警告
-I 用来表示寻找头文件的目录(一般用相对路径表示)