zoukankan      html  css  js  c++  java
  • 14、编写一个通用的Makefile

    编译test_Makefile的方法:
    a. gcc -o test a.c b.c
    对于a.c: 预处理、编译(C文件转换成汇编)、汇编(汇编转换成机器码)
    对于b.c:预处理、编译、汇编
    最后链接
    优点:命令简单
    缺点:如果文件很多,即使你只修改了一个文件,但是所有的文件文件都要重新"预处理、编译、汇编"
    效率低

    b. 写Makefile
    核心:规则

    目标:依赖1 依赖2(目标指根据依赖生成文件名字)
      命令

    a.o : a.c

      gcc -c -o a.o a.c

    %.o:%.c    //这里的%是通配符

      gcc -c -o $@  $<     //$@表示目标  $<表示第一个依赖 %^表示所有的依赖

    (gcc还要加上-Wp,-MD,名字.d  用来生成依赖文件,否则.h文件改变后,执行make的时候gcc不会发现文件变化了,这样就不执行gcc指令)

    命令执行的条件:
    i. "依赖"文件 比 "目标"文件 新
    ii.没有"目标"这个文件

    一、各级子目录的Makefile:
    它最简单,形式如下:
    obj-y += file.o
    obj-y += subdir/

    "obj-y += file.o"表示把当前目录下的file.c编进程序里,
    "obj-y += subdir/"表示要进入subdir这个子目录下去寻找文件来编进程序里,是哪些文件由subdir目录下的Makefile决定。

    注意: "subdir/"中的斜杠"/"不可省略

    二、顶层目录的Makefile:
    它除了定义obj-y来指定根目录下要编进程序去的文件、子目录外,主要是定义工具链、编译参数、链接参数──就是文件中用export导出的各变量。导出的目的是给个子目录下makefile使用

    export AS LD CC CPP AR NM
    export STRIP OBJCOPY OBJDUMP

    //链接的时候指定优化选项和目录(目录是告诉编译器去哪里找那些头文件,$(shell pwd)表示执行pwd指令获得当前目录),使用arm-linux-gcc来编译的时候,编译器是去/usr/local/arm/4.3.2/arm-none-linux-guneabi/libc/usr/include目录下找头文件,可以通过-I(i的大小)头文件目录来指定头文件或者通过-L 指定库文件目录

    CFLAGS := -Wall -O2 -g  //-Wall表示列出所有警告   -O2表示优化选项  -g表示,等号的前面“:”表示立即变量,没有这个:,赋值过程会被延时,使用的时候财货确定下来,有无冒号的原因具体见gcc文档
    CFLAGS += -I $(shell pwd)/include

    //LDFLAGS 表示链接参数

    LDFLAGS := -lm -lfreetype

    三、顶层目录的Makefile.build:(在数码相框的makefile那节的doc目录中有详细介绍,(子目录下的makefile是最先执行))
    这是最复杂的部分,它的功能就是把某个目录及它的所有子目录中、需要编进程序去的文件都编译出来,打包为built-in.o
    详细的讲解请看视频。

    举例说明Makefile.build

    PHONY := __build   //PHONY 假象目标,肯定会执行
    __build:  //声明最开始的目标


    obj-y :=  //先赋空值
    subdir-y :=

    include Makefile  //因为Makefile中含有obj-y等变量值

    # obj-y := a.o b.o c/ d/    //下面用#开始的四条语句是举例怎么从obj-y中取得所有子目录
    # $(filter %/, $(obj-y)) : c/ d/  //filter表示把$(obj-y)中不符合%/的移除,保留复合%/的
    # __subdir-y : c d
    # subdir-y : c d
    __subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))  //$(patsubst pattern,replacement,text) 在text中用replacement代替pattern
    subdir-y += $(__subdir-y)

    # c/built-in.o   d/built-in.o   //subdir_objs := c/built-in.o   d/built-in.o
    subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o)   

    # a.o b.o//下面六行语句的目前是为了生成依赖文件,这样.h文件改变后在执行make才会让编译器知道.h文件也改变了
    cur_objs := $(filter-out %/, $(obj-y))
    dep_files := $(foreach f,$(cur_objs),.$(f).d)
    dep_files := $(wildcard $(dep_files))

    ifneq ($(dep_files),)
      include $(dep_files)
    endif


    PHONY += $(subdir-y)


    __build : $(subdir-y) built-in.o //顶层目录的makefile执行到这里的时候会先去获得subdir-y,其获得规则在下面,同理built-in.o,这里的$(subdir-y) 仅为了生成所有的built-in.o,其后的built-in.o才是最后的依赖文件

    $(subdir-y):
      make -C $@ -f $(TOPDIR)/Makefile.build    //$@表示进入各级子目录,使用顶层目录下的Makefile.build来生成各级子目录的built-in.o

    built-in.o : $(cur_objs) $(subdir_objs)//依赖的是当前目录下.o文件和各级子目录下built-in.o
      $(LD) -r -o $@ $^

    dep_file = .$@.d   //没有冒号,表示延时赋值,在下面使用的时候才赋值,这样$@才有值

    %.o : %.c
      $(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<

    .PHONY : $(PHONY)

  • 相关阅读:
    docker-compose,docker-machine,docker swarm 的简单总结
    linux ubuntu安装好后,开通远程登录
    docker数据卷的使用 -v --volumes--from
    shell脚本中source无效
    模块 shutil
    模块 sys
    模块 os
    模块 random
    模块 datetime,time
    import本质
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/9000283.html
Copyright © 2011-2022 走看看