《SRS原理》上架了,深度剖析 SRS 源代码,访问地址:srs.xianwaizhiyin.net
本文采用的 SRS 版本是 4.0-b8 , 下载地址:github
SRS4.0源码分析-CMake 讲了 SRS 在 Clion
里面的调试 中使用的CMake 的逻辑。但是实际编译的时候,通常 使用 configure 跟 makefile。
对于一个 开源项目来说,理解了 configure 跟 makefile ,基本上就理解了这个开源项目的50%。
何时阅读 configure 跟 makefile ?这个问题不好说,我看开源项目,有时候是调试,理解完他的大部分代码逻辑,才开始看 configure 跟 makefile ,因为有些编译逻辑 跟 功能代码 有关。
有时候我是一开始就看 configure 跟 makefile 。
开始 分析 SRS 的 configure 文件。
#!/bin/bash
#####################################################################################
# the main output dir, all configure and make output are in this dir.
#####################################################################################
# create the main objs
SRS_WORKDIR="."
SRS_OBJS_DIR="objs"
SRS_OBJS="${SRS_WORKDIR}/${SRS_OBJS_DIR}"
SRS_MAKEFILE="Makefile"
# linux shell color support.
RED="\\033[31m"
GREEN="\\033[32m"
YELLOW="\\033[33m"
BLACK="\\033[0m"
上面的代码,是设置各种目录,以及 提示颜色。
#####################################################################################
# parse user options, set the variables like:
# srs features: SRS_SSL/SRS_HLS/SRS_HTTP_CALLBACK/......
# build options: SRS_JOBS
#####################################################################################
# parse options, exit with error when parse options invalid.
. auto/options.sh
# setup variables when options parsed.
. auto/setup_variables.sh
上面的代码调用了 两个 shell 脚本,是解析 命令参数的 ,例如 configure --jobs=16
,jobs
就是命令参数,options.sh
跟 setup_variables.sh
是把这个参数解析成 shell 变量
options.sh
跟 setup_variables.sh
自行阅读即可,比较简单。SRS 的 命令行参数 parse 比较简单,是直接全匹配字符串,不像 FFmpeg 那么复杂。
# We don't need to cleanup the exists files.
rm -f ${SRS_WORKDIR}/${SRS_MAKEFILE}
# create objs
mkdir -p ${SRS_OBJS}/${SRS_PLATFORM}
# apply user options.
. auto/depends.sh
# the auto generated variables.
. auto/auto_headers.sh
再次 执行 两个 shell 脚本 depends.sh
跟 auto_headers.sh
。
先分析一下 depends.sh
的逻辑,不贴代码了,直接说重点。
1,Ubuntu_prepare()
,Centos_prepare()
,OSX_prepare()
上面 3 个函数分别 检查相应的操作系统的环境,例如 gcc g++ unzip
等软件有没安装之类的。
2,编译 第三方库 state thread 。
3,安装 cherrypy
,HOOK 实现用的 cherrypy
4,编译第三方库 libopus
,webrtc 要用 libopus
5,编译 FFmpeg 。
6,编译 第三方库 srt 。
7,编译 测试代码 以及 gperf
综上, depends.sh
这个脚本主要就是编译一些 依赖的 第三方的静态库。
再分析一下 auto_headers.sh
,auto_headers.sh
主要是生成 srs_auto_headers.hpp
头文件,实际上是 把 shell 里面的某些变量 转成 c++ 的宏定义,放进去头文件,例如 SRS_HDS_BOOL
# 40 ~ 50 行
#####################################################################################
# generate Makefile.
#####################################################################################
# ubuntu echo in Makefile cannot display color, use bash instead
SRS_BUILD_SUMMARY="_srs_build_summary.sh"
# utest make entry, (cd utest; make)
SrsUtestMakeEntry="@echo -e \"ignore utest for it's disabled\""
if [ $SRS_UTEST = YES ]; then SrsUtestMakeEntry="(cd ${SRS_OBJS_DIR}/${SRS_PLATFORM}/utest && \$(MAKE))"; fi
40 ~ 50 行 是 决定 执 不 执行单元测试。
# 51 ~ 57 行
#####################################################################################
# finger out modules to install.
# where srs module is a dir which contains a config file.
SRS_MODULES=()
__mfiles=`find modules -name "config"` && for __mfile in $__mfiles; do
SRS_MODULES+=("`dirname $__mfile`")
done
SRS_MODULES=()
是定义一个一维数组,这是 shell 定义数组的语法。
然后是 查找 srs-4.0-b8\trunk\modules
目录下有 config
文件的目录,然后加进去 SRS_MODULES
变量。
在 SRS4.0 里面,主要有 hls-ingester
跟 mp4-parse
两个 模块 ,如图:
可以用以下命令 把 SRS_MODULES
打印出来看看。
echo "SRS_MODULES[0] is "${SRS_MODULES[0]}
echo "SRS_MODULES[1] is "${SRS_MODULES[1]}
#退出 shell
exit
# variables for makefile for all modules.
__mphonys="" && __mdefaults="" && __mcleanups="" && __makefiles=""
# add each modules for application
for SRS_MODULE in ${SRS_MODULES[*]}; do
echo "install module at: $SRS_MODULE"
. $SRS_MODULE/config
if [[ $SRS_MODULE_MAKEFILE != "" ]]; then
__makefiles="$__makefiles $SRS_MODULE_MAKEFILE"
fi
if [[ 0 -ne ${#SRS_MODULE_MAIN[@]} ]]; then
__mphonys="$__mphonys $SRS_MODULE_NAME"
__mdefaults="$__mdefaults $SRS_MODULE_NAME"
__mcleanups="$__mcleanups $SRS_MODULE_NAME"
fi
done
上面的代码 就是 把 模块 目录的 config 文件定义的变量 合并进去 __mphonys
,__mdefaults
等变量。
#75 ~ 80 行
# generate extra phony for each modules.
cat << END > ${SRS_OBJS}/${SRS_MAKEFILE}
.PHONY: $__mphonys
END
上面的代码是生成 伪目标 ,写进去 makefile文件,如图:
这里有个重点,shell 里面的 <<
输入, 然后 >
输出的语法不太容易理解,他那个输出文件是放在中间的,放在 第一个 END 后面,而不是第二个 END 后面。
写到这里,发现 configure
文件有 大约800行 shell,全部贴出来太浪费空间了,下面有些地方只会讲重点。
# 82 ~ 130 行
#####################################################################################
# build tools or compiler args.
# enable gdb debug
GDBDebug=" -g -O0"
# the warning level.
WarnLevel=" -Wall -Wno-deprecated-declarations"
# the compile standard.
CppStd="-ansi"
if [[ $SRS_CXX11 == YES ]]; then
CppStd="-std=c++11"
fi
if [[ $SRS_CXX14 == YES ]]; then
CppStd="-std=c++14"
fi
# performance of gprof
SrsGprof=""; SrsGprofLink=""; if [ $SRS_GPROF = YES ]; then SrsGprof=" -pg -lc_p"; SrsGprofLink=" -pg"; fi
# performance of gperf
SrsGperf=""; SrsGperfLink=""; if [ $SRS_GPERF = YES ]; then SrsGperfLink=" -lpthread"; fi
# the cxx flag generated.
CXXFLAGS="${CXXFLAGS} ${CppStd}${WarnLevel}${GDBDebug}${LibraryCompile}${SrsGprof}"
if [ $SRS_GPERF = YES ]; then
CXXFLAGS="${CXXFLAGS} -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free";
fi
# For coverage.
if [[ $SRS_GCOV == YES ]]; then
SrsGcov="-fprofile-arcs -ftest-coverage"
fi
if [[ $SRS_GCOV == YES ]]; then
CXXFLAGS="${CXXFLAGS} ${SrsGcov}";
fi
# User configed options.
if [[ $SRS_EXTRA_FLAGS != '' ]]; then
CXXFLAGS="${CXXFLAGS} $SRS_EXTRA_FLAGS";
fi
# Start to generate the Makefile.
cat << END >> ${SRS_OBJS}/${SRS_MAKEFILE}
GCC = ${SRS_TOOL_CC}
CXX = ${SRS_TOOL_CXX}
AR = ${SRS_TOOL_AR}
LINK = ${SRS_TOOL_CXX}
CXXFLAGS = ${CXXFLAGS}
.PHONY: default srs srs_ingest_hls
default:
END
上面的代码 主要是指定编译选项, 有几个 重点
1,指定 编译选项 调试级别(GDBDebug),警告(WarnLevel),C++标准(CppStd)
2,使用 Gprof 或者 Gperf 做性能分析,
推荐阅读 《Gprof 性能分析》,《Gperf 性能分析》
最后就是 输出这些变量到 makefile
文件。
130 ~ 197 行 主要是 赋值 SrsLinkOptions
变量,link 选项,不做分析。
从 200 行 sehll 代码开始,就是重点了,主要是 编译 SRS自身 的模块代码。
# 198 ~ 342 行
#####################################################################################
# Modules, compile each module, then link to binary
#
#Core, depends only on system apis.
MODULE_ID="CORE"
MODULE_DEPENDS=()
ModuleLibIncs=(${SRS_OBJS_DIR})
MODULE_FILES=("srs_core" "srs_core_version4" "srs_core_autofree" "srs_core_performance"
"srs_core_time")
CORE_INCS="src/core"; MODULE_DIR=${CORE_INCS} . auto/modules.sh
CORE_OBJS="${MODULE_OBJS[@]}"
# 后续代码逻辑类似,省略....
上面的代码主要有一个重点 ,就是执行 auto/modules.sh
来生成 模块代码的 makefile文件。
MODULE_DIR=${CORE_INCS} . auto/modules.sh
这句 shell 命令,我也不太明白,中间的 . 是什么意思,埋个坑,后面填。
补充: shell 的语法是 用 空格 或者 ;
隔开不同的命令。
所以上面 是两个命令。
MODULE_DIR=${CORE_INCS}
. auto/modules.sh
前面的 .
是 source
命令的另一种写法,推荐阅读《Linux下source命令详解》
INCS 是 includes 的缩写,头文件包含路径。
后面的 210 ~ 252 行代码,都是 类似的 逻辑,生成 模块代码的 makefile文件。
总结一下,SRS 自身有 4 个模块,分别是。
CORE
应该是核心模块KERNEL
应该是内核模块PROTOCOL
应该是协议模块SRT
这个模块应该是 对libsrt
库的封装app
功能封装模块,集群,回源之类的功能。server
跟main
模块,configure里面把这两个分成独立的 modules ,但是可以直接理解为 main 入口就行。
这 6 个模块都有各自的文件夹,如图:
继续 分析 configure (shell脚本)
343 ~ 438 行 应该是 为了 link 出来 srs 可执行文件,做一些变量赋值的准备工作,库依赖定义之类的。
# 439 ~ 449 行
#####################################################################################
# generate colorful summary script
. auto/summary.sh
#####################################################################################
# makefile
echo "Generate Makefile"
# backup old makefile.
rm -f ${SRS_WORKDIR}/${SRS_MAKEFILE}.bk &&
mv ${SRS_WORKDIR}/${SRS_MAKEFILE} ${SRS_WORKDIR}/${SRS_MAKEFILE}.bk
又有一个 . ,这个还是 source
命令的缩写, summary.sh
是打印总结信息。然后 把 makefile 重命名成 makefile.bk 。
449 行 后面的逻辑 主要有是以下2点。
1,把之前的 shell 变量,丢进去 生成 makefile 文件。
2,创建各种目录,为 make 跟 运行 srs做准备。
configure shell 脚本分析完毕,不过还有一个 重点, configure 会生成两个 makefile 文件,trunck/Makefile
跟 trunck/objs/Makefile
。
trunck/Makefile
是主 makefile, objs 目录下的应该是被 trunck/Makefile
引入的。
trunck/Makefile
里面的规则应该会用到 trunck/objs/Makefile
makefile 的编译逻辑,请看 《SRS4.0源码分析-makefile》
©版权所属:知识星球:弦外之音,QQ:2338195090。
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1。