美文网首页
9、iOS强化 --- 静态库

9、iOS强化 --- 静态库

作者: Jax_YD | 来源:发表于2021-03-12 11:42 被阅读0次
    • 什么是静态库?
      静态库也叫做静态链接库,可以简单的看做一组目标文件的集合。即多个目标文件经过压缩打包后形成的文件。
      在iOS开发中,常见的静态库有:
      .a文件(是一个文档格式)
      .framework文件(该文件可以是静态库,也可以是动态库)
      静态库的缺点:浪费内存和磁盘空间,模块更新困难。

    这里我们解释一下接下来我们要用到的clang命令:

    /**
     clang命令参数:
         -x: 指定编译文件语言类型
         -g: 生成调试信息
         -c: 生成目标文件,只运行preprocess,compile,assemble,不链接
         -o: 输出文件
         -isysroot: 使用的SDK路径
         1. -I<directory> 在指定目录寻找头文件 header search path
         2. -L<dir> 指定库文件路径(.a\.dylib库文件) library search path
         3. -l<library_name> 指定链接的库文件名称(.a\.dylib库文件)other link flags -lAFNetworking
         -F<directory> 在指定目录寻找framework framework search path
         -framework <framework_name> 指定链接的framework名称 other link flags -framework AFNetworking
    
        -l的查找规则:先找lib+<library_name>的动态库,找不到,再去找lib+<library_name>的静态库,还找不到,就报错
     */
    

    .a文件

    首先我们先来看一下.a的格式是什么?
    我这边有一AFNetworking的静态库:

    image.png
    在终端执行下面的命令,来看一下libAFNetworking.a的格式:
    file libAFNetworking.a
    
    image.png
    可以看到libAFNetworking.a是一个文档的格式。

    下面我们再来看一下libAFNetworking.a里面到底有什么。
    这里我们要用到ar命令,我们可以通过man ar来看一ar是干什么的:

    image.png
    我们通过ar -t 这个命令来打印一下libAFNetworking.a里面的内容:
    image.png
    可以看到libAFNetworking.a就是.o文件的集合。

    静态库链接

    下面我们将.a文件与我们的代码链接生出可执行程序。
    首先我们有一个test.m文件

    image.png
    下面我们来编译生成test.o文件:
    image.png
    这是我们发现,编译报错,因为找不到AFNetworking.h文件。我们在test.m文件引用了AFNetworking,但是在编译的过程中我们并没有告诉编译器AFNetworking.h的地址,类似于我们Xcode中header search paths的报错。
    ⚠️ 指令中的\shell里面的转移字符,可以让指令换行,但是还是一条指令,这样方便阅读。

    下面我们来设置一下AFNetworking.h的路径:
    我们通过-I来指定目录,.代表当前文件夹

    image.png
    image.png
    这样生成目标文件test.o成功了。
    接下来生成可执行文件test
    执行下面的命令:
    image.png
    image.png

    静态库的合并

    通过上面我们知道,静态库.o问价的合集,那么静态库的合并其实就是将.a先解压,然后再合并成一个.a文件。
    这里我们用libtoolar也可以做到,看上ar的解释;通常会用libtool来做这件事)。
    那我们来看一下libtool

    image.png
    • 现在有两个静态库libAFNetworking.a & libSDWebImage.a,执行下面的指令进行合并:
    libtool -static -o test.a libAFNetworking.a libSDWebImage.a
    
    image.png

    Framework

    image.png
    • Mac OS / iOS 平台还可以使用Framework
      Framework 实际上是一种打包方式,将库的二进制文件,头文件和有关的资源文件打包到一起,方便管理和分发。
      在使用到Framework里面的文件的时候,那么生成.o文件和上面试一样,因为-I只是一个路径,头文件和库文件本身并不一定要放到一起。

    我们来看一下Framework文件里面的内容:

    image.png
    接下来我们手动创建一个Framework,暂时我们用不到签名和资源文件,所以我们只需要头文件.a就可以了。
    我们按照正常的工程目录来创建:
    image.png
    这里我们有这样一组文件:
    image.png
    我们先生成.a文件:
    image.png
    这里YSExample.o 生成 YSExample.a的时候用到了下面的命令:
    ar -rc TestExample.a TestExample.o
    
    /**
     `ar`压缩目标文件,并对其进行编号和索引,形成静态库。同时也可以解压缩静态库,查看有哪些目标文件:
     ar -rc a.a a.o
        -r: 像a.a添加or替换文件
        -c: 不输出任何信息
        -t: 列出包含的目标文件
     */
    

    接着我们将YSExample.a放到刚刚创建的路径里面,同时按照我们看到的Framework中文件的格式,将后缀去掉等。

    image.png

    接下来我们编译一下,生成test.o文件:

    clang -x objective-c  \
    -target x86_64-apple-macos11.1 \
    -fobjc-arc \
    -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
    -I./Frameworks/TestExample.framework/Headers \
    -c test.m -o test.o
    
    image.png

    然后执行:

    clang -target x86_64-apple-macos11.1 \
    -fobjc-arc \
    -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk \
    -F./Frameworks \
    -framework TestExample \
    test.o -o test
    
    image.png

    使用shell脚本来执行上面的操作

    shell是一种解释型的语言,会一行一行的去解释你的代码。
    首先我们搭建我们的测试环境,创建一个文件夹,文件夹内容如下:

    image.png

    build.sh:将test.m赋值,名字和后缀改一下就可以了。
    接着我们将我们要在终端执行的命令,拷贝到build.sh里面(这些命令就不在做解释,上面都有解释):

    SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.1.sdk
    FILE_NAME=test
    HEADER_SEARCH_PATH=./StaticLibrary
    
    echo "-----开始编译test.m"
    clang -x objective-c \
    -target x86_64-apple-macos11.1 \
    -fobjc-arc \
    -isysroot $SYSROOT \
    -I${HEADER_SEARCH_PATH} \
    -c ${FILE_NAME}.m -o ${FILE_NAME}.o
    
    echo "-----开始进入StaticLibrary"
    pushd ./StaticLibrary
    
    clang -x objective-c \
    -target x86_64-apple-macos11.1 \
    -fobjc-arc \
    -isysroot $SYSROOT \
    -c TestExample.m -o TestExample.o
    
    ar -rc libTestExample.a TestExample.o
    echo "-----开始退出StaticLibrary"
    popd
    
    echo "-----开始test.o to test EXEC"
    clang -target x86_64-apple-macos11.1 \
    -fobjc-arc \
    -isysroot $SYSROOT \
    -L./StaticLibrary \
    -lTestExample \
    ${FILE_NAME}.o -o ${FILE_NAME}
    

    第一次运行,汇报这个错:

    image.png
    是因为build.sh文件没有可执行权限,那么我们给它加一个权限就可以了:
    chmod +x ./build.sh
    // x 代表可执行权限
    

    然后再执行脚本:


    image.png

    -noall_load

    clang链接的过程中-noall_load默认就是生效的。
    那么这个时候就产生了一个问题,大家都知道,OC的分类(Category)是在运行时动态创建的。那么在链接的时候,发现分类的方法没有被调用,就会被剥离。
    下面看一下具体的场景。
    我们有一个静态库 如下:

    image.png
    和 一个APP工程 如下:
    image.png
    • 第一步我们将两个工程引入到同一个workspace中:
      创建workspace

      image.png
      (创建workspace的时候,主要保存到相应的文件。此时是在YSStaticLibrary工程中做到操作。)
      添加其他工程workspace:
      image.png
      选择对应的project
      image.png
      最后通过wookspace从新打开工程即可。
    • 为了方便编译,我可以这样做:


      image.png
    • 我们在YSAPP中使用一下我们的静态库,然后运行:

      image.png
      会发现,马上就报错了:
      image.png
      这就是因为链接的过程中将ys_test_category剥离了(分类是在运行时创建的)。
    • 这里给大家提示一下(不要把我们APP工程里面的分类 和 静态库里面的分类搞混了):
      .o.o 生成可执行文件 ,是先合并成一个大的.o 然后再去链接
      .o.a 是先dead code strip 再去链接
      -noall_load这些只针对静态库有效。(\color{red}{看下面代码注释,这一点很关键}

    这个时候我们可以通过添加链接器参数也保留静态库的符号:

    LGSTATIC_FRAMEWORK_PATH=${BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/YSStaticLibrary.framework/YSStaticLibrary
    OTHER_LDFLAGS=-Xlinker -force_load $LGSTATIC_FRAMEWORK_PATH
    
        // OTHER_LDFLAGS 通过clang 给ld传递参数
        // -Xlinker 告诉clange 参数是传给 ld的不是传给你的
        
        // -noall_load 不全部加载
        // -all_load 所有的都加载
        // -Objc 除了OC的代码,其他的正常剥离
        // -force_load 指定哪些静态库不要 dead code strip
        /// 以上四个参数只是针对我们的静态库
    
    image.png

    将上面的指令,添加到对应的xcconfig文件中就可以了。对于配置xcconfig文件不太明白的同学可以参考2、iOS强化 --- Xcode 多环境的配置
    再运行就可以了。

    image.png

    相关文章

      网友评论

          本文标题:9、iOS强化 --- 静态库

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