Dramatically long Swift compilation time - ios

I like Apple and the things they do, but Swift... OH GOD!
I have a problem with `Swift` compile time.
Configuration:
MacBook Pro (Retina, 13-inch, Mid 2014)
2,6 GHz Intel Core i5
8 GB 1600 MHz DDR3
SSD 256 (up to 800 MB/s)
1k classes
10 pods
Compile time: 3 min.
Looks like for "new best and amazing swift, the dream" this configuration is not enough and it works like Google Chrome - InfiniteLoop(find free memory - eat)
I tried various methods to speed up the compile time:
Set HEADERMAP_USES_VFS to YES (no change)
Set Build Settings / Architectures / Build Active Architecture Only
to YES (some improvement)
Set defaults write com.apple.Xcode PBXNumberOfParallelBuildSubtasks 4 (8)
(sometimes it's become even worse)
Set optimisation level to -Onone (no major improvement)
Set debug information format - DWARF instead of DWARF with dSYM File
Disable Find implicit dependencies from your scheme (no major
improvement)
Created a new project and moved all files to the new one (takes too long and give small time improvement)
Change compilator from default to others available (even worse)
Strict rules on how to write fast compiled Swift code (below more details)
I've found a few posts where people describe the same problem: here and here
I guess everyone is waiting for new Xcode 8.2 beta 2 where:
Xcode will not rebuild an entire target when only small
changes have occurred. (28892475)
But this is only partially true, I still have long compile time - moved from 6-12 minutes to 3-8. Detailed description of this can be found here and here
Also, I followed all these rules during code writing:
Chained function reduction
Unwrapping the optionals
Implicit typing for an object (dictionary especially)
Avoiding ?? operator (this one extremely hungry!!)
Avoiding ?: operator
In othe words, don't use any "new cool features" because you'll wait for ages.
One more try - is a workaround described here:
Go to Product -> Scheme -> Edit Scheme. Select Build in left side
column and uncheck "Find implicit dependencies" But this flag should
remain checked when you are building the project for the first time.
But, this workaround isn't what I'm looking for and this is also can be as a temporary solution.
Swift is a pain not because it's hard to write, but because it's hard to use (at least on some machines).
For comparison: I have a project on Objective-C with 2k classes, and 11 pods - clean compile time is ~30 seconds.
Also I found a lot of opened bugs on swift performance:
SR-2461
SR-1465
SR-1707
SR-663
and many others, the list is too long, and some of them were opened a few years ago
My question is:
Does anyone have any solution on improving compile time for Swift?

This issue has been extremely frustrating for me as well. We've tried several of the solutions you've mentioned and none of them worked.
The one thing that made a significant improvement in compilation time is:
Turning on the Whole Module Optimization while adding -Onone in Other Swift Flags.
See this - Speed Up Swift Compilation
I'm using Swift 3 with Xcode 8.3.

We improved our compile times a lot by using Carthage instead of Cocoapods to include third party libraries.

It's likely you have code optimisation switched on, whilst this is a must for building your release version, for dev builds it isn't particularly important.
What code optimisation does is exactly what it says, it optimises your code to make the end binary that is produced smaller. It does things such as rename variables/methods to single characters etc... Like I said you obviously want this when submitting to the app store but you might not care if the app is larger whilst developing it.
You can turn off code optimisation for development builds by going to Project Settings > Build Settings, searching 'optim', under Swift Compiler - Code Generation set Optimization Level to None [-Onone] for Debug builds.
This should significantly improve your build times.

WHOLE MODULE OPTIMIZATION WITH NO DEBUGGING RESTRICTIONS
Just add SWIFT_WHOLE_MODULE_OPTIMIZATION as an user-defined setting with the value YES and your compile times should improve a lot.
This fix was introduced by the developers at Zalando. Shout out to them.
https://jobs.zalando.com/tech/blog/improving-swift-compilation-times-from-12-to-2-minutes/?gh_src=4n3gxh1

Related

Extremely long compilation times with Swift in Xcode

I have three iOS projects:
First one - 35k Swift LOC, Swift 2.1 (or 2.0?), compiled using Xcode 7.2.3
Second one - 15k Swift LOC, Swift 2.3, compiled using Xcode 8.2.1
Third one - 15k Swift LOC, Swift 3.0, compiled using Xcode 8.2.1
The compile times for all of these are abysmal (10+ minutes for a clean build), and the development on each one of these is slowing to a crawl.
I have already tried:
Using Whole Module Optimization
Changing C Dialect to compiler default
Analyzing build times for the project and optimizing bottlenecks (a few methods that took 6-10s to compile with array concatenation, nil coalescing operators and such), which shaved like 15 seconds - completely unnoticeable difference
HEADERMAP_USES_VFS = YES
A few other I don't remember now
I'm working on a Mac mini Late 2014 with an SSD, 8GB RAM & 2.6ghz i5, if that matters.
Anyone knows what might cause that, what to do with that or even any workarounds for now? From what I've read on SO and other places, it seems like an unresolved compiler issue.
EDIT: Yes, I'm using Cocoapods for dependencies. I'll try moving to Carthage and see what happens.
Try set the following in Build Settings as a workaround. I am assuming you have just one Target.
Set the Build Active Architecture Only to Yes.
Set Optimization Level to None [-Onone]
Add User-Defined setting called "SWIFT_WHOLE_MODULE_OPTIMIZATION" with the value "YES"
Empty your derived data and build.
You can also then use this tool to analyze any slow compiling Swift files: https://github.com/RobertGummesson/BuildTimeAnalyzer-for-Xcode
I was experiencing build times that were taking 6-7 minutes. I moved away from Cocoapods and started using Carthage which helped for clean builds. Even then builds were still taking 3 minutes. The biggest improvement came with the steps I mentioned above.
Update
Instead of adding the User-Defined setting, on your Debug build set the Optimization Level to 'Fast, Whole Module Optimization'. Then in Other Swift Flags for your debug build add '-Onone'.
It's an open issue on swift's site: https://bugs.swift.org/browse/SR-6037
Hopefully they'll fix it soon.

My Xcode 7.3 compiler is constantly breaking and causing extremely long Build and Compile times

This Issue Occurred On A SpriteKit Xcode Project
I have an issue with Swift where, once my project reaches a certain level of complexity where I have tons of classes and methods around, my autocompletion breaks so that "Jump To Definition" ceases to work and my IDE is reduced to the usefulness of a basic TextEditor/Notepad.
My code's color will change to white completely, which causes a lot of strain on my eyes, and this seems to only happen when I remove and add large blocks of code as I watch my CPU activity climb up to 75% usage on all CPU cores.
I think this started happening when I switched the target iOS from 9.3 over to 8.0. Is this an issue with the compiler trying to interpret old Swift syntax?
I also will have cases where I wait two minutes for minor changes to compile, only for the build to fail due to "Linker command failed with exit code", which is easily fixed by compiling twice.
Here's my specs:
OS X 10.11.4
Core i7 Skylake 4.0GHz
16 GB DDR4 RAM
256GB SSD
I'm thinking about building a system running OS X with dual processors which might alleviate the issue, since it can take upwards of 2 minutes just to compile code that's different by 1 line.
Okay, I found one solution which resolved my issue.
Remove All Emojis From Variable Names & .Swift File Names
Contrary to Apple's official Swift 2.0 textbook, DO NOT use ANY kind of Emoji's for things like Variable Names and Swift File Names UNLESS you know that the emoji you're using is a very old emoji (but even then, I wouldn't recommend it).
After opening my project in AppCode, AppCode had unicode problems with file names such as: foobar🔵.swift. It was very buggy and it would break Xcode later if I opened and saved a project with pre-existing emojis in AppCode.
So avoid using emojis in your code unless it's for strings like:
let someString = "⬛️🗡💣📚"
Welcome to Swift! Great language, awful tooling.
Joking aside, there are a couple of issues at play here. First off, syntax highlighting disappears when SourceKit crashes. SourceKit is the library which parses Swift on-the-fly so that Xcode can do things like indexing, syntax highlighting and code completion. It's a lot better than it used to be (using Swift 1.0 in Xcode was almost comical at times), but it's still far from perfect. Until SourceKit improves, you won't see much difference.
As for your build times, it's worth trying something like the Swift Build Time Analyzer to see which functions are taking a particularly long time to compile. I recently halved the compile time of the project I work on by removing all lazy vars set via closures. A recent compiler change made type inference for these sorts of closures incredibly slow, so each one was taking ~6 seconds to compile.

