目的
解决一个项目同时存在多版本ffmpeg出现编译错误
思路:通过修改库名后再通过dlopen方式去动态加载,进而避免符号冲突
修改方法(老,新方法见下方)
- libavcodec/avcodecres.rc
Line 43 VALUE “InternalName”, “libavcodec_target” - libavcodec/libutvideodec.cpp
Line 114 utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), “libavcodec_target”) - libavcodec/libutvideoenc.cpp
Line 110 utv->codec = CCodec::CreateInstance(UNFCC(avctx->codec_tag), “libavcodec_target”) - libavcodec/Makefile
NAME = avcodec_target - libavutil/Makefile
NAME = avutil_target - 将libavcodec.v重命名为libavcodec_target.v
- 将libavutil.v重命名为libavutil_target.v
以上修改基于ffmpeg 2.3.3修改,生成目标为:
libavcodec_target.so
libavcodec_target.a
libavutil_target.so
libavutil_target.a
时隔一个月左右,上述方法仍然爆出了符号冲突的问题,琢磨一段时间后得到了如下方法。
最近琢磨出来了新方法
简单说一下这个方法,原理是执行完官方的make后自己去再利用生成的*.o生成新的库,方法虽然看似笨拙,但实际效果却比前面的方法更好,说一下前面的方法为何不好(说明一下,当前问题仅用到libavcodec.so和libavutil.so):
- 官方编译出来后libavcodec.so会依赖libavutil.so,但经过前面的方法编译出来后相应的依赖关系已不存在,通过make -n命令查看后发现对应的依赖关系确实没了,由于ffmpeg官方makefile分析难度较大,所以本人研究后发现无力去修改makefile,只能寻求其他方式。
- 基于老方法编译得到的结果会出现多套库仍存在符号冲突的问题,只能解决多套ffmpeg库共存时的编译问题,这样在调用时仍存在较大隐患,即便是因为使用了dlopen也会因为库之间的依赖关系不存在导致在查找符号时找到其他库里去。
新方法步骤
- 思路:借用官方的make得到的*.o,配合make -n命令获取到ffmpeg在最后ld阶段都干了些什么,借用它的命令将两套库的中间文件合并到一条命令下:
gcc -shared -Wl,soname, xxx.so -Lxxx -Wl,rpath-link=xxx -o libTarget.so libavutil/***.o libavcodec/***.o -lX11 -lasound -lm -pthread -lrt
其中***.o表示所有的中间文件,此处仅列出部分。
如果完全按照make -n得到的命令可能会出现提示ld错误 VERSiON script,此时可以将命令中的-Wl,–version-script,libavcodec/libavcodec.ver去掉,我在编译的时候还遇到另外一个问题,提示某个符号冲定义,找到源码位置发现只是引用了该符号的头文件,然后将中间文件在命令中去除,继续编译就能正常生成一个新的库,使用新库的好处是只需要一个库能包含原先多个库的符号,再配合dlopen就不会出现在使用动态加载了仍然出现符号冲突的问题。
通篇文章只有文字,公司原因源码内容不能公开,但思路还是比较清晰且本身方法简单,只是可能不会想到用这种方式,在此记录希望有用的朋友能够用得上。
记住,此处最关键的是make -n命令去分析ffmpeg的编译过程,不然按照官方makefile的书写我是没那个能力将过程分析透彻。
稍微理一下ffmpeg编译的文件之间的关系:
- ./configure -prefix=/usr/lib32 --各种裁剪选项,执行后会生成config.mak,该文件定义了一些基本变量,比较关键的是一些gcc会用到的编译选项,这些变量会在其他地方使用
- libriary.mak/common.mak里定义了编译过程,比如ld的过程,install的过程。
重要的暂且想到这么两点,以后碰到了更重要的再继续记录。