使用BUCK进行iOS项目打包

关于BUCK

BUCK是Facebook开源的快速打包工具,能够用于多种语言及平台的项目打包,例如:C、C++、Java、iOS、Android等等。用于大型的iOS、Android项目,能够显著提高打包效率。html

关于BUCK介绍的一些连接以下:java

BUCK官网ios

What Makes Buck so Fast?:介绍了BUCK如何作到性能提高c++

BUCK源码: 里面有源码和大量Unit Test提供了不少示例,同时查看Issues能够找到不少问题的解决方案git

iOS快速编译BUCKgithub

基于Facebook Buck改造Android构建系统之初体验shell

 

核心概念

Build Rule

build rule is a procedure for producing an output file from a set of input files.数组

Build Target

build target is a string that is used to identify a build rule in your project.app

Build File 

build file is a file named BUCK that defines one or more build rules.iphone

.buckconfig

The root of your project must contain a configuration file named  .buckconfig.

 

iOS打包相关Rule

Rule
产出
做用

apple_asset_catalog()

没有特定产出,能够做为apple_bundle()的依赖 Contains resources stored in Apple asset catalog directories

apple_binary()

静态库:.a file An apple_binary() rule builds a native executable from the supplied set of Objective-C/C++ source files

apple_bundle()

.app 或者 .appex (apple watch extension) An apple_bundle() rule takes an Apple binary and all of the resources and asset catalogs in the rule's transitive dependencies and generates a bundle containing all of those files. 

apple_library()

静态库:.a file An apple_library() rule represents a set of Objective-C/C++ source files

apple_package()

ipa file An apple_package() rule takes the output of an apple_bundle() rule and compresses it in an IPA (iOS App Store Package) file. 

apple_resource()

This rule does not have any output on its own and can be built only as a dependency (either direct or transitive) of an apple_bundle() rule. An apple_resource() rule contains sets of resource directories, files and file variants that can be bundled in an application bundle. 

apple_test()

An apple_test() rule contains Objective-C/C++ code which can be built and used to test code contained in other rules.

core_data_model()

This rule does not have any output on its own and can be built only as a dependency (either direct or transitive) of an apple_bundle() rule, in which case all core_data_model() rules that the bundle rule depends on are merged and placed into the final output bundle together. An core_data_model() rule contains models for Apple's Core Data framework. 

prebuilt_apple_framework()

引用.framework库
     

 

使用BUCK用于iOS工程打包

目录组织结构

对于一个多个子工程组成,经过依赖关系最终集成为单个可执行文件。使用BUCK,须要为每个子工程都建立BUCK文件,在根目录配置.buckconfig。大体目录结构以下:

 

|—.buckconfig

|—BUCK

|—SubProject1

|---------src

|---------BUCK

|—SubProject2

|---------src

|---------BUCK

|—SubProject3

|---------src

|---------BUCK

|—SubProject4

|---------src

|---------BUCK

......

 

每一个子工程的BUCK文件,负责配置build rule,生成静态.a 文件,而后最终经过根目录中的BUCK,来生成.ipa文件。

 

.buckconfig配置

[cache]
  mode = dir
 
[cxx]
    cflags = -std=gnu11
    cxxflags = -std=c++14 -stdlib=libc++
    default_platform = iphonesimulator-x86_64
    combined_preprocess_and_compile = true
 
[alias]
  SubProject1 = //SubProject1: SubProject1Lib
  SubProject2 = //SubProject2: SubProject2Lib
  SubProject3 = //SubProject3: SubProject3Lib
  SubProject4 = //SubProject4: SubProject4Lib
  
 
[apple]
  xctool_zip_target = //third-party/ios/xctool:xctool-minimal-zip
 
[project]
    ignore = .buckd, \
             .hg, \
             .git, \
             .idea, \
             buck-cache, \
             buck-out, \

 

cxx:定义了一些C++编译的参数

alias: 定义了一些build target的别名。例如CTFoundation为例,在CTFoundation中的BUCK文件中定义了CTFoundationLib的rule,因此若是要打包CTFoundation,能够经过别名的方式,命令以下:

# 未用别名
buck build //SubProject1:SubProject1Lib
  
# 使用别名
buck build SubProject1

 

apple: 指定了xctool的文件地址。Buck的iOS打包是依赖于xctool,因此须要把xctool的相关代码引入,具体内容能够参考示例: 

git clone git@github.com:fbsamples/bucksamples.git
cd bucksamples/cross-platform-scale-2015-demo/
 

 

BUCK文件配置

独立子工程的BUCK配置

