使用 clang 编译 FFmpeg 一、 准备工作
下载 FFmpeg、 最新版 ndk(上篇文章已经提及)
整理下文件(当然用你喜欢的就行, 只要配置的路径对就没问题)
二、 明确使用 target-os=android, 使用 clang 进行编译 2.1 明确 clang 编译环境的位置 1 2 # 在相应 ndk 的这个目录下 ndk/toolchains/llvm/prebuilt/darwin-x86_64
让我们看看 clang 等编译工具的内容(bin目录)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 aarch64-linux-android-addr2line i686-linux-android-gprof aarch64-linux-android-ar i686-linux-android-ld aarch64-linux-android-as i686-linux-android-ld.bfd aarch64-linux-android-c++filt i686-linux-android-ld.gold aarch64-linux-android-dwp i686-linux-android-nm aarch64-linux-android-elfedit i686-linux-android-objcopy aarch64-linux-android-gprof i686-linux-android-objdump aarch64-linux-android-ld i686-linux-android-ranlib aarch64-linux-android-ld.bfd i686-linux-android-readelf aarch64-linux-android-ld.gold i686-linux-android-size aarch64-linux-android-nm i686-linux-android-strings aarch64-linux-android-objcopy i686-linux-android-strip aarch64-linux-android-objdump i686-linux-android16-clang aarch64-linux-android-ranlib i686-linux-android16-clang++ aarch64-linux-android-readelf i686-linux-android17-clang aarch64-linux-android-size i686-linux-android17-clang++ aarch64-linux-android-strings i686-linux-android18-clang aarch64-linux-android-strip i686-linux-android18-clang++ aarch64-linux-android21-clang i686-linux-android19-clang aarch64-linux-android21-clang++ i686-linux-android19-clang++ aarch64-linux-android22-clang i686-linux-android21-clang aarch64-linux-android22-clang++ i686-linux-android21-clang++ aarch64-linux-android23-clang i686-linux-android22-clang aarch64-linux-android23-clang++ i686-linux-android22-clang++ aarch64-linux-android24-clang i686-linux-android23-clang aarch64-linux-android24-clang++ i686-linux-android23-clang++ aarch64-linux-android26-clang i686-linux-android24-clang aarch64-linux-android26-clang++ i686-linux-android24-clang++ aarch64-linux-android27-clang i686-linux-android26-clang aarch64-linux-android27-clang++ i686-linux-android26-clang++ aarch64-linux-android28-clang i686-linux-android27-clang aarch64-linux-android28-clang++ i686-linux-android27-clang++ aarch64-linux-android29-clang i686-linux-android28-clang aarch64-linux-android29-clang++ i686-linux-android28-clang++ arm-linux-androideabi-addr2line i686-linux-android29-clang arm-linux-androideabi-ar i686-linux-android29-clang++ arm-linux-androideabi-as ld.lld arm-linux-androideabi-c++filt llvm-ar arm-linux-androideabi-dwp llvm-as arm-linux-androideabi-elfedit llvm-config arm-linux-androideabi-gprof llvm-cov arm-linux-androideabi-ld llvm-dis arm-linux-androideabi-ld.bfd llvm-link arm-linux-androideabi-ld.gold llvm-modextract arm-linux-androideabi-nm llvm-nm arm-linux-androideabi-objcopy llvm-objcopy arm-linux-androideabi-objdump llvm-profdata arm-linux-androideabi-ranlib llvm-readobj arm-linux-androideabi-readelf llvm-strip arm-linux-androideabi-size llvm-symbolizer arm-linux-androideabi-strings pkg-config arm-linux-androideabi-strip sancov armv7a-linux-androideabi16-clang sanstats armv7a-linux-androideabi16-clang++ scan-build armv7a-linux-androideabi17-clang scan-view armv7a-linux-androideabi17-clang++ x86_64-linux-android-addr2line armv7a-linux-androideabi18-clang x86_64-linux-android-ar armv7a-linux-androideabi18-clang++ x86_64-linux-android-as armv7a-linux-androideabi19-clang x86_64-linux-android-c++filt armv7a-linux-androideabi19-clang++ x86_64-linux-android-dwp armv7a-linux-androideabi21-clang x86_64-linux-android-elfedit armv7a-linux-androideabi21-clang++ x86_64-linux-android-gprof armv7a-linux-androideabi22-clang x86_64-linux-android-ld armv7a-linux-androideabi22-clang++ x86_64-linux-android-ld.bfd armv7a-linux-androideabi23-clang x86_64-linux-android-ld.gold armv7a-linux-androideabi23-clang++ x86_64-linux-android-nm armv7a-linux-androideabi24-clang x86_64-linux-android-objcopy armv7a-linux-androideabi24-clang++ x86_64-linux-android-objdump armv7a-linux-androideabi26-clang x86_64-linux-android-ranlib armv7a-linux-androideabi26-clang++ x86_64-linux-android-readelf armv7a-linux-androideabi27-clang x86_64-linux-android-size armv7a-linux-androideabi27-clang++ x86_64-linux-android-strings armv7a-linux-androideabi28-clang x86_64-linux-android-strip armv7a-linux-androideabi28-clang++ x86_64-linux-android21-clang armv7a-linux-androideabi29-clang x86_64-linux-android21-clang++ armv7a-linux-androideabi29-clang++ x86_64-linux-android22-clang bisect_driver.py x86_64-linux-android22-clang++ clang x86_64-linux-android23-clang clang++ x86_64-linux-android23-clang++ clang-check x86_64-linux-android24-clang clang-format x86_64-linux-android24-clang++ clang-tidy x86_64-linux-android26-clang clang-tidy.real x86_64-linux-android26-clang++ git-clang-format x86_64-linux-android27-clang i686-linux-android-addr2line x86_64-linux-android27-clang++ i686-linux-android-ar x86_64-linux-android28-clang i686-linux-android-as x86_64-linux-android28-clang++ i686-linux-android-c++filt x86_64-linux-android29-clang i686-linux-android-dwp x86_64-linux-android29-clang++ i686-linux-android-elfedit yasm
我们可以在这里发现不同 Android 版本和架构的编译工具。 通过查看里面的编译工具我们发现, clang、 clang++ 是不但分架构还分 Android 版本的, 而其他工具只分架构。 比如我选几个哈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 armv7a-linux-androideabi16-clang armv7a-linux-androideabi16-clang++ armv7a-linux-androideabi29-clang armv7a-linux-androideabi29-clang++ arm-linux-androideabi-addr2line arm-linux-androideabi-ar arm-linux-androideabi-as arm-linux-androideabi-c++filt arm-linux-androideabi-dwp arm-linux-androideabi-elfedit arm-linux-androideabi-gprof arm-linux-androideabi-ld arm-linux-androideabi-ld.bfd arm-linux-androideabi-ld.gold arm-linux-androideabi-nm arm-linux-androideabi-objcopy arm-linux-androideabi-objdump arm-linux-androideabi-ranlib arm-linux-androideabi-readelf arm-linux-androideabi-size arm-linux-androideabi-strings arm-linux-androideabi-strip
发现问题了吗, 前缀不一样耶。 这个问题在配置 configure 时需要特别注意。(这里知道前缀不一样就好了)
在查看 configure 时 发现如下代码:
1 2 3 4 5 6 7 8 9 10 set_default target_os if test "$target_os" = android; then cc_default="clang" fi ar_default="${cross_prefix}${ar_default}" cc_default="${cross_prefix}${cc_default}" cxx_default="${cross_prefix}${cxx_default}" nm_default="${cross_prefix}${nm_default}" pkg_config_default="${cross_prefix}${pkg_config_default}"
发现问题了吗?
如果 target-os 设置的是 Android 的话, 那么 使用的 clang 去编译呢。 我们先不管 ar_default、cc_default、cxx_default、….等等的默认值,我们先看最后几行各个工具的拼接, 发现都是 cross_prefix 去拼接的。 cross_prefix 就是我们在设置 configure 里配置的 –cross-prefix 前缀。 发现问题没, 发现问题没, 发现问题没, 我们在 2.1 中刚看到, 很明显 clang、 clang++ 的前缀和 其他工具的不一样。 所以这个地方很矛盾呀。 为了通用,我们可以定义一个参数在外部去单独设置 clang 和 clang++ 的前缀(这里我随便命名成–cross-prefix-clang)。跟设置 –cross-prefix 一样。
现在看下 ar_default、 cc_default、 cxx_default、 nm_default、 pkg_config_default等还有其他工具的默认名字, 可以在configure中全局搜索这个名字看默认值, 发现 ar_default 默认值是ar, 如果拼上前缀的话(–cross-prefix + ar),在编译工具中是存在这个工具的, 其他的也一样。 但是 clang 和 clang++ 也不行, 不存在的, 我们看到在上面已经把 cc_default=”clang”了, 但是 clang++ 还没有, 所以在上面需要手动添加一个 cxx_default=”clang++”, 这样的话(–cross-prefix-clang + clang 或者 + clang++) 才存在哦!
2.3 明确所需要的头文件和库 使用了 clang 编译就需要指定 clang 的头文件和库
1 2 使用该目录下的头文件和库, 在编写脚本时, 引入即可 /ndk/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
1 2 3 --cross-prefix=PREFIX use PREFIX for compilation tools [$cross_prefix] # 这里添加 --cross-prefix-clang=PREFIX use PREFIX for compilation clang tools [$cross_prefix]
先设置一个帮助信息呢, 规范嘛要
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 CMDLINE_SET=" $PATHS_LIST ar arch as assert_level build_suffix cc objcc cpu cross_prefix # 这里添加 cross_prefix_clang custom_allocator cxx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 set_default target_os if test "$target_os" = android; then cc_default="clang" # 这里修改 默认值 cxx_default="clang++" fi ar_default="${cross_prefix}${ar_default}" # 这里修改成我们新定义的前缀 cc_default="${cross_prefix_clang}${cc_default}" # 这里修改成我们新定义的前缀 cxx_default="${cross_prefix_clang}${cxx_default}" nm_default="${cross_prefix}${nm_default}" pkg_config_default="${cross_prefix}${pkg_config_default}"
四、 编写脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #!/bin/bash export TMPDIR=../temp # 定义变量(可以不定义, 直接在下面写死也行, 这样不是更加清晰复用和简易嘛) SYSROOT=/Users/liushuai/ffmpeg_2/ndk/toolchains/llvm/prebuilt/darwin-x86_64/sysroot # 定义变量(可以不定义, 直接在下面写死也行, 这样不是更加清晰复用和简易嘛) PLATFORM=/Users/liushuai/ffmpeg_2/ndk/toolchains/llvm/prebuilt/darwin-x86_64 function build { ./configure \ --prefix=$PREFIX \ --target-os=android \ --arch=$CPU \ --enable-shared \ --disable-static \ --disable-doc \ --disable-ffmpeg \ --disable-ffplay \ --disable-ffprobe \ --disable-avdevice \ --disable-symver \ --enable-cross-compile \ --sysroot=$SYSROOT \ --cross-prefix=$PLATFORM/bin/arm-linux-androideabi- \ --cross-prefix-clang=$PLATFORM/bin/armv7a-linux-androideabi16- \ --extra-cflags="-I$SYSROOT/usr/include" \ --extra-ldflags="-L$SYSROOT/usr/lib" $ADDITIONAL_CONFIGURE_FLAG make clean make -j4 make install } CPU=armv7-a PREFIX=../os build
你会发现直接编译完,动态库生成了!!!, 没有发现中间有任何问题