diff --git a/README.md b/README.md index 7fa5c81..8f05150 100644 --- a/README.md +++ b/README.md @@ -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 的项目使用此插件,如果你的项目满足以上条件推荐使用此插件,不然可能收效甚微,不建议继续往下看了。 @@ -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 `的方式,但是有些是通过`#import "Header.h"`,这种情况如果设置了对应的header search path编译是可以成功的,比如使用原生的cocoapods情况下,在项目中使用`#import "Masonry.h"`、`#import `和`#import `三种方式引入都是可以成功的,如果你使用这个插件并且开启这个选项后只有`#import `可以编译成功。默认为关闭。 +- **set\_hmap\_use\_strict\_mode:** 在一个 target 中引用另一个 target 的 header,严格意义上来说应该使用`#import `的方式,但是有些是通过`#import "Header.h"`,这种情况如果设置了对应的 header search path 编译是可以成功的,比如使用原生的 cocoapods 情况下,在项目中使用`#import "Masonry.h"`、`#import `和`#import `三种方式引入都是可以成功的,如果你使用这个插件并且开启这个选项后只有`#import `可以编译成功。默认为关闭。 最终你的Podfile看起来会是这样的 : diff --git a/README_en.md b/README_en.md index b8e207b..ee2d834 100644 --- a/README_en.md +++ b/README_en.md @@ -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 @@ -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 `, but not all library developer do like that, if you turn it on, you can find then. diff --git a/lib/cocoapods-project-hmap/podfile_dsl.rb b/lib/cocoapods-project-hmap/podfile_dsl.rb index b5988df..564d072 100644 --- a/lib/cocoapods-project-hmap/podfile_dsl.rb +++ b/lib/cocoapods-project-hmap/podfile_dsl.rb @@ -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 diff --git a/lib/cocoapods-project-hmap/xcconfig.rb b/lib/cocoapods-project-hmap/xcconfig.rb index 85e5136..44a59d2 100644 --- a/lib/cocoapods-project-hmap/xcconfig.rb +++ b/lib/cocoapods-project-hmap/xcconfig.rb @@ -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 @@ -29,27 +22,58 @@ 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, --include-directory , --include-directory= + # 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 + # 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 @@ -57,10 +81,10 @@ def remove_system_option_in_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