makefile及其相关知识介绍

 

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>\n", 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!\n");
 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\n");
 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\n");
 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\n");
 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\n");
100         free(Buf);
101         fclose(fp);
102         return -1;
103     }
104 
105     free(Buf);
106     fclose(fp);
107 
108     return 0;
109 }
View Code

 

(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           用来表示寻找头文件的目录(一般用相对路径表示)

posted @ 2018-03-13 11:06  嘎嘎的天空  阅读(301)  评论(0编辑  收藏  举报