FFmpeg之Makefile流程分析

1. 目标依赖关系

在这里插入图片描述
在FFMpeg源码根目录下下执行make,会找到第一个目标all,那么整个编译最终目标就是要完成All目标。我们先找一下all目标的所有依赖

依赖一:all-yes
根目录下的Makefile

# first so "all" becomes default target
all: all-yes

include $(SRC_PATH)/fftools/Makefile

依赖二:AVPROGS
fftools/Makefile

# first so "all" becomes default target
all: $(AVPROGS)

这个AVPROGS=ffmpeg ffprobe,两个可执行程序

2. all-yes依赖

all-yes表示所有的lib依赖,就是ffmpeg里面核心的几个模块:avcodec, avutil, avformat avresample…

all-yes是通过foreach循环完成添加。核心代码在根目录下的Makefile:

define DOSUBDIR
$(foreach V,$(SUBDIR_VARS),$(eval $(call RESET,$(V))))
SUBDIR := $(1)/
include $(SRC_PATH)/$(1)/Makefile
-include $(SRC_PATH)/$(1)/$(ARCH)/Makefile
-include $(SRC_PATH)/$(1)/$(INTRINSICS)/Makefile
include $(SRC_PATH)/ffbuild/library.mak
endef

$(foreach D,$(FFLIBS),$(eval $(call DOSUBDIR,lib$(D))))

2.1 子模块Makefile

这里遍历每个模块(FFLIBS),然后include模块中的Makefile和ffbuild/library.mak。我们以codec模块为例,看下:

NAME = avcodec
DESC = FFmpeg codec library

HEADERS = ac3_parser.h                                                  \
          adts_parser.h                                                 \
          avcodec.h                                                     \
          avdct.h                                                       \
          
# 后面省略...

每次include一个模块的Makefile这个NAME变量都会发生更新。

2.2 library.mak

这个mak文件内,负责处理每个模块编译通用逻辑。看一下核心逻辑:

# common.mak描述了所有模块中文件编译的通用规则
include $(SRC_PATH)/ffbuild/common.mak

# 模块的all-yes目标和对应依赖
all-$(CONFIG_STATIC): $(SUBDIR)$(LIBNAME)  $(SUBDIR)lib$(FULLNAME).pc
all-$(CONFIG_SHARED): $(SUBDIR)$(SLIBNAME) $(SUBDIR)lib$(FULLNAME).pc

# 静态压缩
# LIBNAME = libavcodec.a (不同模块的 LIBNAME 会更新)
# OBJS 是每个模块内部Makefile定义,模块编译出来的所有.o文件
$(SUBDIR)$(LIBNAME): $(OBJS) $(STLIBOBJS)
	$(RM) $@
	$(AR) $(ARFLAGS) $(AR_O) $^
	$(RANLIB) $@

# 动态库
$(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SHLIBOBJS) $(SLIBOBJS) $(SUBDIR)lib$(NAME).ver
	$(warning lorien SLIBNAME TARGET = $@ DEPS = $^)
	$(SLIB_CREATE_DEF_CMD)
	$$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS)
	$(SLIB_EXTRA_CMD)

2.3 common.mak

common.mak内定义所有模块编译的通用规则。

define COMPILE
       $(call $(1)DEP,$(1))
       $($(1)) $($(1)FLAGS) $($(2)) $($(1)_DEPFLAGS) $($(1)_C) $($(1)_O) $(patsubst $(SRC_PATH)/%,$(SRC_LINK)/%,$<)
endef

COMPILE_C = $(call COMPILE,CC)
COMPILE_CXX = $(call COMPILE,CXX)

%.o: %.c
	$(COMPILE_C)

%.o: %.cpp
	$(COMPILE_CXX)

大致编译流程如下:

  1. foreach循环确定了all-yes所有依赖,也就是avcodec, avutil, avscale, avformat等这些模块。
  2. 然后进入这些模块,将.c编译出所有的.o
  3. 然后通过 library.mak中,$(AR) $(ARFLAGS) $(AR_O) $^将所有的.o打包成.a库文件
  4. 最后每个模块都会产出各自的.a 文件,比如:libavformat.a, libavcodec.a, libavutil.a …

3. PROGS依赖

所有模块的库文件制作完成之后,接下来,编译生成两个可执行程序:ffmpeg 和 ffprobe

我们看下根目录的Makefile

# 这个include,会给all新增一个依赖:PROGS
include $(SRC_PATH)/fftools/Makefile
include $(SRC_PATH)/doc/Makefile
include $(SRC_PATH)/doc/examples/Makefile

# ffmpeg: ffmpeg_g
# 使用strip命令将ffmpeg_g生成ffmpeg
$(PROGS): %$(PROGSSUF)$(EXESUF): %$(PROGSSUF)_g$(EXESUF)
ifeq ($(STRIPTYPE),direct)
	$(STRIP) -o $@ $<
else
	$(warning lorien PROGS dep = $(PROGS))
	$(RM) $@
	$(CP) $< $@
	$(STRIP) $@
endif

# ffmpeg_g: libavdevice/libavdevice.a libavfilter/libavfilter.a  ...  fftools/ffmpeg.o
%$(PROGSSUF)_g$(EXESUF): $(FF_DEP_LIBS)
	$(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(OBJS-$*) $(FF_EXTRALIBS)

直接看注释即可,不做过多赘述。

猜你喜欢

转载自blog.csdn.net/H_Zhang/article/details/127839822
今日推荐