需求:
1. 純靜態編譯ffmpeg ,即ldd ./ffmpeg 的結果是:not a dynamic executable
2. ?修改ffmpeg 項目,添加自定義功能庫
3. 自定義庫由c++實現,要求能被純c的ffmpeg項目調用
4. 自定義庫必須使用g++ 的一些高級特性編譯,要求g++支持c++11
5. 自定義庫使用了pthread庫?和openmp?庫
6. 自定義庫使用了opencv 3.0.0庫,
7. 禁用所有的圖形顯示庫x11,xcb,聲音設備avdevice等等,靜態鏈接這些庫,會很痛苦。
動手之前需要注意:
A.?ffmpeg.org (CentOS或?Ubuntu)的方法是不能達到需求1的,因為它大量使用包管理軟件(yum 或apt-get)安裝一些ffmpeg的依賴庫,而這些依賴庫大多是動態版本(.so.*) 。這就使得編譯ffmpeg時,無法靜態鏈接這些依賴庫。因而,非開發工具(如gcc g++ pkg-config aotoconf etc )的依賴庫(如ass,freetype,sdl theora, jpeg png,etc),需要手動下載它們的源碼(以及這些依賴庫的依賴庫),然后編譯得到靜態庫(.a)。一般來說,這些依賴庫多數是configure 配置,然后make,make install。
./configure ***?--enable-shared=no --enable-static=yes?--with-***=/dir
B.自定義功能庫也類似于上述方法寫好myfunc.cpp,然后g++編譯,ar打包成.a。但是由于我們寫好的cpp要求c++11特性,而CentOS6.5上的gcc/g++版本為4.4.7不支持c++11。因而,需要安裝gcc4.8以上版本。從repo里面無法安裝較新的gcc的話,只能自行下載gcc源碼,自行編譯了。然而發現了一個第三方的編譯好的工具鏈devtool3,它提供了gcc 4.9.2 以及配套的binutils工具。然而,不要急,先不要安裝它,看完本注意事項。
C.要求c++打包的庫能夠被ffmpeg的項目鏈接,要求libstdc++.a (-lstdc++);能夠使用openmp,要求libgomp.a ( -fopenmp); libstdc++.a可以通過yum install libstdc++-static得到,但是libgomp.a則沒有對應的方法。
綜合B和C的注意事項,我們應該自行編譯gcc,而不是使用系統自帶的gcc或者yum apt-get下載安裝的,因為自行編譯gcc能夠直接得到libstdc++.a和libgomp.a這些靜態庫。我選用的版本是gcc4.8.4,同樣地配置它編譯出靜態庫。配套的Binutils也需要重新編譯。
D. glibc是GNU的標準C庫實現,如果要靜態鏈接glibc這些底層的庫_——libc.a,libm.a,librt.a,libdl.a,libpthread.a ,需要安裝glibc的靜態版本
#yum install glibc-static,?
#whereis libc.a(找到路徑)
#cp 路徑/libc.a ~mydir/(其它4個庫類似,重新拷貝到一個新的位置,以防鏈接時優先選擇動態鏈接,當然把這個路徑放在LDFLAGS最前面)
E.opencv 和ffmpeg在配置階段(分別使用cmake和configure),務必關閉所有的與圖形IO相關的依賴,因為圖形庫的靜態版本,太難找了,依賴關系特別冗長繁雜。
F. 最終鏈接ffmpeg時候,由于ffmpeg依賴了一些庫如x264,x265,freetype等,它們各自依賴了glibc的一些庫如librt,libm,libc,libdl。因而原始命令(#make -n|grep ffmpeg_g)中glibc的一些庫(libm,libc,librt,libdl,libpthread)被反復調用,分布于多個地方,如下:
gcc ?-Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -L/home/ffmpeg/ffmpeg_sjtu/lib ?-Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample ??-o ffmpeg_g cmdutils.o ffmpeg_opt.o ffmpeg_filter.o ffmpeg.o ??-lavdevice -lavfilter -lavformat -lavcodec -lpostproc -lswresample -lswscale -lavutil ?-L/home/ffmpeg/ffmpeg_build/lib -lx265 -lstdc++-lm -lrt -ldl?-L/home/ffmpeg/ffmpeg_build/lib -lx264?-lpthread -lm -ldl?-L/home/ffmpeg/ffmpeg_build/lib -lvpx -lm -lpthread -L/home/ffmpeg/ffmpeg_build/lib -lvpx -lm -lpthread -L/home/ffmpeg/ffmpeg_build/lib -lvpx?-lm -lpthread?-L/home/ffmpeg/ffmpeg_build/lib -lvpx -lm -lpthread -ltheoraenc -ltheoradec -logg -L/home/ffmpeg/ffmpeg_build/lib -lopus -lm -lmp3lame -L/home/ffmpeg/ffmpeg_build/lib -lfribidi -L/home/ffmpeg/ffmpeg_build/lib -lfreetype -lz -L/home/ffmpeg/ffmpeg_build/lib -lfontconfig -lxml2 -llzma -lm -lfreetype -lz -L/home/ffmpeg/ffmpeg_build/lib -lfdk-aac -lm -L/home/ffmpeg/ffmpeg_build/lib -lass -lharfbuzz -lfontconfig -lenca -lfribidi -lxml2 -llzma -lm -lfreetype -lz -lm -llzma -lbz2 -lz?-pthread -lrt?-lstdc++ ?????-L/home/ffmpeg/sjtu_fruc/lib -lsjtu_fruc ?-fopenmp???-L/usr/local/lib -L/usr/local/share/OpenCV/3rdparty/lib -lopencv_shape -lopencv_stitching -lopencv_objdetect -lopencv_superres -lopencv_videostab -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_video -lopencv_photo -lopencv_ml -lopencv_imgproc -lopencv_flann -lopencv_core -lopencv_hal -lzlib -llibjpeg -llibwebp -llibpng -llibtiff -llibjasper -ltbb -lippicv?-lstdc++?-ldl -lm -lpthread -lrt ??
因此,為了能夠靜態鏈接glibc的幾個庫,需要手動修改這條最終的鏈接命令:把所有glibc的庫放到最后,以如下方式:
-lm -lrt -ldl ?-lm -lpthread -lrt ??-static -lc
?
注意,-static -lc (libc.a)必須放到最后(pthread之后),因為pthread和c庫有函數重定義的沖突。
?
這條語句最終為:
printf "LD\t%s\n" ffmpeg_g; gcc ?-Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -L/home/ffmpeg/ffmpeg_sjtu/lib ?-Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample ??-o ffmpeg_g cmdutils.o ffmpeg_opt.o ffmpeg_filter.o ffmpeg.o ??-lavdevice -lavfilter -lavformat -lavcodec -lpostproc -lswresample -lswscale -lavutil ?-L/home/ffmpeg/ffmpeg_build/lib -lx265 -L/home/ffmpeg/ffmpeg_build/lib -lx264 -L/home/ffmpeg/ffmpeg_build/lib -lvpx ?-L/home/ffmpeg/ffmpeg_build/lib -lvpx ?-L/home/ffmpeg/ffmpeg_build/lib -lvpx ?-L/home/ffmpeg/ffmpeg_build/lib -lvpx -ltheoraenc -ltheoradec -logg -L/home/ffmpeg/ffmpeg_build/lib -lopus -lmp3lame -L/home/ffmpeg/ffmpeg_build/lib -lfribidi -L/home/ffmpeg/ffmpeg_build/lib -lfreetype -lz -L/home/ffmpeg/ffmpeg_build/lib -lfontconfig -lxml2 -llzma -lfreetype -lz -L/home/ffmpeg/ffmpeg_build/lib -lfdk-aac -L/home/ffmpeg/ffmpeg_build/lib -lass -lharfbuzz -lfontconfig -lenca -lfribidi -lxml2 -llzma -lfreetype -lz ?-llzma -lbz2 -lz ??-L/home/ffmpeg/sjtu_fruc/lib -lsjtu_fruc ?-fopenmp ??-L/usr/local/lib -L/usr/local/share/OpenCV/3rdparty/lib -lopencv_shape -lopencv_stitching -lopencv_objdetect -lopencv_superres -lopencv_videostab -lopencv_calib3d -lopencv_features2d -lopencv_highgui -lopencv_videoio -lopencv_imgcodecs -lopencv_video -lopencv_photo -lopencv_ml -lopencv_imgproc -lopencv_flann -lopencv_core -lopencv_hal -lzlib -llibjpeg -llibwebp -llibpng -llibtiff -llibjasper -ltbb -lippicv -lstdc++?-lm -lrt -ldl ?-lm -lpthread -lrt ??-static -lc
盡管它執行會報出一些warnning,但是,不影響生成ffmpeg_g可執行文件。
然后執行,
#cp ffmpeg_g ffmpeg
#strip ffmpeg
即可
測試ffmpeg