Does the Swift toolchain eliminate code that is never called?

If I create an Xcode project with the iOS Single View Application template and choose Swift for the language, will the compiler exclude from the release build (binary) functions that never get called?
I'm wondering because I want to include a third-party library that has a lot of superfluous classes & functions, and I want to keep my app small & fast.
While I agree with comments, it is unlikely to impact performance in any significant way even if it was included...
Xcode 6 uses Apple LLVM Compiler Version 6.1, depending on how closely related it is to LLVM Developer Group's version the optimization feature is available http://llvm.org/docs/Passes.html with options such as -dce: Dead Code Elimination, -adce: Aggressive Dead Code Elimination.
One way to know for sure what is included is checking the assembly output using -emit-assembly option in the swift compiler and review the output, or opening the binary in a disassembler such as Hopper ( http://www.hopperapp.com/download.html )

How to handle large Swift Project?

After iPhone app that I'm writing in Swift become quite big (> 150 .swift files + various Objective-C libs), Xcode start behave pretty badly:
every second compilation I get various errors, e.g.:
Command failed due to signal: Segmentation fault: 11
compilation take enormous amount of time (> 2 min on MacBook Pro Retina)
and so on.
I just wonder if everyone has same problems and maybe someone found a way to reduce this nightmare?
What I have done so far — I split project into several dynamic frameworks that I link from main project, it helps to reduce compile time, but introduce some new problems.
I also use iRamDisk to keep DerivedData folder in RAM and periodically delete all files from it, it sometimes helps with SourceKit crashes.
Swift toolchain is still a bit gross, you'll need to use some temporary workarounds until Apple fixes it (see UPDATES below)
Here is a list of items that you can do to keep yourself from going crazy.
Slowness caused by immature Swift compiler
Change your development workflow using Injection for Xcode. Once you installed the plugin, you'll be able to inject code changes in your simulator\device without recompiling. You don't need to hardcode\modify anything in your project. We started using it recently at work and it made a huge impact on our side, even if it doesn't apply to every use case (for example you can't create new functions, you can only modify the existing ones).
Some particular code constructs that the compiler doesn't like and takes too much time to compile. The most common problem is with the Type Checker that slows down compile time exponentially based on how many type checks it needs to do (read more here for practical examples and here for a detailed explanation). In order to identify if you are suffering from this problem you can follow this blog post, you will gather information about the functions that creates slowness by using some compiler additional flags. Alternatively you can use this Xcode plugin to identify the source of the build slowness.
Use dynamic frameworks wisely, where it makes sense. A framework recompilation will be done only when you modify one of its Swift files (dynamic frameworks are only available for iOS >= 7).
Condense code in the same files. Lowering the number of Swift files speeds up the compile process sensibly. You can easily achieve it enabling "Whole module optimization" by adding a user-defined custom flag SWIFT_WHOLE_MODULE_OPTIMIZATION and set it to YES and at the same time set optimization level to none (to disable optimizations that would make it slow) OUTDATED You may consider to use this gist, it's a build script that collapses all your code in a "merge.swift" file.
You'll need to create a new target for it, but it is worth a
try.
Double check things listed here (there are a few some more misc reasons because the compilation is slow)
OUTDATED Try the approach described in this blog post, it involves creating a build script that generates a make file. It requires manual intervention on the build script (it contains the list of swift files).
OUTDATED Try this hacked up incremental compilation technique
UPDATE: Incremental builds introduced on Swift 1.2 (Xcode 6.3)
Apple finally introduced incremental builds with Swift 1.2 (shipped with Xcode 6.3). It's not still perfect, but it's a huge improvement.
From now on a class is recompiled only when it is changed (or when one of the class it depends on has been changed).
However the compiler still can’t understand if the changes to a class are to its interface or not. So any kind of change to a class causes a recompilation of that class and all of its dependencies.
UPDATE: Recompile dependent classes only when public interface changes introduced on Swift 2.1 (Xcode 7.1)
Starting from Swift 2.1 (Xcode 7.1), the dependent classes are recompiled only when you change the public interface of a class, and not at every change. This makes an huge difference in particular for big projects.
Project (mis)configuration (not related to Swift)
Be sure that "Build Active Architecture Only" is YES for debug.
Be sure that you didn't add pre\post compilation scripts that take too much time.
Apple has some advices for speeding up your Xcode build in Technical Note 2190. Have you thought about creating and precompiling an own framework for outsourcing unchanged Swift modules or some/all Objective-C code?
Remove all type inferences in Swift.
This SO topic has some nice ideas and this blog post suggest to
stop generating dSYM bundles and
avoid compiling with -O4 if using Clang.
Although lots of these improvements are related to Objective-C, I am quite sure, that some of them are still relevant for Swift.
The (re)compiling is a known issue that I am sure will be resolved soon. Some recommendations:
Use Objective C where possible - it compiles fast even if it is a part of a Swift project
Split code to frameworks
Specify types instead of leaving it up to the compiler to infer them
Again, there is a good chance that this will be fixed soon, so perhaps it is best not to make big investments in rewriting or reorganizing the code at this point in time.
you could try:
upgrading the amount of RAM in your computer
if you have multiple .swift files that do things on the same view controller, try condensing them into one .swift file per view controller
tweaking the settings under compile sources to see if you have any duplicates or if there are any scripts or settings you can add to make it compile faster...
you can also take a look at this post's answers for some hints as to what you can do to slow down compile time
I've discovered that one of the main causes of segmentation faults and slow compilation is hardcoding big arrays and dictionaries, especially when declaring them as global constants and trying to access values from them from within another .swift file. When I store all that data inside plists, these problems are gone.
In my experience avoid creating the large swift files, when I started a project in my new company, there was a 'UIViewController' with more than 2000 lines, little changes on this file taking much time to build, I made 4 extensions with <500 lines from that class, my speed improvement was incredible.

