# Compile time optimization

References:

CCache I almost missed you

How to improve compilation speed for iOS projects by 5 times

Optimize build time for iOS projects

Tip: Much of this article is the same as above, with the addition of a replacement @import script

As our project gets bigger and bigger, full compilation often starts in ten minutes, which greatly affects the thinking and time of development, so we plan to introduce CCache

  • Xcode compiles cache
    • The Archive mode ignores the cache
    • The DerivedData directory is often problematic
  • CCache
    • Archive does not ignore caches
    • The hit rate is basically stable

Using CCache improves compilation time by roughly 70%.

Install CCache

Command: manually call chmod -r 777 setup.command &&./setup.command to grant script permission and execute the command

Script name :setup.command Script content:

if command -v ccache >/dev/null 2>&1; Then echo "CCache already installed "else if command -v brew >/dev/null 2>&1; Ruby_path = 'which ruby' then echo "HomeBrew install ccache" brew install ccache else echo "HomeBrew install ccache" ruby_path= 'which ruby echo $ruby_path $ruby_path -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" brew install ccache fi fiCopy the code

Xcode set

We have installed CCache on the computer, the next thing we need to do is to set up the project

  • Disable the Enable Module

  • The new Macro CC configuration lets Xcode automatically run the CCache script

  • Replace the @import script

After the Enable Module is disabled, we need to delete all @import code used in the project and replace it with #import <>. This step is difficult because the @import code in the Pod library is changed. Replace @import from third party. My first thought was to use a script

Chmod -r 777 ChangeImportMethod.py && Chmod -r 777 Pods && Python ChangeImportMethod.py

The script name is changeimportmethod.py

Script content:

# coding=utf-8

import os
# python2 can be executed without relying on other libraries
This script needs to execute chmod 777 to grant read/write permissions and also execute once in Pod folder to ensure read/write permissions are allowed
project_path = os.getcwd() + "/Pods" # project root
print(project_path)

suf_set = ('.h'.'.m')

# Ready to be covered
preparationSet = {
    "@import Foundation;":"#import <Foundation/Foundation.h>"."@import UIKit;":"#import <UIKit/UIKit.h>"."@import Security;":"#import <Security/Security.h>"."@import PassKit;":"#import <PassKit/PassKit.h>"."@import Contacts;":"#import <Contacts/Contacts.h>"."@import QuartzCore;":"#import <QuartzCore/QuartzCore.h>"."@import CoreLocation;":"#import <CoreLocation/CoreLocation.h>"."@import CoreGraphics;":"#import <CoreGraphics/CoreGraphics.h>"
    }

Walk through the file and rename it as required
for (root, dirs, files) in os.walk(project_path):
    for file_name in files:
        if file_name.endswith(suf_set):
            # print('-----fileName-------' + file_name)
            with open(os.path.join(root, file_name), 'r+') as f:
                s0 = f.read()
                f.close()
                for key in preparationSet:
                    if key in s0:
                        print('========needChange========' + root +"/"+ file_name)
                        with open(os.path.join(root, file_name), 'r+') as f4:
                            s1 = f4.read().replace(key, preparationSet[key])
                            print(key + '-- -- -- -- -- - >' + preparationSet[key])
                            f4.seek(0)
                            f4.write(s1)
                            f4.truncate()
                            f4.close()
Copy the code

Once the script is written, access is simple and we need to run our script fix before compiling the project source. So I’m going to add Run Scripts

  • The CocoaPods configuration is modified in the Podfile
post_install do |installer_representation|
  installer_representation.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      iftarget.name ! ='Library name you want to ignore'&& target.name ! ='Library name you want to ignore'
        config.build_settings['CLANG_ENABLE_MODULES'] = 'NO'
        config.build_settings['CC'] = '$(SRCROOT)/.. /ccache-clang'
        config.build_settings['CXX'] = '$(SRCROOT)/.. /ccache-clang++'
      end
    end
  end
  system 'chmod -R 777 setup.command && ./setup.command'
end
Copy the code

What are you going to do

  • Improved cache hit ratio

You can run the ccache -s command to view the cache hit ratio of ccache. For CCache to really reduce compile time, the hit rate needs to be about 90%. As mentioned above, frequently caching miss is slower than not using CCache. Therefore, after integrating CCache, a cache hit ratio of 90% should be guaranteed to improve the construction speed. If the cache hit ratio is too low, log analysis should be performed to troubleshoot the cause. The few cache hits we’ve tried so far in our project are up to 50%, so there’s a lot of room for optimization.

  • Remove the Precompiled Prefix Header

The use of PCH files is the most common cause of poor cache hit ratio. Many projects import frequently used classes into PCH for convenience, and the contents of the PCH are appended to each file at compile time. Changes in the PCH contents will cause the contents of the entire file for the compiled object to change, thus invalidation of the CCache cache. If you’ve ever run a project that compiles a full version of one or two source files after you’ve changed them, check to see if there are too many import dependencies in the PCH. If you can’t remove the PCH, try to reduce the number of import files in the PCH.

  • Cleaning up obsolete code

It’s obvious that no code can compile faster than no code, but it can be a lot of work to implement. It is easy to create modules that are no longer used when your business is rapidly iterating and updating. Regular cleaning can reduce both project build time and installation package size. If you think the code will be useful in the future, you can simply remove references to the Xcode project and keep the files for reference.