下面以一个独立的子工程做为示例,并且没有其余依赖,因此能够做为第一个示例。它的BUCK文件配置以下:

apple_library(
  name = 'SubProject1Lib',
  preprocessor_flags = ['-fobjc-arc','-Wno-deprecated-declarations','-fmodules'],
  compiler_flags = ['-Wno-objc-designated-initializers','-fembed-bitcode'],
  linker_flags = [
        '-F$DEVELOPER_DIR/Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks',
        '-F$DEVELOPER_DIR/../SharedFrameworks',
        '-F$DEVELOPER_DIR/Library/PrivateFrameworks',
  ],
 
  srcs = glob(['src/**/**/**/*.m',]),
 
  frameworks = [
        '$SDKROOT/System/Library/Frameworks/Foundation.framework',
  ],
   
  exported_headers = {
    'xxx1.h': './src/xxx.h',
    'xxx2.h': './src/xxx2.h',
    ...
  },
 
  #header_namespace = '',
  visibility = [
    'PUBLIC',
  ],
)

 

整个BUCK文件就一个apple_library,产出libCTLocation.a文件。能够看到里面能够指定一下编译的flags、依赖的framework、源代码、对外暴露的头文件等等。

经过命令 buck build CTLocation就能够打包查看,在buck-out目录中能够看到生成出来的.a文件。

 

须要注意的exported_headers的配置:

The set of header files that are made available for inclusion to the source files in this target and all targets that transitively depend on this one. These should be specified as either a list of header files or a dictionary of header names to header files. The header names can contain forward slashes (/). If a list of header files is specified, the headers can be imported with #import "$HEADER_PATH_PREFIX/$HEADER_NAME" or, if a header file that belongs to the same rule is being imported, with #import "$HEADER_NAME", where $HEADER_PATH_PREFIX is the value of the target's header_path_prefix attribute, and $HEADER_NAME is the filename of the header file. If a dictionary is specified, each header can be imported with #import "$HEADER_NAME", where $HEADER_NAME is the key corresponding to this file. In this case, the header_path_prefix attribute is ignored. In either case, quotes in the import statements can be replaced with angle brackets.

 

能够有两种配置格式,数组和字典。

使用数组的时候,其余代码引用是须要加上前缀例如:#import "SubProject1/xxx.h",默认前缀和apple_library的name一致,能够经过设置header_path_prefix改变。

使用字典的时候,其余代码引用时候能够经过key来引用,例如:

// BUCK配置:
exported_headers = {
 'xxx.h': './src/xxx.h',
}
  
// 其余代码引用
#import "xxx.h"
 

依赖资源文件

若是代码中有资源文件,须要经过apple_resource来引用

apple_resource(
    name = 'SubProject1Resource',
    files = glob(['*.png']),
    dirs = [],
)

 

特殊的Compiler flag

在iOS中,有些源代码须要一些特殊的compiler flag,例如非ARC的源码。在src里面能够进行配置:

srcs = glob(['SubProject1/**/**/**/*.m',], excludes = ['**/**/xxx1.m','**/**/xxx2.m'])+
  [('src/xxx1.m', ['-Wno-shorten-64-to-32']),
  ('src/xxx2.m', ['-fno-objc-arc'])]
 

引用外部framework

prebuilt_apple_framework(
    name = 'BuckTest',
    framework = 'BuckTest.framework',
    preferred_linkage = 'shared',
    visibility = ['PUBLIC'],
)

 

引用外部.a 静态库

以下项目有依赖外部的.a库,能够经过如下方法引用

cxx_library(
  name = 'lib1',
  srcs = [],
  exported_headers = {
    'xxx.h': 'libs/xxx.h',
  },
  visibility = ['PUBLIC'],
)
  
apple_library(
  name = 'SubProject1Lib',
  deps = [':lib1'],
  ...
  libraries = [
    'libs/xxx.a',
  ],

 

当前BUCK的局限性

BUCK自己目前还在快速迭代中,因此不少rule尚未完善、文档不全,社区也够活跃,遇到问题会比较难找到解决方案。

目前iOS项目中碰到的一些限制问题:

    • 自定义的script,在XCode的build phase中能够自定义一些shell脚本,可是在BUCK中没有找到对应的方式
    • 没法生成.bundle资源包,iOS打包过程当中每一个子工程都会产出一个.a和.bundle文件,可是BUCK打包不会产出.bundle文件只会有.a,资源文件只能经过apple_resource()来管理做为其余rule的依赖。
    • 经过apple_library()生成.a文件彷佛目前还没办法指定valid architectures。
相关文章
相关标签/搜索