【问题标题】:Creating a shared library that statically includes ffmpeg创建一个静态包含 ffmpeg 的共享库
【发布时间】:2017-10-08 11:05:49
【问题描述】:

我很难尝试创建一个将 ffmpeg 库“烘焙”为静态库的共享库。

考虑以下目录架构:

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)

我已经走了很长一段路(请参阅Including objects to a shared library from a C++ archive (.a))并且库可以这样编译:(为简洁起见,省略了[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

但问题仍然存在。

我已经成功创建了一个共享库,它“烘焙”那些 .a 档案,即它只是动态地依赖于 ffmpeg 库,并且不存在此类问题。

我很困惑..我是否误解了一些基本的东西,忘记了一些烦人的链接选项,或者两者兼而有之?感谢您的帮助!

【问题讨论】:

    标签: c++ ffmpeg shared-libraries static-libraries


    【解决方案1】:

    您需要将您的共享库与 ffmpeg 所需的第 3 方/系统库链接:libbz2、libva、libxcb、libass、freetype2 等。实际列表应该在 ffmpeg 分发/构建工件(automake 的 .pc 文件)中的某个位置

    ignore-all 不是一个好主意;您的应用程序可能运行正常,但这些未解决的项目仍然存在;一旦撞到其中任何一个,它就会崩溃。我的猜测是,它们中的大多数永远都不会被击中,因为它们是用于 libavdevice 的,你可能甚至没有使用它,但仍然是个坏主意。另外,检查你是否真的需要那个 libavdevice 库——如果你去掉那个库,你可能会稍微修剪一下所需的库列表。

    【讨论】:

    • 尝试删除 libavdevice,但没有解决问题。那么,从静态编译的“.a”档案(烘焙到我的共享库中)到另一个库的任何引用都将被破坏..?即,“依赖链”通常会在链中有静态库时被破坏?这是一些讨论 ..stackoverflow.com/questions/7841920/… ..关于 ffmpeg 的配置脚本以创建(几乎)没有依赖关系的库的任何提示?
    • ffmpeg 作为一个静态库,对归档文件中没有明确存在的其他库有很多依赖;任何具有外部引用的静态库都是这种情况。猜猜这就是你所说的依赖链断开的意思?无论如何,您需要手动将您的共享库与这些依赖项链接(或使用 automake/cmake/whatever 可以为您完成的构建系统)。删除 libavdevice 不会删除所有这些依赖项,但会删除一些(至少对 jack、oss、pulseaudio)。您可以在没有大多数库的情况下构建 ffmpeg,但这将是非常小的构建
    • 所以在创建我的共享库时,我必须把所有链接到,比如,pulseaudio、oss、vdpau-thingies 等的“-L”和“-l”开关放在那里?好的..谢谢!
    【解决方案2】:

    告诉链接器在创建可执行文件时忽略未解析的符号就可以了:

    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 运行。

    【讨论】:

      猜你喜欢
      • 2021-02-26
      • 2011-01-09
      • 2021-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多