美文网首页
iOS | 交叉编译 工欲善其事,必先利其器

iOS | 交叉编译 工欲善其事,必先利其器

作者: BinaryBang | 来源:发表于2020-04-16 12:29 被阅读0次

    前言


    在iOS设备上进行音视频的处理,往往要使用市面上比较流行的音视频相关库,比如音频编码的Lame,处理视频的FFmpeg,处理图片的OpenCv等.

    而要能够运行这些库,我们必须将它们编译为能够在iOS设备上运行的文件.这就需要我们进行交叉编译.交叉编译是iOS通向音视频处理的第一道拦路虎,非常容易出错.本文最后以编译Lame库为例,介绍交叉编译的完整流程.

    1 交叉编译

    1.1 CPU的类型和指令集

    对于一台电脑或者手机来说,核心部件是中央处理器CPU,所有指令的执行,最终都是依靠CPU来完成的.

    指令集,是CPU能够执行的指令的集合,每种类型CPU都有自己的指令集,或者架构.

    如果是不同系列CPU,指令集是互不兼容的,在指令集为A的CpuA上运行的代码,不能在指令集为B的CpuB上执行.
    如果是相同系列的CPU,指令集向下兼容,低版本指令集A1的CpuA1上运行的代码,也可以在高版本指令集为A2的CpuA2上运行,但是不能够充分发挥CpuA2的性能.

    1.2 iOS设备架构列表

    iOS设备都虽然都是ARM系列的CPU,但是有不同的指令集:
    armv6:iPhone,iPhone2,iPhone 3G
    armv7:iPhone 4,iPhone 4S
    armv7s:iPhone 5,iPhone 5S
    arm64:iPhone6(P),iPhone7(P)
    arm64e:iPhone XS
    i386:32位模拟器
    x64:64位模拟器

    1.3 什么是交叉编译

    编译型语言的源代码,比如C源代码,要能在PC上运行,需要经过编译,链接,成为PC可执行的二进制文件,然后才能在PC上运行.

    同理,如果要在其他机器上运行,就必须编译,链接成为可以在其他机器上运行的代码.

    源代码在机器A上的编译链接得到机器B上运行的代码.
    如果机器B==机器A,那么就是本机编译.
    如果机器B!=机器A,就是交叉编译.

    比如,机器A是Mac,机器B是iPhone,那么就是在Mac上交叉编译生成iPhone的代码.

    那么为什么不直接在iPhone上本机编译呢,因为iPhone上没有成熟的编译工具,以及足够的硬件条件去编译源代码.

    1.4 iOS关于架构的设置

    iOS中,有3个关于架构的设置:
    BuildSettings|Architectures|Architectures
    指定工程被编译成可支持哪些指令集类型,而支持的指令集越多,就会编译出包含多个指令集代码的数据包,对应生成二进制包就越大,也就是ipa包会变大。

    BuildSettings|Architectures|Valid Architectures
    限制可能被支持的指令集的范围,也就是Xcode编译出来的二进制包类型最终从这些类型产生,而编译出哪种指令集的包,将由Architectures与Valid Architectures(因此这个不能为空)的交集来确定.

    BuildSettings|Architectures|Build Active Architecture Only
    是否只生成支持当前连接设备的指令集的包.
    一般Debug模式下设置为YES,加快编译速度;而Release模式下设置为NO,更好地适配各种机型.

    一般情况下,我们编译armv7s和arm64的包就可以适配大部分机型了.

    2 交叉编译Lame库

    2.1 Lame库

    Lame是一款效果很好的开源Mp3编码器,是在iOS设备上将音频编码为Mp3的最佳选择.
    本章用最新版本3.100进行编译.

    2.2 configure命令

    这里先提一个文件,configure文件:



    每一个符合GNU标准的软件包都会包含该命令.

    交叉编译的整个流程,做了很多事情,我也不是很清楚具体都做了什么.我们需要关心的是,我们需要做什么:
    我们需要通过以合适的方式运行configure命令,改名令执行的结果会生成合适的Makefile文件.
    然后利用make和make install命令编译和安装整个库.

    所以,我们在交叉编译中需要做的重点,就是用合适的参数去运行configure命令.

    2.2 configure命令常用参数

    我们输入命令./configure -h可以查看configure的帮助文档,会显示当前软件包的全部可选项配置.
    下面介绍几个主要的配置:

    • 指定执行编译任务的主机的架构
      --build={Build}
      build: 执行代码编译的主机的架构,正常的话就是你的主机系统。
      这个参数一般由config.guess来猜就可以。当然自己指定也可以。

    • 指定输出位置
      --prefix={PREFIX}, 指定编译好的库放在哪个目录下,这是GNU大部分库的标准配置.

    • 指定要运行库的架构
      --host={HOST},指定要交叉编译出来的库,最终运行的平台,不同的架构CPU有不同的值:
      arm64:
      arm-apple-darwin
      armv7:
      arm-apple-darwin
      i386:
      i386-apple-darwin
      x86_64:
      x86_64-apple-darwin

    • 工具链的路径
      CC,交叉编译工具链的路径,其实就是gcc编译器的路径.不同架构的CPU有不同的值:
      x86_64:
      xcrun -sdk iphonesimulator clang -arch x86_64
      i386:
      xcrun -sdk iphonesimulator clang -arch i386
      arm64:
      xcrun -sdk iphoneos clang -arch arm64
      armv7s:
      xcrun -sdk iphoneos clang -arch armv7s

    • 编译参数
      CFLAGS,编译时需要带的参数,不同架构的CPU有不同的值:
      x86_64:
      -arch x86_64 -fembed-bitcode -miphoneos-version-min=7.0
      i386:
      -arch i386 -fembed-bitcode -miphoneos-version-min=7.0
      arm64:
      -arch arm64 -fembed-bitcode -miphoneos-version-min=7.0
      armv7s:
      -arch armv7s -fembed-bitcode -miphoneos-version-min=7.0
      其中,-fembed-bitcode表示该静态库使用了bitcode,关于bitcode,请参考后面的bitcode一节.

    • 链接参数
      LDFLAGS,链接时的参数,和CFLAGS保持一致.

    • 指定关闭动态链接
      --disable-shared:关闭动态链接,以便工具可以单独使用.

    • 指定不编译可执行文件.
      --disable-frontend,指定不编译LAME的可执行文件.

    • 指定创建静态库
      --enable-static,创建静态库,默认为YES.

    软件工程师的职责之一,就是要把重复性的东西做成工具,让工作变得简单,从而创造快乐和价值.在本文末尾,会给出一个编译脚本.利用该脚本,可以方便地编译出i386,x86_64,armv7s,arm64架构的库.

    2.3 查看编译成果物

    每一个指令集的包中,有lib,include,share3个目录:



    lib目录,存放的是我们的静态库文件,libmp3lame.a
    include目录,是工程中需要使用的头文件,每个指令集对应的目录下的头文件是一样的.
    share目录,包含了使用手册.

    2.4 合并静态库

    如果我们多个指令集的静态库,需要把他们合并才能使用.
    如果这几个静态库的文件路径是libPath1,libPath2
    使用以下命令合并:

    $ lipo -create libPath1 libPath2 -output outputFilePath
    

    合并后的库文件的目录为outputFilePath

    验证是否合并成功,可使用file命令或者lipo -info命令:

    $ file libmp3lame.a 
    libmp3lame.a: Mach-O universal binary with 4 architectures: [i386:current ar archive random library] [arm64]
    libmp3lame.a (for architecture i386):   current ar archive random library
    libmp3lame.a (for architecture armv7s): current ar archive random library
    libmp3lame.a (for architecture x86_64): current ar archive random library
    libmp3lame.a (for architecture arm64):  current ar archive random library
    
    或者:
    $ lipo -info libmp3lame.a 
    Architectures in the fat file: libmp3lame.a are: i386 armv7s x86_64 arm64 
    

    2.5 bitcode

    如果开启了bitcode
    1,Xcode会将程序编译为一个中间表现形式(bitcode)
    2,AppStore会将该中间形式的代码进行优化
    总体来说,开启bitcode可以优化app的性能;

    一个项目要使用bitcode,必须满足该项目中所有使用的第三方静态库都在编译时打开了bitcode.否则,只能关闭bitcode,从而得不到性能上的优化.

    3 编译脚本的使用

    编译脚本是一个sh文件,使用时先将脚本放到LAME库文件的根目录下.
    然后在命令行中,切换到LAME库文件的目录下,然后执行:
    sh ./LameBuilderForiOS.sh
    该脚本会编译i386 x86_64 arm64 armv7s四个平台的库文件,输出在{LAME库目录}/thin文件夹中,然后将这四个库文件合并起来,输出在{LAME库目录}/fat文件夹中.

    编译脚本地址和编译好的Lame库地址:
    https://github.com/GikkiAres/LameBuilder

    相关文章

      网友评论

          本文标题:iOS | 交叉编译 工欲善其事,必先利其器

          本文链接:https://www.haomeiwen.com/subject/kghrvhtx.html