编译相关

作为一个开发者,我们很多时候要了解编译器到底在做什么,本文主要就库与xcode的设置作一些介绍.

1.什么是库?

简单的说,库就是编译好的二进制文件,编译的时候只需要link一下;库为分静态库和动态库:

  • 静态库 - 静态链接库,如.a文件;之所以叫做静态库,是因为静态库在编译的时候会被直接拷贝一份,复制到目标程序里
  • 动态库 - 动态链接库,如.dylib;动态库在编译时并不会被拷贝到目标程序中,目标程序中只会存储指向动态库的引用。等到程序运行时,动态库才会被真正加载进来
  • 两者的优缺点:

  • 静态库:
    优点:编译完成后,库文件实际上就没有作用了。目标程序没有外部依赖,可以直接运行
    缺点:目标程序的体积增大
  • 动态库:
    优点:不需要拷贝到目标程序中,不影响包体积;而且同一份库可以被多个程序使用,所以也称共享库;编译时才载入可以对库进行替换而不需要重新编译
    缺点:动态载入带来性能损失,也使得目标程序依赖于外环境。如不同iOS系统下动态库的接口不同导致报错
  • 2.Architecture

    Architectures:
    编译选项指定了工程将被编译成支持哪些指令集。支持指令集是通过编译生成对应的二进制数据包实现的,如果支持的指令集数据有多个,就会编译出包含多个指令集代码的数据包,造成最终编译的包很大。

    Valid Architectures:
    该编译选项指定了可能支持的指令集,该列表和Architectures列表的交集,将是Xcode最终生成二进制包所支持的指令集。

    如何选择支持的指令集:
    如果软件对安装包大小非常敏感,可以减少安装包中的指令集。如只支持armv7指令集。不对对于armv7s/arm64指令集设备来说,运行armv7应用是会有一定的性能损失。具体多少目前没有数据。

    使用命令查看生成包的处理器类型:lipo -info AppName.app/AppName
    配置Architectures为armv7 arm64,Valid Architectures为arm64 armv7 armv7s

    使用模拟器编译

  • Build Active Architectures only的debug设置为YES,Architectures in the fat file: AppName.app/AppName are: x86_64
  • Build Active Architectures only的debug设置为NO,Architectures in the fat file: AppName.app/AppName are: i386 x86_64

  • 在模拟器下只不会编译出真机处理器体系结构的代码段

    使用真机编译 iPhone4s
  • Build Active Architectures only的debug设置为YES,Architectures in the fat file: AppName.app/AppName are: armv7
  • Build Active Architectures only的debug设置为NO,Architectures in the fat file: AppName.app/AppName are: armv7 arm64

  • 在真机下,Build Active Architecture only为YES的时候,Xcode只会根据active scheme来决定生成支持哪种处理器的包且只有一种,为NO的时候,Xcode是取Valid Architectures与Architecture的交集来生成相应的包

    3.指令集

    什么是指令集:存储在CPU内部,对CPU运算进行指导和优化的硬程序。
    什么是ARM:ARM架构过去称作进阶精简指令集机器(Advanced RISC Machine).是一个32位元精简指令集(RISC)中央处理器架构。也称RISC微处理器。
    CISC(复杂指令集计算机)和RISC(精简指令集计算机)是当前CPU的两种架构。RISC结构优先选取使用频最高的简单指令,避免复杂指令;将指令长度固定,指令格式和寻址方式种类减少;以控制逻辑为主,不用或减少微码控制等。
    不同指令集适配: 机器对指令集的支持是向下兼容的

  • armv6:iPhone3GS以下
  • armv7:3GS以上~iPhone4
  • armv7s:iPhone5~iPhone5s以下
  • arm64:iPhone5s及以上
  • 4.Search Paths(搜索路径)

  • Header Search Paths:外部头文件路径一般设置为$(SRCROOT)/../include
  • Library Search Path:库搜索路径一般设置为$(SCRROOT)/ .a文件所在的文件路径
  • Other Linker Flags:链接器参数,如-ObjC,-all_load,-force_load等。
  • 5.编译与链接

    C代码到可执行文件经历:源代码->预处理器->编译器->汇编器->机器码->链接器->可执行文件(Mach-O)。
    预处理:处理源文件中的宏定义,将代码中的宏用其对应的具体内容进行替换;import某个头文件,会用此头文件中的内容去替换这么代码。
    链接器:一个.c或.cpp文件就是一个编译单元,编译后产生一个.o目标文件;为了最终生成一个可执行文件、静态库或动态库,就需要把各个编译单元按照特定的约定组合到一起(这里特定的约定指的就是目标文件格式),它定义了目标文件、库文件和可执行文件的格式,这里组合的过程就叫做链接。

    在最后一步需要把.o文件和C语言运行库链接起来,这时候需要用到ld命令,而Other Linker Flags设置的值实际上就是ld命令执行时后面所加的参数。

  • -ObjC:链接器会把静态库中所有objectvie-c类和分类都加载到最后的可执行文件中,当静态库中有类和category的时候必须要加这个flag。
  • -all_load:当在静态库中只有category没有类的时候使用-ObjC,这些category是加载不进去的。这时候就要使用-all_load了。-all_load会让链接器把所有找到的目标文件都加载到可执行文件中。但是不能轻易使用这个参数,如果同时使用多个静态库,不同的库文件可能会有相同的目标文件,导致编译错误:ld duplicate symbol。
  • -force_load:所做的事情和-all_load其实是一样的,但是-force_load需要指定要进行全部加载的库文件路径,这样的话只是完全加载了一个库文件,不影响其他库文件的按需加载(-force_load $(BUILT_PRODUCTS_DIR)/libarc.a)
  • 6.Build Phases

  • Compile Sources:
    指定了所有必须进行编译的文件
  • Link Binary with Libraries:
    当编译结束,下一步就是将所有的内容链接到一块。这里列出了所有的静态库和动态库。这些库会与上面编译阶段生成的目标文件进行链接。
  • Copy bundle Resource
    当链接完成之后,build phase中最后需要处理的就是将静态资源(图片和字体)拷贝到app的bundle中。其中png的图片不仅仅是拷贝,还会做一些优化。
  • 7.Build Rules

    指定不同文件类型该如何编译。每一条build rule指定了其应用于哪种文件类型,该文件类型是如何被处理的,以及输入内容被放置到何处。