SRS 的社群来了,想加入微信社群的朋友请购买《SRS原理》电子书,里有更高级的内容与答疑服务。
本文采用的 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》
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://sigusoft.com/clion/3694.html