Skip to content

Commit

Permalink
feat: update README and delete built-in black pod list
Browse files Browse the repository at this point in the history
  • Loading branch information
chenxGen committed Sep 23, 2021
1 parent 8f388bb commit 1b4c8d2
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 92 deletions.
18 changes: 10 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

此插件思路来源于[《一款可以让大型iOS工程编译速度提升50%的工具》](https://tech.meituan.com/2021/02/25/cocoapods-hmap-prebuilt.html)。通过使用 header map (以下简称 hmap ) 代替文件路径搜索优化预处理阶段中头文件搜索的性能实现编译速度提升。

[English](./README_en.md)
[English Version](./README_en.md)

## 首先,什么样的项目适合使用这个插件?

1. **仅适合使用 objective-c 作为主要开发语言项目**,因为 swift 没有头文件的概念,从其编译原理上看并没有什么帮助;
2. **不适合 Podfile 中 开启了 `use_frameworks!` or `use_modular_headers!` 的项目使用**,由于为了兼容 clang module 特性,采取的策略是不对开启了 DEFINES_MODULE 的项目生成 hmap;
3. **不适用于 CPU 为 M1 以及后续 M 系列芯片的 Mac**,因为使用之后提升也很小;
- **仅适合使用 objective-c 作为主要开发语言项目**,因为 swift 没有头文件的概念,从其编译原理上看并没有什么帮助;

- **不适合 Podfile 中 开启了 `use_frameworks!` or `use_modular_headers!` 的项目使用**;为了兼容 clang module 特性,采取的策略是不对开启了 DEFINES_MODULE 的项目生成 hmap;

- **不适用于 CPU 为 M1 以及后续 M 系列芯片的 Mac**;因为使用之后提升也很小;

综上,比较适合 old school 的项目使用此插件,如果你的项目满足以上条件推荐使用此插件,不然可能收效甚微,不建议继续往下看了。

Expand All @@ -28,15 +30,15 @@

## 使用

只需要在你的`Podfile`中调用`plugin 'cocoapods-project-hmap'` 声明使用该插件。
只需要在你的`Podfile`中添加如下行`plugin 'cocoapods-project-hmap'` 声明使用该插件。

同时插件还为`Podfile`提供了一下几个可选的方法调用:

- **set_hmap_black_pod_list:** 开发插件的时候发现有些Pod target使用预生成的hmap编译会出错,比如使用了`#import "a/very/very/long/path/to/header.h"`,暂时没想到好的解决方案,所以针对这种情况需要手动添加到黑名单,不对该target的进行处理,如:`set_hmap_black_pod_list(['PodA','PodB'])`,插件内置了一些这种情况的三方库,具体见:[built-in black list](/lib/cocoapods-project-hmap/podfile_dsl.rb)。如果你还有其他的三方库由于其他原因编译失败,也可以把它添加到黑名单。。。
- **set\_hmap\_black\_pod\_list:** 如果你有第三方库在使用插件后编译失败,可以尝试把它添加到黑名单中

- **turn_prebuilt_hmap_off_for_pod_targets:** 如果你发现有太多的三方库需要添加到黑名单,你可以直接通过调用这个方法开启“纯净模式”,关闭插件对Pod Project内部所有target的header处理,仅仅对提供给主项目使用的target处理hmap
- **turn\_prebuilt\_hmap\_off\_for\_pod\_targets:** 如果你发现有太多的三方库需要添加到黑名单,你可以直接通过调用这个方法开启“纯净模式”,关闭插件对 Pod Project 内部所有 target 的 header 处理,仅仅对提供给主项目使用的 target 处理 hmap

- **set_hmap_use_strict_mode:** 在一个target中引用另一个target的header,严格意义上来说应该使用`#import <PodA/Header.h>`的方式,但是有些是通过`#import "Header.h"`这种情况如果设置了对应的header search path编译是可以成功的,比如使用原生的cocoapods情况下,在项目中使用`#import "Masonry.h"``#import <Mansory.h>``#import <Masonry/Mansory.h>`三种方式引入都是可以成功的,如果你使用这个插件并且开启这个选项后只有`#import <Masonry/Mansory.h>`可以编译成功。默认为关闭。
- **set\_hmap\_use\_strict\_mode:** 在一个 target 中引用另一个 target 的 header,严格意义上来说应该使用`#import <PodA/Header.h>`的方式,但是有些是通过`#import "Header.h"`这种情况如果设置了对应的 header search path 编译是可以成功的,比如使用原生的 cocoapods 情况下,在项目中使用`#import "Masonry.h"``#import <Mansory.h>``#import <Masonry/Mansory.h>`三种方式引入都是可以成功的,如果你使用这个插件并且开启这个选项后只有`#import <Masonry/Mansory.h>`可以编译成功。默认为关闭。


最终你的Podfile看起来会是这样的 :
Expand Down
60 changes: 9 additions & 51 deletions README_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,14 @@

A cocoapods plugin to improve compilation speed at preprosessor phase by using hmap instead of file paths for header searching. The idea comes from [《一款可以让大型iOS工程编译速度提升50%的工具》](https://tech.meituan.com/2021/02/25/cocoapods-hmap-prebuilt.html)

## Benchmark

There are some test cases in the benchmark project : [hmap-benchmark](https://github.com/chenxGen/hmap-benchmark/).

The latest outputs by running `run_benchmark.rb` are:

- Mac mini (Intel i7/16g) :

```
+--------------------------------------+--------------------+------------------------------------------------------------------------------------------------------------------------+
| Case | Average(s) | Detail(s) |
+--------------------------------------+--------------------+------------------------------------------------------------------------------------------------------------------------+
| 100 source files & 125 pods (origin) | 192.43606980641684 | [218.57447242736816, 178.7542200088501, 179.97951698303223] |
| 100 source files & 125 pods (plugin) | 165.76690363883972 | [166.8555600643158, 165.40182876586914, 165.04332208633423] |
| > optimization (speed) | 16.09% | |
| > optimization (time cost) | 13.86% | |
| 1 source files & 125 pods (origin) | 170.00553512573242 | [175.31463813781738, 173.79285717010498, 160.9091100692749] |
| 1 source files & 125 pods (plugin) | 124.49473492304485 | [123.54309391975403, 124.4949209690094, 125.4461898803711] |
| > optimization (speed) | 36.56% | |
| > optimization (time cost) | 26.77% | |
| Total (origin) | 181.22080246607462 | [218.57447242736816, 178.7542200088501, 179.97951698303223, 175.31463813781738, 173.79285717010498, 160.9091100692749] |
| Total (plugin) | 145.1308192809423 | [166.8555600643158, 165.40182876586914, 165.04332208633423, 123.54309391975403, 124.4949209690094, 125.4461898803711] |
| > optimization (speed) | 24.87% | |
| > optimization (time cost) | 19.91% | |
+--------------------------------------+--------------------+------------------------------------------------------------------------------------------------------------------------+
```
- Mac air (Apple M1/16g) :

```
+--------------------------------------+-------------------+--------------------------------------------------------------------------------------------------------------------+
| Case | Average(s) | Detail(s) |
+--------------------------------------+-------------------+--------------------------------------------------------------------------------------------------------------------+
| 100 source files & 125 pods (origin) | 95.07198365529378 | [91.36949586868286, 96.10968923568726, 97.73676586151123] |
| 100 source files & 125 pods (plugin) | 91.2074584166289 | [90.87663986448735, 90.77357686752014, 91.97326111793518] |
| > optimization (speed) | 4.24% | |
| > optimization (time cost) | 4.06% | |
| 1 source files & 125 pods (origin) | 81.564133644104 | [80.95829105377197, 82.07278513988386, 81.66132473945618] |
| 1 source files & 125 pods (plugin) | 79.28314812668217 | [78.21958923339844, 80.21097787748413, 79.17887886892395] |
| > optimization (speed) | 2.98% | |
| > optimization (time cost) | 2.89% | |
| Total (origin) | 88.3180586496989 | [91.36949586868286, 96.10968923568726, 97.73676586151123, 80.95829105377197, 82.07278513988386, 81.66132473945618] |
| Total (plugin) | 85.2053037/161153 | [90.87663986448735, 90.77357686752014, 91.97326111793518, 78.21958923339844, 80.21097787748413, 79.17887886892395] |
| > optimization (speed) | 3.65% | |
| > optimization (time cost) | 3.52% | |
+--------------------------------------+-------------------+--------------------------------------------------------------------------------------------------------------------+
```

The outputs indicate that this plugin has about 3%-36% build speed improvement, the improvement is not significant on mac using M1 processor because of Apple M1 processor's high IO performance (I GUESS...).

**So if you are using Mac with Apple M1 processor, There may be no need to use this plugin.**
## First

What kind of projects are recommended to use this plugin?

- **Project using objective-c as their main develop language**
- **Project not using `use_frameworks!` and `use_modular_headers!` in their Podfile**

and Developer not using Mac with M series CPU.

## Requirement

Expand All @@ -69,7 +27,7 @@ In your `Podfile`, add this line : `plugin 'cocoapods-project-hmap'`

And this plugin also provides Podfile DSL bellow:

- `set_hmap_black_pod_list`: There are some unsolved situation in develping this plugin, such as a 'pod' using a long path import in their code, like `#import "a/very/very/long/path/to/header.h"`, I did not think of a suitable strategy to handle this, so I provide a method to adding then to black list, you can add then with code `set_hmap_black_pod_list(['PodA','PodB'])`, and there are some built-in 'pod' in black list, see : [built-in black list](/lib/cocoapods-project-hmap/podfile_dsl.rb). And if you have some other build error because of this plugin, adding then to black list...
- `set_hmap_black_pod_list`: If you have some compilation error for pod targets because of this plugin, adding the target name to black list...
- `turn_prebuilt_hmap_off_for_pod_targets`: If you have to many build error after using this plugin, or have to add to many 'pod' to black list, I provides a most non-intrusive way to use, call this method `turn_prebuilt_hmap_off_for_pod_targets` to ignore hmap prebuilt for most of the pod target (excepting the 'main' pods, named `Pods-${YOUR SCHEME}`).
- `set_hmap_use_strict_mode`: Import a header in other library(PodA), strictly speaking, we should use `#import <PodA/Header.h>`, but not all library developer do like that, if you turn it on, you can find then.

Expand Down
14 changes: 2 additions & 12 deletions lib/cocoapods-project-hmap/podfile_dsl.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,7 @@
# !/usr/bin/env ruby
# built-in black list pods (long import path not supported
# built-in black list pods
# you can use hmap_black_pod_list to add other pods
$hmap_black_pod_list = [
# 'GoogleUtilities',
'MeshPipe',
'GoogleDataTransport',
'FirebaseCoreDiagnostics',
'FirebaseCore',
'FirebaseCrashlytics',
'FirebaseInstallations',
'CoreDragon',
'Objective-LevelDB'
]
$hmap_black_pod_list = []

$strict_mode = false
$prebuilt_hmap_for_pod_targets = true
Expand Down
66 changes: 45 additions & 21 deletions lib/cocoapods-project-hmap/xcconfig.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,8 @@ def remove_header_search_path(prebuilt_hmap_target_names=nil)
if header_search_paths
new_paths = Array.new
header_search_paths.split(' ').each do |p|
if p.include?('${PODS_ROOT}/Headers') == false or p.end_with?('/Private"') or p.end_with?('/Public"')
# retain path not in normal `pod headers` path
# and "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
unless search_path_should_be_deleted?(p, prebuilt_hmap_target_names)
new_paths << p
elsif prebuilt_hmap_target_names != nil && prebuilt_hmap_target_names.empty? == false
# add path not prebuilt hmap
if prebuilt_hmap_target_names.select { |name| p.include?(name) }.empty?
new_paths << p
end
end
end
if new_paths.size > 0
Expand All @@ -29,38 +22,69 @@ def remove_header_search_path(prebuilt_hmap_target_names=nil)
remove_attr_with_key('HEADER_SEARCH_PATHS')
end
end
remove_system_option_in_other_cflags
remove_system_option_in_other_cflags(prebuilt_hmap_target_names)
end
def remove_system_option_in_other_cflags
def search_path_should_be_deleted?(search_path, prebuilt_hmap_target_names=nil)
# Check if the path should be deleted from search list
# 1. It must be at the ${PODS_ROOT} directory
# 2. It has generated hmap
ret = false
if search_path.include?('${PODS_ROOT}/Headers')
if prebuilt_hmap_target_names
ret = prebuilt_hmap_target_names.select { |name| search_path.include?(name) }.empty? == false
end
end
ret
end
def remove_system_option_in_other_cflags(prebuilt_hmap_target_names=nil)
# ----------------------------------------------
# -I<dir>, --include-directory <arg>, --include-directory=<arg>
# Add directory to include search path. For C++ inputs, if there are multiple -I options,
# these directories are searched in the order they are given before the standard system directories are searched.
# If the same directory is in the SYSTEM include search paths, for example if also specified with -isystem, the -I option will be ignored
#
# -isystem<directory>
# Add directory to SYSTEM include search path
# ----------------------------------------------
flags = @attributes['OTHER_CFLAGS']
if flags
new_flags = ''
skip = false
is_isystem_flag = false
flags.split(' ').each do |substr|
if skip
skip = false
next
append_str = substr
# Previous flag is `isystem`
if is_isystem_flag
is_isystem_flag = false
if search_path_should_be_deleted?(append_str, prebuilt_hmap_target_names)
next
else
# recover
append_str = "-isystem #{append_str}"
end
end
if substr == '-isystem'
skip = true

if append_str == '-isystem'
is_isystem_flag = true
next
end

if new_flags.length > 0
new_flags += ' '
end
new_flags += substr
new_flags += append_str
end

if new_flags.length > 0
@attributes['OTHER_CFLAGS'] = new_flags
else
remove_attr_with_key('OTHER_CFLAGS')
end
end
end
def reset_header_search_with_relative_hmap_path(hmap_path, white_list=nil)
# remove all search paths
remove_header_search_path(white_list)
# add build flags
def reset_header_search_with_relative_hmap_path(hmap_path, prebuilt_hmap_target_names=nil)
# Delete associate search paths
remove_header_search_path(prebuilt_hmap_target_names)
# Add hmap file to search path
new_paths = Array["${PODS_ROOT}/#{hmap_path}"]
header_search_paths = @attributes['HEADER_SEARCH_PATHS']
if header_search_paths
Expand Down

0 comments on commit 1b4c8d2

Please sign in to comment.