• ffmeg 中fftools/Makefile 分析


    1. 1 AVPROGS-$(CONFIG_FFMPEG) += ffmpeg
    2. 2 AVPROGS-$(CONFIG_FFPLAY) += ffplay
    3. 3 AVPROGS-$(CONFIG_FFPROBE) += ffprobe
    4. 4
    5. 5 AVPROGS := $(AVPROGS-yes:%=%$(PROGSSUF)$(EXESUF))
    6. 6 PROGS += $(AVPROGS)
    7. 7
    8. 8 AVBASENAMES = ffmpeg ffplay ffprobe
    9. 9 ALLAVPROGS = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF))
    10. 10 ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))
    11. 11
    12. 12 OBJS-ffmpeg += fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o
    13. 13 OBJS-ffmpeg-$(CONFIG_LIBMFX) += fftools/ffmpeg_qsv.o
    14. 14 ifndef CONFIG_VIDEOTOOLBOX
    15. 15 OBJS-ffmpeg-$(CONFIG_VDA) += fftools/ffmpeg_videotoolbox.o
    16. 16 endif
    17. 17 OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += fftools/ffmpeg_videotoolbox.o
    18. 18
    19. 19 define DOFFTOOL
    20. 20 OBJS-$(1) += fftools/cmdutils.o fftools/$(1).o $(OBJS-$(1)-yes)
    21. 21 $(1)$(PROGSSUF)_g$(EXESUF): $$(OBJS-$(1))
    22. 22 $$(OBJS-$(1)): | fftools
    23. 23 $$(OBJS-$(1)): CFLAGS += $(CFLAGS-$(1))
    24. 24 $(1)$(PROGSSUF)_g$(EXESUF): LDFLAGS += $(LDFLAGS-$(1))
    25. 25 $(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(EXTRALIBS-$(1))
    26. 26 -include $$(OBJS-$(1):.o=.d)
    27. 27 endef
    28. 28
    29. 29 $(foreach P,$(AVPROGS-yes),$(eval $(call DOFFTOOL,$(P))))
    30. 30
    31. 31 all: $(AVPROGS)
    32. 32
    33. 33 fftools/ffprobe.o fftools/cmdutils.o: libavutil/ffversion.h | fftools
    34. 34 OUTDIRS += fftools
    35. 35
    36. 36 ifdef AVPROGS
    37. 37 install: install-progs install-data
    38. 38 endif
    39. 39
    40. 40 install-progs-yes:
    41. 41 install-progs-$(CONFIG_SHARED): install-libs
    42. 42
    43. 43 install-progs: install-progs-yes $(AVPROGS)
    44. 44 $(Q)mkdir -p "$(BINDIR)"
    45. 45 $(INSTALL) -c -m 755 $(AVPROGS) "$(BINDIR)"
    46. 46
    47. 47 uninstall: uninstall-progs
    48. 48
    49. 49 uninstall-progs:
    50. 50 $(RM) $(addprefix "$(BINDIR)/", $(ALLAVPROGS))
    51. 51
    52. 52 clean::
    53. 53 $(RM) $(ALLAVPROGS) $(ALLAVPROGS_G) $(CLEANSUFFIXES:%=fftools/%)
    54. ~

    分析此文件的目的是为了提高make在项目管理中的使用.
    这个文件只是一个局部的Makefile, 并不能单独工作,欲工作需在顶层执行make,欲再次看到变化你可以
    touch ./fftools/cmdutils.c , 这是一个基础文件,会引起重新编译。
    分析开始:
    1. AVPROGS-$(CONFIG_FFMPEG)   += ffmpeg
    2. AVPROGS-$(CONFIG_FFPLAY)   += ffplay
    3. AVPROGS-$(CONFIG_FFPROBE)  += ffprobe

    # makefile (从“fftools/Makefile”,行 3)
    AVPROGS-yes = ffmpeg ffplay ffprobe
    被赋值的变量都是要立即求值的,
    其中CONFIG_FFMPEG,CONFIG_FFPLAY,CONFIG_FFPROBE 均在config.mak有定义为yes
    所以到第3行时:
    AVPROGS-yes = ffmpeg ffplay ffprobe


    5. AVPROGS     := $(AVPROGS-yes:%=%$(PROGSSUF)$(EXESUF))
    6. PROGS       += $(AVPROGS)
    7.
    8. AVBASENAMES  = ffmpeg ffplay ffprobe
    9. ALLAVPROGS   = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF))
    10.ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))

    # makefile (从“fftools/Makefile”,行 5)
    AVPROGS := ffmpeg ffplay ffprobe
    对AVPROGS 立即赋值, 结果类型为简单变量,
    由于PROGSSUF,EXESUB在config.mak中均定义为空,所以替换结果未变,

    PROGS 是一个递归变量,原来它为空值,此时会为以上3值,但随后它还会变
    在doc/example/Makefile 第29行
    PROGS          += $(EXAMPLES)
    所以PROGS 变量在数据库中记录的是
    # makefile (从“ doc/examples/Makefile ”,行 29)
    PROGS = $(AVPROGS) $(EXAMPLES)
    在本文件中的作用是中间过程,被合并到(+=)后续中去了.
    递归变量在用的时候会被递归展开.


    # makefile (从“fftools/Makefile”,行 8), 说明后面再没有重新赋值了。
    AVBASENAMES = ffmpeg ffplay ffprobe
    # makefile (从“fftools/Makefile”,行 9), 变量要滞后展开,所以就保持原样了.
    ALLAVPROGS = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF))
    # makefile (从“fftools/Makefile”,行 10)
    ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF))

    这三行被直接记录到数据库,留着将来使用递归展开.


    12 OBJS-ffmpeg                        += fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o
    13 OBJS-ffmpeg-$(CONFIG_LIBMFX)       += fftools/ffmpeg_qsv.o
    14 ifndef CONFIG_VIDEOTOOLBOX
    15 OBJS-ffmpeg-$(CONFIG_VDA)          += fftools/ffmpeg_videotoolbox.o
    16 endif
    17 OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += fftools/ffmpeg_videotoolbox.FFLIBSo

    从数据库中看,只记录了17行和29行
    # makefile (从“fftools/Makefile”,行 17)
    OBJS-ffmpeg- = fftools/ffmpeg_qsv.o fftools/ffmpeg_videotoolbox.o fftools/ffmpeg_videotoolbox.o
    从这句话可以看出, $(CONFIG_LIBMFX),$(CONFIG_VDA),$(CONFIG_VIDEOTOOLBOX)为空
    # makefile (从“fftools/Makefile”,行 29)
    OBJS-ffmpeg = fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o fftools/cmdutils.o fftools/ffmpeg.o
    从这句话可以看出, 第12行等只是一个中间过程,到29行还有赋值

    1. 下面命令包要登场,还包括一个循环语句和eval函数,及命令包调用
    2. 19 define DOFFTOOL
    3. 20 OBJS-$(1) += fftools/cmdutils.o fftools/$(1).o $(OBJS-$(1)-yes)
    4. 21 $(1)$(PROGSSUF)_g$(EXESUF): $$(OBJS-$(1))
    5. 22 $$(OBJS-$(1)): | fftools
    6. 23 $$(OBJS-$(1)): CFLAGS += $(CFLAGS-$(1))
    7. 24 $(1)$(PROGSSUF)_g$(EXESUF): LDFLAGS += $(LDFLAGS-$(1))
    8. 25 $(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(EXTRALIBS-$(1))
    9. 26 -include $$(OBJS-$(1):.o=.d)
    10. 27 endef
    11. 28
    12. 29 $(foreach P,$(AVPROGS-yes),$(eval $(call DOFFTOOL,$(P))))

    插曲:
    变量和函数的定义可以用下表来概括。
         IMMEDIATE = DEFERRED
         IMMEDIATE ?= DEFERRED
         IMMEDIATE := IMMEDIATE
         IMMEDIATE ::= IMMEDIATE
         IMMEDIATE += DEFERRED or IMMEDIATE
         IMMEDIATE != IMMEDIATE

         define IMMEDIATE
           DEFERRED
         endef

         define IMMEDIATE =
           DEFERRED
         endef

         define IMMEDIATE ?=
           DEFERRED
         endef

         define IMMEDIATE :=
           IMMEDIATE
         endef

         define IMMEDIATE ::=
           IMMEDIATE
         endef

         define IMMEDIATE +=
           DEFERRED or IMMEDIATE
         endef

         define IMMEDIATE !=
           IMMEDIATE
         endef

    由此看出, 函数名称是要被立即求值的,但函数体我们定义的是延时求值.
    DOFFTOOL 命令包, 在数据库中是这样定义的.

    1. # makefile (从“fftools/Makefile”,行 19)
    2. define DOFFTOOL
    3. OBJS-$(1) += fftools/cmdutils.o fftools/$(1).o $(OBJS-$(1)-yes)
    4. $(1)$(PROGSSUF)_g$(EXESUF): $$(OBJS-$(1))
    5. $$(OBJS-$(1)): | fftools
    6. $$(OBJS-$(1)): CFLAGS += $(CFLAGS-$(1))
    7. $(1)$(PROGSSUF)_g$(EXESUF): LDFLAGS += $(LDFLAGS-$(1))
    8. $(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(EXTRALIBS-$(1))
    9. -include $$(OBJS-$(1):.o=.d)
    10. endef

    可见它就是一个原样照印保留着,留待使用时扩展.
    包含了OBJS-$(1) 变量
    还定义了一些变量依赖,比较复杂的是还包含了一个.d依赖,这个.d依赖可能会是一个列表,根据OBJ-$(1)文件个数
    所以看起来就很复杂了,已经不能用眼睛看透,也不用看了,但可用心体会。
    关键是使用这个函数,第29行
    对每一个AVPROGS要循环执行 $(call DOFFTOOL,$(P))))
    相当于一大堆代码在29行被展开,$(eval)是求值的意思,把它们当作make语句在这里被source进来。
    我们直接看看数据库记录的结果吧. 当然是被我整理过的, 不过可以跟宏对的上

    # makefile (从“fftools/Makefile”,行 29)
    //特定的flags
    fftools/ffmpeg_opt.o: CFLAGS +=
    fftools/ffmpeg_filter.o: CFLAGS +=
    fftools/ffprobe.o: CFLAGS +=
    fftools/cmdutils.o: CFLAGS +=  -D_REENTRANT -I/usr/include/SDL2
    ffmpeg_g: LDFLAGS +=
    ffmpeg_g: FF_EXTRALIBS +=
    //objs 组成
    OBJS-ffprobe = fftools/cmdutils.o fftools/ffprobe.o
    OBJS-ffplay = fftools/cmdutils.o fftools/ffplay.o
    OBJS-ffmpeg = fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o fftools/cmdutils.o fftools/ffmpeg.o
    //执行文件的依赖关系
    ffmpeg_g: fftools/ffmpeg_opt.o fftools/ffmpeg_filter.o fftools/ffmpeg_hw.o fftools/cmdutils.o fftools/ffmpeg.o
    //.o 的依赖关系
    fftools/ffmpeg_opt.o: fftools/ffmpeg_opt.c fftools/ffmpeg_opt.c fftools/ffmpeg.h config.h fftools/cmdutils.h .....
    fftools/ffmpeg_filter.o: fftools/ffmpeg_filter.c fftools/ffmpeg_filter.c fftools/ffmpeg.h config.h fftools/cmdutils.h ...
    fftools/ffprobe.o: fftools/ffprobe.c config.h libavutil/ffversion.h libavformat/avformat.h libavcodec/avcodec.h ...
    fftools/cmdutils.o: fftools/cmdutils.c fftools/cmdutils.c config.h compat/va_copy.h libavformat/avformat.h ...
    我们看得很清楚,定义了针对性的FLAGS, OBJS, 及其依赖关系(由.d文件得到)

    再往后面看,就已经很简单了,定义了几条规则,这里就忽略不题了。仅说一下关键点

    1. fftools/ffprobe.o fftools/cmdutils.o: libavutil/ffversion.h | fftools

    多目标依赖右边有一个| 是什么意思?
    没有bar |是一个正常的依赖, 有bar 是 bar依赖,
    正常依赖是当目标不存在或依赖比目标新,重建目标
    bar依赖是当目标不存在,重建目标,当依赖比目标新,不必重建。
    这里的fftools只是一个目录,所以它的依赖性会弱一些,bar依赖就可以了.


    2. $(RM) $(ALLAVPROGS) $(ALLAVPROGS_G) $(CLEANSUFFIXES:%=fftools/%)
        看得比较多了变量展开,变量替换又是怎样用的?
    插曲:
        foo := a.o b.o c.o
        bar := $(foo:%.o=%.c)
        上面的变量替换等价于patsubst(%.o,%.c,$(foo))
        推荐用这两种方法,
        $(foo:.o=.c) 也可以,为了兼容性,当不如用%更规范。

        上述bar的值 为 a.c b.c c.c

    问题:怎样快速知道变量的定义? 其未展开的值及展开后的值, 可添加show-var.mk 文件
    问题:怎样快速找到使用的规则

  • 相关阅读:
    【力扣每日一题】2023.9.24 LRU缓存
    【.NET深呼吸】用代码写WPF控件模板
    【R语言文本挖掘】:tidy数据格式及词频计算
    1008. 前序遍历构造二叉搜索树
    4面百度软件测试工程师的面试经验总结
    Bean的生命周期(五)
    【Autosar 存储栈Memery Stack 3.存储读写流程的要求与时序】
    STM32CubeMX ADC参数配置页中文注解
    Swing编程 — JTable遇到的坑和总结
    CentOS7 利用remi yum源安装php8.1
  • 原文地址:https://blog.csdn.net/hejinjing_tom_com/article/details/126341849