Invalid Executable Size - From iTunes Connect

I am uploading my iOS application on iTunes. I am using MonoTouch for compiling my LibGdx Game for iOS. In Android it is hardly 7-8mb. But When I upload on iTunes AppStore then its goes to 78 mb. I dont know why ? Please Let me know.
I have also received this error from Apple.
Dear developer,
We have discovered one or more issues with your recent delivery for "Run Panda Run: Racing". To process your delivery, the following issues must be corrected:
Invalid Executable Size - The executable size of 72037504 bytes exceeds the maximum allowed size of 60 MB.
It's hard to give a definite answer without more details. There's a lot of things that can affect the size of the applications. Let's start with the basic.
What you should check:
First, ensure that your application is not being build with Don't link. That will create very big applications since you'll be AOT'ing nearly the full .NET framework that Xamarin.iOS ships;
Second, make sure you're building for a single architecture (ARMv7). FAT binaries (e.g. ARMv7 and ARMv7s) are build two times and needs twice the space;
Third make sure you have not enabled the Debug build (it's possible to do so in Release build, it's a checkbox). That will create larger binaries to support debugging;
Fourth make sure you're using the LLVM compiler. It takes more time to compile but it generates better (and smaller) code;
Those initial checks are pretty easy to do and are the most common reasons for getting very large binaries.
To understand where the size come from you need to know how the application are built.
The main difference between the Android and iOS version is that JIT'ing (just-in-time compilation) is not allowed on iOS (Apple's rules).
That means the code must be AOT'ed (ahead-of-time compilation) and that process creates much larger executables (because IL is way more compact than native code);
If your code is generic-heavy then the final binary can get quite large since it will need to natively compile every generic possibilities (many cases can be shared, but value-types cannot).
What you can do to reduce size:
First try to reduce your managed code size. The easy way to do this is the enable the linker on every assemblies, i.e. Link all assemblies in your project options.
Many people think it's not worth linking their own code - because they know it will be needed at runtime (so the linker cannot remove it) or else they would not have written that code.
That's half true. The linker might not be able to remove most of your application code but if you're using 3rd party assemblies they are not likely 100% used. The linker can remove that extra code (and also remove, from the SDK, all the code that is kept to support that unneeded code). The more shared code you have the more the linker can help you.
Less IL code means faster AOT time, which translate to faster builds and smaller final binaires (including the executable size).
Note: there's a lot of documents and blog entries on how you can control the linker to skip some assemblies, some types or method from being processed/removed.
Second try to reduce your native size. If you're building native libraries then have a second look at them as they will be statically (not dynamically) linked to your final binary (another rule for iOS applications). Some of them might not be worth (feature wise) their weight in your final binary (and there might be lighter alternatives).
Debugging should not be enabled, as it will make the build unnecessarily large.
For more information refer : https://learn.microsoft.com/en-us/xamarin/ios/deploy-test/app-distribution/app-store-distribution/publishing-to-the-app-store?tabs=windows
I had the same problem but in my case I had minimum os version set to 8 in the info.plist causing a larger .ipa file. I changed this to version 10 and was able to pass the size requirements. Even 10 is a bit generous

Resources