创建静态包含 ffmpeg 的共享库
Creating a shared library that statically includes ffmpeg
我很难尝试创建一个将 ffmpeg 库 "baked in" 作为静态库的共享库。
考虑以下目录模式:
include/
my own .h files
ext/
ffmpeg .h files
lib/
libav*.a archive files (softlinks to the actual .a files)
libValkka.so (my shared library)
test/
mytest.cpp
bin/
(binaries appear here)
我已经走了很长一段路(参见 )并且库编译正常:(为简洁起见省略了 [STUFF])
/usr/bin/c++ -fPIC -std=c++14 -pthread -Iinclude/ext -I/usr/include/libdrm -g -shared -Wl,-soname,libValkka.so -o lib/libValkka.so CMakeFiles/Valkka.dir/src/avthread.cpp.o CMakeFiles/Valkka.dir/src/opengl.cpp.o CMakeFiles/Valkka.dir/src/openglthread.cpp.o [STUFF] CMakeFiles/Valkka.dir/src/filters.cpp.o -lX11 -lGLEW -lGLU -lGL -Wl,--allow-multiple-definition -Wl,-Bsymbolic -Wl,--whole-archive -Wreorder lib/libavdevice.a lib/libavfilter.a lib/libavformat.a lib/libavcodec.a lib/libavutil.a lib/libswscale.a lib/libswresample.a -Wl,--no-whole-archive
但是,在创建可执行文件时 - 他们的源代码不使用任何 ffmpeg api(只是我自己的 api) - 使用:
c++ -std=c++14 -pthread -Iinclude -Iinclude/ext -Llib test/mytest.cpp -lValkka -g -o bin/mytest
我收到一堆关于缺少 ffmpeg 依赖项的错误。不是所有东西都不见了,只是一些奇怪的东西:
lib/libValkka.so: undefined reference to `pa_stream_get_index'
lib/libValkka.so: undefined reference to `deflateInit_'
lib/libValkka.so: undefined reference to `pa_stream_get_state'
lib/libValkka.so: undefined reference to `lzma_stream_decoder'
lib/libValkka.so: undefined reference to `BZ2_bzDecompress'
lib/libValkka.so: undefined reference to `vaInitialize'
lib/libValkka.so: undefined reference to `pa_stream_unref'
lib/libValkka.so: undefined reference to `deflateInit2_'
lib/libValkka.so: undefined reference to `snd_pcm_close'
...
lib/libValkka.so: undefined reference to `vaGetDisplayDRM'
lib/libValkka.so: undefined reference to `vaMaxNumEntrypoints'
lib/libValkka.so: undefined reference to `uncompress'
lib/libValkka.so: undefined reference to `pa_stream_drop'
lib/libValkka.so: undefined reference to `pa_context_connect'
lib/libValkka.so: undefined reference to `FT_Get_Kerning'
lib/libValkka.so: undefined reference to `ass_free_track'
lib/libValkka.so: undefined reference to `pa_operation_unref'
lib/libValkka.so: undefined reference to `FT_Stroker_Done'
lib/libValkka.so: undefined reference to `vaTerminate'
lib/libValkka.so: undefined reference to `ass_new_track'
lib/libValkka.so: undefined reference to `jack_client_close'
...
lib/libValkka.so: undefined reference to `xcb_xfixes_query_version'
lib/libValkka.so: undefined reference to `xcb_shape_rectangles'
lib/libValkka.so: undefined reference to `pa_mainloop_free'
lib/libValkka.so: undefined reference to `snd_device_name_hint'
lib/libValkka.so: undefined reference to `vaCreateImage'
lib/libValkka.so: undefined reference to `vaBeginPicture'
lib/libValkka.so: undefined reference to `DtsSetColorSpace'
lib/libValkka.so: undefined reference to `vaDestroyConfig'
lib/libValkka.so: undefined reference to `pa_stream_writable_size'
lib/libValkka.so: undefined reference to `snd_pcm_hw_params_get_buffer_size_max'
lib/libValkka.so: undefined reference to `ass_read_file'
这真令人沮丧,尤其是当我看到共享库中包含这些名称时...!
nm lib/libValkka.so | grep "vaBeginPicture"
给予
U vaBeginPicture
等我认为这可能是关于存档 .a 文件的依赖顺序的问题,并且还尝试了:
..... -Wl,--allow-multiple-definition -Wl,-Bsymbolic -Wl,--start-group -Wl,--whole-archive -Wreorder lib/libavdevice.a lib/libavfilter.a lib/libavformat.a lib/libavcodec.a lib/libavutil.a lib/libswscale.a lib/libswresample.a -Wl,--no-whole-archive -Wl,--end-group
但问题依旧。
我已经成功创建了一个共享库,它不 "bake in"那些.a档案,即动态依赖于ffmpeg库,没有这样的问题.
我很困惑..我是不是误解了一些基本的东西,忘记了一些烦人的链接选项,或者两者都有?感谢帮助!
告诉链接器在创建可执行文件时忽略未解析的符号就可以了:
c++ -std=c++14 -pthread -Iinclude -Iinclude/ext -Llib test/mytest.cpp -lValkka -g -o bin/mytest -Wl,--unresolved-symbols=ignore-all
生成的可执行文件也运行正常。
但是..使用这样的链接器标志让我感到不快。也许有更好的选择?为什么一开始就找不到这些符号?
编辑
根据 Andrey 的建议,我借助 ffmpeg 的配置脚本从 ffmpeg 中删除了所有外部库。这是一个有点尴尬的过程,所以我创建了一个很好的 python 脚本来自动完成它。这可能有点矫枉过正,但就是这样:
#!/usr/bin/python3
"""
* Creates script "run_configure.bash" that launches ffmpeg's "configure" script with correct parameters (enabling/disabling stuff)
* Run in the same directory where you have ffmpeg's configure script
"""
import subprocess
import os
import re
def features(switch, adstring="", remove=[]):
p=subprocess.Popen(["./configure",switch],stdout=subprocess.PIPE)
st=p.stdout.read()
fst=""
for s in st.split():
ss=s.decode("utf-8")
ok=True
for rem in remove:
if (ss.find(rem)!=-1):
ok=False
if ok: fst+=adstring+ss+" "
return fst
def disable_external():
p=subprocess.Popen(["./configure","-h"],stdout=subprocess.PIPE)
st=p.stdout.read().decode("utf-8")
# find some text tags from the configure output:
# i1=st.find("External library support:")
i1=st.find("themselves, not all their features will necessarily be usable by FFmpeg.")
i2=st.find("Toolchain options:")
st=st[i1:i2]
""" # debugging ..
print(st)
stop
"""
p=re.compile('--(enable|disable)-(\S*)')
switches=[]
for sw in p.findall(st):
if (sw[1] not in switches):
# print(sw[1]) # debugging
switches.append(sw[1])
fst=""
for sw in switches:
fst+="--disable-"+sw+" "
return fst
st ="./configure "
st+="--disable-everything --disable-doc --disable-gpl --disable-pthreads --enable-static --enable-shared "
st+= disable_external()
st+= features("--list-decoders",adstring="--enable-decoder=", remove=["vdpau","crystalhd","zlib"])
st+= features("--list-muxers", adstring="--enable-muxer=")
st+= features("--list-demuxers",adstring="--enable-demuxer=")
st+= features("--list-parsers", adstring="--enable-parser=")
f=open("run_configure.bash","w")
f.write("#!/bin/bash\n")
f.write(st+"\n")
f.close()
os.system("chmod a+x run_configure.bash")
print("\nNext run ./run_configure.bash\n")
"""
For cleaning up .a and .so files, use
find -name *.a -exec ls {} \;
find -name *.so* -exec ls {} \;
"""
希望有人觉得它有用。 运行 与 python3.
您需要 link 您的共享库与 ffmpeg 所需的第三个 party/system 库:libbz2、libva、libxcb、libass、freetype2 等。实际列表应该在 ffmpeg 中的某处 distribution/build 工件(automake 的 .pc 文件)
忽略全部不是一个好主意;您的应用程序可能 运行 OK,但这些未解决的项目仍然存在;一旦碰到其中任何一个,它就会崩溃。我的猜测是它们中的大多数永远不会被击中,因为它们是用于您可能甚至不会使用的 libavdevice 的,但这仍然是一个坏主意。另外,检查你是否真的需要那个 libavdevice 库——如果你去掉那个库,你可能 trim 需要的库列表很多。
我很难尝试创建一个将 ffmpeg 库 "baked in" 作为静态库的共享库。
考虑以下目录模式:
include/
my own .h files
ext/
ffmpeg .h files
lib/
libav*.a archive files (softlinks to the actual .a files)
libValkka.so (my shared library)
test/
mytest.cpp
bin/
(binaries appear here)
我已经走了很长一段路(参见
/usr/bin/c++ -fPIC -std=c++14 -pthread -Iinclude/ext -I/usr/include/libdrm -g -shared -Wl,-soname,libValkka.so -o lib/libValkka.so CMakeFiles/Valkka.dir/src/avthread.cpp.o CMakeFiles/Valkka.dir/src/opengl.cpp.o CMakeFiles/Valkka.dir/src/openglthread.cpp.o [STUFF] CMakeFiles/Valkka.dir/src/filters.cpp.o -lX11 -lGLEW -lGLU -lGL -Wl,--allow-multiple-definition -Wl,-Bsymbolic -Wl,--whole-archive -Wreorder lib/libavdevice.a lib/libavfilter.a lib/libavformat.a lib/libavcodec.a lib/libavutil.a lib/libswscale.a lib/libswresample.a -Wl,--no-whole-archive
但是,在创建可执行文件时 - 他们的源代码不使用任何 ffmpeg api(只是我自己的 api) - 使用:
c++ -std=c++14 -pthread -Iinclude -Iinclude/ext -Llib test/mytest.cpp -lValkka -g -o bin/mytest
我收到一堆关于缺少 ffmpeg 依赖项的错误。不是所有东西都不见了,只是一些奇怪的东西:
lib/libValkka.so: undefined reference to `pa_stream_get_index'
lib/libValkka.so: undefined reference to `deflateInit_'
lib/libValkka.so: undefined reference to `pa_stream_get_state'
lib/libValkka.so: undefined reference to `lzma_stream_decoder'
lib/libValkka.so: undefined reference to `BZ2_bzDecompress'
lib/libValkka.so: undefined reference to `vaInitialize'
lib/libValkka.so: undefined reference to `pa_stream_unref'
lib/libValkka.so: undefined reference to `deflateInit2_'
lib/libValkka.so: undefined reference to `snd_pcm_close'
...
lib/libValkka.so: undefined reference to `vaGetDisplayDRM'
lib/libValkka.so: undefined reference to `vaMaxNumEntrypoints'
lib/libValkka.so: undefined reference to `uncompress'
lib/libValkka.so: undefined reference to `pa_stream_drop'
lib/libValkka.so: undefined reference to `pa_context_connect'
lib/libValkka.so: undefined reference to `FT_Get_Kerning'
lib/libValkka.so: undefined reference to `ass_free_track'
lib/libValkka.so: undefined reference to `pa_operation_unref'
lib/libValkka.so: undefined reference to `FT_Stroker_Done'
lib/libValkka.so: undefined reference to `vaTerminate'
lib/libValkka.so: undefined reference to `ass_new_track'
lib/libValkka.so: undefined reference to `jack_client_close'
...
lib/libValkka.so: undefined reference to `xcb_xfixes_query_version'
lib/libValkka.so: undefined reference to `xcb_shape_rectangles'
lib/libValkka.so: undefined reference to `pa_mainloop_free'
lib/libValkka.so: undefined reference to `snd_device_name_hint'
lib/libValkka.so: undefined reference to `vaCreateImage'
lib/libValkka.so: undefined reference to `vaBeginPicture'
lib/libValkka.so: undefined reference to `DtsSetColorSpace'
lib/libValkka.so: undefined reference to `vaDestroyConfig'
lib/libValkka.so: undefined reference to `pa_stream_writable_size'
lib/libValkka.so: undefined reference to `snd_pcm_hw_params_get_buffer_size_max'
lib/libValkka.so: undefined reference to `ass_read_file'
这真令人沮丧,尤其是当我看到共享库中包含这些名称时...!
nm lib/libValkka.so | grep "vaBeginPicture"
给予
U vaBeginPicture
等我认为这可能是关于存档 .a 文件的依赖顺序的问题,并且还尝试了:
..... -Wl,--allow-multiple-definition -Wl,-Bsymbolic -Wl,--start-group -Wl,--whole-archive -Wreorder lib/libavdevice.a lib/libavfilter.a lib/libavformat.a lib/libavcodec.a lib/libavutil.a lib/libswscale.a lib/libswresample.a -Wl,--no-whole-archive -Wl,--end-group
但问题依旧。
我已经成功创建了一个共享库,它不 "bake in"那些.a档案,即动态依赖于ffmpeg库,没有这样的问题.
我很困惑..我是不是误解了一些基本的东西,忘记了一些烦人的链接选项,或者两者都有?感谢帮助!
告诉链接器在创建可执行文件时忽略未解析的符号就可以了:
c++ -std=c++14 -pthread -Iinclude -Iinclude/ext -Llib test/mytest.cpp -lValkka -g -o bin/mytest -Wl,--unresolved-symbols=ignore-all
生成的可执行文件也运行正常。
但是..使用这样的链接器标志让我感到不快。也许有更好的选择?为什么一开始就找不到这些符号?
编辑
根据 Andrey 的建议,我借助 ffmpeg 的配置脚本从 ffmpeg 中删除了所有外部库。这是一个有点尴尬的过程,所以我创建了一个很好的 python 脚本来自动完成它。这可能有点矫枉过正,但就是这样:
#!/usr/bin/python3
"""
* Creates script "run_configure.bash" that launches ffmpeg's "configure" script with correct parameters (enabling/disabling stuff)
* Run in the same directory where you have ffmpeg's configure script
"""
import subprocess
import os
import re
def features(switch, adstring="", remove=[]):
p=subprocess.Popen(["./configure",switch],stdout=subprocess.PIPE)
st=p.stdout.read()
fst=""
for s in st.split():
ss=s.decode("utf-8")
ok=True
for rem in remove:
if (ss.find(rem)!=-1):
ok=False
if ok: fst+=adstring+ss+" "
return fst
def disable_external():
p=subprocess.Popen(["./configure","-h"],stdout=subprocess.PIPE)
st=p.stdout.read().decode("utf-8")
# find some text tags from the configure output:
# i1=st.find("External library support:")
i1=st.find("themselves, not all their features will necessarily be usable by FFmpeg.")
i2=st.find("Toolchain options:")
st=st[i1:i2]
""" # debugging ..
print(st)
stop
"""
p=re.compile('--(enable|disable)-(\S*)')
switches=[]
for sw in p.findall(st):
if (sw[1] not in switches):
# print(sw[1]) # debugging
switches.append(sw[1])
fst=""
for sw in switches:
fst+="--disable-"+sw+" "
return fst
st ="./configure "
st+="--disable-everything --disable-doc --disable-gpl --disable-pthreads --enable-static --enable-shared "
st+= disable_external()
st+= features("--list-decoders",adstring="--enable-decoder=", remove=["vdpau","crystalhd","zlib"])
st+= features("--list-muxers", adstring="--enable-muxer=")
st+= features("--list-demuxers",adstring="--enable-demuxer=")
st+= features("--list-parsers", adstring="--enable-parser=")
f=open("run_configure.bash","w")
f.write("#!/bin/bash\n")
f.write(st+"\n")
f.close()
os.system("chmod a+x run_configure.bash")
print("\nNext run ./run_configure.bash\n")
"""
For cleaning up .a and .so files, use
find -name *.a -exec ls {} \;
find -name *.so* -exec ls {} \;
"""
希望有人觉得它有用。 运行 与 python3.
您需要 link 您的共享库与 ffmpeg 所需的第三个 party/system 库:libbz2、libva、libxcb、libass、freetype2 等。实际列表应该在 ffmpeg 中的某处 distribution/build 工件(automake 的 .pc 文件)
忽略全部不是一个好主意;您的应用程序可能 运行 OK,但这些未解决的项目仍然存在;一旦碰到其中任何一个,它就会崩溃。我的猜测是它们中的大多数永远不会被击中,因为它们是用于您可能甚至不会使用的 libavdevice 的,但这仍然是一个坏主意。另外,检查你是否真的需要那个 libavdevice 库——如果你去掉那个库,你可能 trim 需要的库列表很多。