韦东山嵌入式入门笔记之——应用开发基础篇(二)

三、Makefile的使用

1、为什么需要Makefile
在编写程序后,如果仅改动了一个源文件(比如.h文件),那么不可能通过一系列的命令来重新编译所有的源文件,甚至有时改动的源文件比较多,出现最后忘记编译某些源文件的情况。而make工具可以解决上述问题,它会在有必要时重新编译所有受改动影响的源文件。而Makefile文件则告诉make怎样编译和连接成一个程序。Makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

Makefile文件一般和项目的其他源文件放在同一目录下。

2、Makefile的简单规则:

一个简单的Makefile文件包含一系列的“规则”,其样式如下:

目标(target)依赖(prerequiries)     //目标程序或者文件    依赖于:  依赖文件

<tab>命令(command)                     //如果“依赖文件”比“目标文件”更加新(即发生更改),那么执行“命令”来重新生成“目标文件”

命令被执行的2个条件:依赖文件比目标文件,或是 目标文件还没生成

命令是Make执行的动作,一个规则可以含有几个命令,每个命令占一行。注意:每个命令行前面必须是一个Tab字符,即命令行第一个字符是Tab。这是不小心容易出错的地方。

3、先介绍Makefile的2个函数

A.  $(foreach var,list,text)

简单地说,就是 for each var in list, change it to text。

对list中的每一个元素,取出来赋给var,然后把var改为text所描述的形式。

例子:

objs := a.o b.o

dep_files := $(foreach  f,  $(objs),  .$(f).d)  // 最终 dep_files := .a.o.d .b.o.d


B.  $(wildcard pattern)

pattern所列出的文件是否存在,把存在的文件都列出来。

例子:

src_files := $( wildcard  *.c)  // 最终 src_files中列出了当前目录下的所有.c文件


4、当使用make命令时,会先在当前目录下寻找名为Makefile的文件,然后执行Makefile中的命令,并在终端上显示执行的命令,如:

book@100ask:~/04_test_Makefile$  make
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o

如果目标程序/文件无需更改,则会提示目标程序已经是最新的了:

book@100ask:~/04_test_Makefile$  make
make:'test'  is up to date.


5、创建Makefile文件时选择文件格式为Makefile


6、命令的执行是有顺序的:假如Makefile文件的命令如下:

test : main.o sub.o
    gcc -o test main.o sub.o

main.o : main.c
     gcc -c -o main.o main.c

sub.o : sub.c
      gcc -c -o sub.o sub.c

第一个目标文件test依赖于main.o 和sub.o,因为main.o不存在,跳到第二段命令,所以先执行gcc -c -o main.o main.c;然后回到第一行,发现sub.o也不存在,所以跳到第三段,执行gcc -c -o sub.o sub.c;再回到第一行,两个依赖文件都有了,满足条件生成目标文件test


7、make clean:只执行Makefile中的clean这个目标文件的相关命令。


8、$@ 表示全部的目标文件,$^ 表示全部的依赖文件,$< 表示第一个依赖文件

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


9、当一个目标文件有两依赖文件时,其中一个有命令,另一个没命令,那么这两依赖文件会合并在一起,更改没有命令的依赖文件也会触发另一个依赖文件的命令。
但是没有命令的依赖文件下面需要空一行并且空行不能有Tab键。


10、想达到的效果:修改源文件或者头文件时,只要使用make命令重新编译牵涉到的文件,就可以重新生成APP:请看4-3-1节(听不懂)
①为什么make clean可以反复使用?clean不是个test那样的程序吗?如果clean存在了为什么还可以反复生成?
②为什么要改成.main.d的文件格式?
③objs := main.o sub.o是什么用法?
④为什么使用objs时要使用${objs}的形式?

 

11、通用Makefile的使用方法:
(1)把顶层Makefile, Makefile.build放入程序的顶层目录
  在各自子目录创建一个空白的Makefile

(2)确定编译哪些源文件
  步骤:
(一)按照需要修改和添加顶层目录中Makefile的obj-y 
(二)在每个子目录中空白的Makefile中添加obj-y 

   对obj-y 的说明:
   obj-y += xxx.o
   obj-y += yyy/           
   ①这表示要编译当前目录下的xxx.c(把.c文件编译得到.o文件)和yyy子目录(yyy目录中的Makefile文件又会指定该目录下需要编译的文件和子目录)
   ②表示yyy是子目录的斜杠 / 不可省略

(3)确定编译选项、链接选项
  步骤:
(一)修改顶层目录Makefile的CFLAGS,这是编译所有.c文件时都要用的编译选项;
           顶层的Makefile文件中有这样一段:

     CFLAGS += -I $(shell pwd)/include

          因为一个工程文件中所有的头文件都放在include目录中,所以这一段表示:编译所有.c文件时都会查找该文件下的include目录(中的头文件)

(二)修改顶层目录Makefile的LDFLAGS,这是链接最后的应用程序时的链接选项;
           LDFLAGS可以在链接时指定库的位置和库的名称:

     LDFLAGS := -L dir -labc

           -L 是指定库的位置是当前位置下的dir目录,-l (小写L)指定库的名称为abc

(三)设置其他编译选项(可不设置)
           修改各自子目录下的Makefile:
           "EXTRA_CFLAGS",    它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置
           "CFLAGS_xxx.o",    它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置
   
(4)使用哪个编译器?
  修改顶层目录Makefile第一行的CROSS_COMPILE, 用来指定工具链的前缀(比如arm-linux-)
  如果是在gcc下编译则不进行赋值
   
(5)确定应用程序的名字:
  修改顶层目录Makefile的TARGET, 这是用来指定编译出来的程序的名字,如:

TARGET := test

(6)执行"make"来编译,执行"make clean"来清除,执行"make distclean"来彻底清除

(7)编译成功后时会提示“xxx has been built !”

(8)通用Makefile的源码位置:【第4篇】嵌入式Linux应用开发基础知识/source/05_general_Makefile

12、通用Makefile的解析: 4-3-3节,跳过
分析了Makefile中的命令的含义和Makefile的设计思路
资料请参考第4章《嵌入式linux应用开发基础知识》的3.0.3节和3.1节

猜你喜欢

转载自blog.csdn.net/San_a_fish_of_dream/article/details/113256556
今日推荐