在了解xcode构建原则之前,需要熟悉workspace相关的概念,即workspace,project和target
target
target指定了构建的product,包含将workspace或project中的一组文件构建成product的指令。单个target定义一个product,它将输入(源文件和处理这些源文件的指令(包含所设定的构建settings和phases))组织进构建系统中。project和target是一对多的关系。
target会继承project的build settings,但可以以target为粒度设置build settings,且Xcode中当前一次只会有一个有效target,此有效target在xcode scheme中标识。
若target A依赖target B的输出来构建,则A依赖B,当它们存在于一个xcode workspace中的时候,Xcode会发现此依赖关系并按顺序构建。这种依赖称为隐性依赖,当然也可以在build settings中声明显性依赖,也可将隐性依赖的两个target显性声明为没有依赖。比如可能在同一个workspace中同时构建一个库并构建一个依赖这个库的应用,则xcode会选择先构建库。但如果应用想链接库的某个特定版本,则可以显性声明这个依赖关系,此时隐性依赖即被覆盖了。
project
xcode project是存储构建一个或多个软件产品所需的所有文件,资源和信息的仓库。project包含构建product所需的所有要素并维护它们之间的关系,它包含一个或多个targets(target指定了构建product的方式)。project定义了所有target的默认build settings,各target可以重载。
Xcode project文件包含如下信息:
源文件的引用:源代码(包括头文件和实现文件),library和framework(xcode内部或者外部),资源文件,interface builder文件
文件结构列表中组织源文件的Groups
project级别的build选项
targets
debug或测试program的可执行环境:从xcode运行或调试时启动哪些可以执行文件,传给可执行文件的命令行参数,程序运行时设置的环境变量
总之,project可以单独存在也可以包含在workspace中,同时可以在Scheme中指定哪个Target、build配置、哪个可执行配置在某个时刻是有效的。
build settings
一个build setting是一个指示产品某个方面构建方式的变量,比如决定xcode传给编译器的参数选项是怎样。其是一个常量或者一个公式供给xcode在构建的时候计算build setting。
workspace
workspace 是组织projects和其他协同工作的文档的一份文档。除此之外,它还维护project和target之间的显性及隐性的依赖关系。
默认workspace中的所有Xcode projects都在同一个目录下构建,称为workspace build directory,由于所有project的所有文件都在同一个目录下,所以所有文件都对每个project可见。比如两个project使用同一个库,则不用复制到另一个project目录中。
workspace中的每个project都有其独立id,同时project可以属于多个workspace,可以单独打开project或者在其他workspace中打开,且都不用重新配置project或者workspace。
可以使用workspace默认的build 目录,也可以指定一个。如果project指定了构建目录,这个目录会被project构建时所在的workspace的build目录覆盖。
xcode scheme
xcode scheme定义了一系列构建的targets,构建时的配置,和一系列执行的测试。
可以有很多scheme,但同一时刻只能有一个有效的。选择scheme时,意味着你也选择了一个运行目标(product构建的硬件平台)。可以指定scheme是否存储在project中,以便包含此project的所有workspace都可以使用些scheme,当然也可以指定只存储在某个workspace中。
现实案例
如果需要将project A的输出*.a作为project B的输入,则可以在B的framework中添加A的project文件。此时project A的内容即可在B的framework层级中展开,同时为了使用A中的头文件,需要将其源文件路径加入A中的target的Build Settings中的User Header Search Paths中
而将所使用的库的头文件及*.a文件配置进spec文件中,并将其交付给pod管理的情况,则由pod默认将头文件均添加进了Pod目录 Pods/Headers/Public中,并将此目录配置进了Pods target的Header Search Paths中
而.a文件导入的方式则是通过如下配置选项来完成
依赖的project依赖了同样的pod库
如果project B所依赖的project A需要依赖同样的Pod库,则情况会复杂一些,首先是,在Podfile文件中,如果添加两条xcodeproj指令
则会导致在执行pod update命令时,头一条xcodeproj 指令所 指明的proj无法被pod所找到
而如果将A作为B的exclusive target,则A和B在workspace中的关系会是平级的关系,所以Podfile中不需要添加project A的信息,只需要将A作为 B所依赖的framework导入进来即可。由于project A由于整个项目位于B中,所以Podfile.lock相对于其目录的位置会不一样,有可能出现Check Pods Manifest.lock中所执行的
diff指令中 Podfile.lock文件路径不正确的总是,这时需要手动调整
如果只让A依赖pod库,同时B也依赖pod库,则会出现多重符号的提示
当然,如果能够让A和B都可以自由地依赖各自所依赖的Pod库自然是最好,但目前还未发现同一个workspace中想到依赖的xcodeproj同时依赖同一个pod库的解决方案