How to speed up build time?

Our app has 72k lines of Swift code in 922 files and 500+ lines of Obj-C code.

Our clean build time is about 4 minutes.
When changing code in a very minor way, e.g. adding a line in a view controller, our incremental build time is about 2-3 minutes. Which is a lot.

We have done many optimizations such as warn-long-expression-type-checking, decrease file size, avoid declaring many types in one file, and reduce 3rd party dependencies. We were able to shave off only about 20 seconds. Which is not very satisfying for me.

One thing we are exploring is modularize the code. We tried pulling out our core models code as a Swift Package, which contains like 20-30 types. But our incremental build time doesn't improve in anyway.

Is there anything else we can do to improve incremental build time with such a large code base? Will these things works?
  • modularize more parts of the app

  • use binary framework instead of source code framework

  • anything else

Below is output of cloc App/. command to show more insights of our code base.


Replies

Not sure if the cloc output is properly formatted. I'll just paste it here again.

Code Block
github.com/AlDanial/cloc v 1.82 T=1.83 s (516.1 files/s, 53330.0 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Swift 922 16777 6540 72453
C/C++ Header 12 97 81 760
Objective C 9 117 61 550
-------------------------------------------------------------------------------
SUM: 943 16991 6682 73763
-------------------------------------------------------------------------------

Sorry you are experiencing this issue. It can be very frustrating!

You can watch the build log in Xcode as it builds to see where the time is going. Sometimes it is not in the Swift compiler.

If it is in the Swift compiler, depending on which release you are running, setting -disable-fine-grained-dependencies in the other Swift flags can help. But when you adopt a new release, you want to try removing it.

You can also try setting -driver-show-incremental and possibly -driver-show-job-lifecycle (also in Other Swift Flags). These flags will cause the compiler to print out extra information to tell you which source files are being compiled, and way. Remember to remove them after you have gathered the information, because the extra output can confuse Xcode. The extra output will show up in the build log if you expand the step for compiling Swift files.

If the small change you are making does not affect other files, you should see only a few source files recompiled.
If a lot of files are recompiled, ensure you don't have a shell script in your build that might be touching the source files.

But if it is just a few files getting recompiled, and a lot of time is going into the Swift compiler, yes, breaking up the target should help.

Good luck!
Hi! Thanks for the reply.

Today I tried creating a stand alone DummyViewController that isn't used anywhere in the app. Compiled, then add one line of code. The incremental compile time is 1 minute.

At this point, I think there's something else other than the modified file here that ramps up the incremental compile time. So I dive into the build logs. I added -driver-show-incremental and -driver-show-job-lifecycle in Other Swift flags and checks the build log under "Compile Swift source files". Here I attached the first 500 lines of the log.



Honestly, I cannot make much sense from the log above. Some help is appreciated.

My best guess is that, since I see Viki-Bridging-Header.h in the log, I guess it's the bridging header. It contains some models, constants, a view controller, and some NSObject helper that is used in many places throughout the app. Is this plausible?

My bridging header looks like this. (Not sure if this will help.)

Code Block objective-c
#ifndef Viki_Viki_Bridging_Header_h
#define Viki_Viki_Bridging_Header_h
#import <GoogleConversionTracking/ACTReporter.h>
#import <SurveyMonkeyiOSSDK/SMError.h>
#import <SurveyMonkeyiOSSDK/SurveyMonkeyiOSSDK.h>
#import <GAI.h>
#import "CSSubscriptionManager.h"
#import "NSObject+VKFoundation.h"
#import "VKAPICollection.h"
#import "NSError+Viki.h"
#import "VKSilo.h"
#import "VKSlideInTransitionContainerViewController.h"
#import "VKRecentSearch.h"
#import "VKVikiliticsConstants.h"
#endif


Please help! 🙏
New clue. Seems like it takes very long at MergeSwiftModule normal x86_64 step. We have about 50 modules in total. Is this step suppose to take this long?