Output compile durations for swift files - swift

Is there a way to output the time taken to compile a swift file during an xcode build?
I would like to compile from the command line to trigger the same build xcode does but to include the time taken to compile each file.
The Report Navigator show full build reports per file but there is no timeframe associated with them.
I would like to cut down the compile time of a Swift 1.2 project, as it takes around 5 - 10 minutes after a clean or 3 -5 minutes after changing source in a heavily dependent file.

You can add…
-Xfrontend -debug-time-function-bodies
…to Other Swift Flags in Swift Compiler - Custom Flags section (build settings).
Note: You have to keep same order of these flags. -Xfrontend says that the next flag should be passed to the frontend. It will not work if you reverse the order.
Then you can get compile times in your build log:
Which is useful when you do want to optimize compile time and also it's good to attach this kind of build log when reporting an issue to Apple Swift guys about slow compile time.
Credit goes to Joe Pamer Errant compiler hacker. Currently an engineering manager at Apple (Swift, Clang), formerly at Microsoft (TypeScript, F#, JavaScript, .NET). He tweeted it as a response to Rob Rix question about profiling Swift compilation. It made me curious, so, I disassembled compiler, checked text section for more flags and found other hidden options. Don't use them in production code, just play with them.
Build time of the whole project. Run following command in terminal…
defaults write com.apple.dt.Xcode ShowBuildOperationDuration YES
…restart Xcode, clean & build and…
What if I have pods?
Do same as above for your pods project

Related

Xcode 8 does full project rebuild

Having updated Swift + ObjC project to Xcode 8 (Swift 2.3) I found 50% or more of the time Xcode does a full rebuild of the project instead of an incremental build.
The changes made are adding simple print statements. There seems to be no logic as to when it performs a full rebuild.
It appears in the "Check dependencies" phase it decides this. On Xcode 7 this did not seem to be a problem.
Has anyone else encountered this?
I have found this works consistently, it will however compile swift files if you modify a header included in the bridging header. It will also do full compile if you switch git branches back and forth.
Firstly make sure optimization level for debug is set to None (Not whole module optimization)
Then, according to https://forums.developer.apple.com/thread/62737 Apple Staff (ddunbar):
We believe that setting:
HEADERMAP_USES_VFS = YES
to true in your project (or for all your targets) may be an effective workaround > for many people. This is not guaranteed to work (which is the reason it isn't > already on by default), but it should work for most projects.
This should be added through "Add user-defined setting" under your target Build Settings.
.
Ok, here's an answer to why it's happening, but I don't know the solution. If you use the "Other Swift Flag" -driver-show-incremental Xcode will output what it decides it needs to compile based upon it's dependancies. You'll see things like:
Queuing EditProfileViewController.swift because of dependencies discovered later
Queuing ChangePasswordViewController.swift because of dependencies discovered later
Queuing JoinViewController.swift because of dependencies discovered later
Queuing JoinProfileViewController.swift because of dependencies discovered later
Queuing FormViewBuildable.swift because of dependencies discovered later
Queuing RadioTextFormView.swift because of dependencies discovered later
Queuing TextFieldFormView.swift because of dependencies discovered later
Queuing AccountProfileViewController.swift because of dependencies discovered later
I'm wondering if this is a swift 3 problem, because I wasn't having this issue before converting. I made a little example project where
FileA inclues a thing from FileB includes a thing from FileC
and even adding a file private change to FileC that's not used anywhere causes FileA, FileB, and FileC to be queued for compilation due to dependencies. I'm going to be testing this example in Xcode 7 later today to see what happens.
So it looks like swift 3's dependency resolution isn't working very well. I've tested this on 2 other swift 3 projects at work, and the same holds true. Make any change in any file, and every file gets compiled. It doesn't feel slow until you start getting to projects with about 15,000 lines of code or so, which may be why nobody is talking much about this. Unless you have a somewhat medium sized swift 3 app, you probably won't even notice that incremental complication isn't working quite right. I'll update if I learn anything more.
Apple released new beta version of Xcode yesterday (Nov 14)
Xcode 8.2 beta 2
And this issue has been marked as resolved in the release note.
Build System
• Xcode will not rebuild an entire target when only small
changes have occurred. (28892475)
It is working for me. The build speed came back as usual.
Everybody who is facing this issue, should give it a try!
https://developer.apple.com/download/
Unchecking "Find Implicit Dependencies" in Edit Scheme > "Scheme" > Build tab fixed it for me for project files. "Copy swift standard libraries" still takes forever..

How to run and debug unit tests for an iPhone application

NOTE: Unit testing is a lot easier to setup nowadays. This tutorial is not really relevant for Xcode version 5 and above.
It took me quite some time but I finally managed to make it work for my project.
To create the "logic" tests I followed Apple guidelines on creating logic tests.
This works fine once you understand that the logic tests are run during build.
To be able to debug those tests it is required to create a custom executable that will call those tests. The article by Sean Miceli on the Grokking Cocoa blog provides all the information to do this. Following it however did not yield immediate success and needed some tweaking.
I will go over the main steps presented in Sean's tutorial providing some "for dummies" outline which took me some time to figure out:
Setup a target that contains the unit tests but DOES NOT run them
Setup the otest executable to run the tests
Setup the otest environment variables so that otest can find your unit tests
The following was performed with XCode 3.2.5
Note for XCode 4
In XCode 4 it is possible to debug your unit tests DIRECTLY. Just write your test, add it to your target as one of the tests and set a breakpoint in it. That's all. More will come.
Step 1 - Setting up the target
Duplicate your unit tests target located under your project Targets. This will also create a duplicate of your unit tests product (.octest file). In the figure below "LogicTest" is the original target.
Rename both the unit tests target and the unit tests product (.octest file) to the same name. In the figure below "LogicTestsDebug" is the duplicate target.
Delete the RunScript phase of the new target
The name of both can be anything but I would avoid spaces.
Step 2 - Setting up otest
The most important point here is to get the correct otest, i.e. the one for your current iOS and not the default Mac version. This is well described in Sean's tutorial. Here are a few more details which helped me setting things right:
Go Project->New Custom Executable. This will pop open a window prompting you to enter an Executable Name and an Executable Path.
Type anything you wish for the name.
Copy paste the path to your iOS otest executable. In my case this was /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/Developer/usr/bin/otest
Press enter. This will bring you to the configuration page of your executable.
The only thing to change at this point is to select "Path Type: Relative to current SDK". Do not type in the path, this was done at step 3.
Step 3 - Setting up the otest arguments and environment variables
The otest arguments are straightforward to setup... But this proved to be my biggest problem. I initially had named my logic test target "LogicTests Debug". With this name and "LogicTests Debug.octest" (with quotes) as argument to otest I kept having otest terminating with exit code 1 and NEVER stopping into my code...
The solution: no space in your target name!
The arguments to otest are:
-SenTest Self (or All or a test name - type man otest in terminal to get the list)
{LogicTestsDebug}.octest - Where {LogicTestsDebug} needs to be replaced by your logic test bundle name.
Here is the list of environment variables for copy/pasting:
DYLD_ROOT_PATH: $SDKROOT
DYLD_FRAMEWORK_PATH: "${BUILD_PRODUCTS_DIR}: ${SDK_ROOT}:${DYLD_FRAMEWORK_PATH}"
IPHONE_SIMULATOR_ROOT: $SDKROOT
CFFIXED_USER_HOME: "${HOME}/Library/Application Support/iPhone Simulator/User"
DYLD_LIBRARY_PATH: ${BUILD_PRODUCTS_DIR}:${DYLD_LIBRARY_PATH}
DYLD_NEW_LOCAL_SHARED_REGIONS: YES
DYLD_NO_FIX_PREBINDING: YES
Note that I also tried the DYLD_FORCE_FLAT_NAMESPACE but this simply made otest crash.
Step 4 - Running your otest executable
To run your otest executable and start debugging your tests you need to:
Set your active target to your unit test target (LogicTestsDebug in my case)
Set your active executable to your otest executable
You can build and run your executable and debug your tests with breakpoints.
As a side note if you are having problems running your otest executable it can be related to:
Faulty path. I had lots of problem initially because I was pointing to the mac otest. I kept crashing on launch with termination code 6.
Faulty arguments. Until I removed the space from bundle (.octest) name I kept having otest crash with exit code 1.
Wrong path in environment variables. Sean tutorial has lots of follow-up questions giving some insight on what other people tried. The set I have now seems to work so I suggest you start with this.
You may get some message in the console which might lead you to think something is wrong with your environment variables. You may notice a message regarding CFPreferences. This message is not preventing the tests from running properly so don't focus on it f you have problems running otest.
Last once everything is working you will be able to stop at breakpoints in your tests.
One last thing...
I've read on many blogs that the main limitation of the integrated XCode SenTestKit is that tests cannot be run while building the application. Well as it turns out this is in fact quite easy to manage. You simply need to add your Logic tests bundle as a dependency to your application project. This will make sure your logic tests bundle is built, i.e. all tests are run, before your application is built.
To do this you can drag and drop your logic test bundle onto your application target.
This post is intended as a "How-to" more than a real question. Therefore this answer is just meant to allow me to mark the "How-to" as "answered". This will probably be flagged by the community as irregular. I'm up for suggestions on where to post future "How-to" articles.
One final note though on this topic.
For those who still wonder whether writing unit tests is worth it I would definitely say Yes!
I am currently writing an application with CoreData and retrieval of data from a web service (xml parsing). The complete model can be tested and debugged without having to:
run the actual application on the simulator or device. Not having to use the device to run the tests is a huge gain of time. It's the difference between 2 minutes and 5 seconds per run.
without the need to create views or controllers when testing the model. The complete development and testing can focus on the model only in the first iteration. Once the model is cleared for integration the rest of the development can follow.
To debug the xml parsing I can simply use "hard-coded" files which I completely control.
The crux is of course to write the tests as you implement features in the code. It really is a time saver down the line in terms of debugging of the complete application.
Voilà, I'll leave it at that.
I was able to run the test case in debugger in the following simple steps:
Product > Build For > Testing
Put a break point in part of the test you want to debug
Product > Test
This is on Xcode 6.0.1 and seems much more convenient than the long procedure described above.

Unit testing in XCode 4

I've managed to set up unit tests for my library in Xcode 4. I've performed builds with tests that I know will pass and fail (i.e. STAssertTrue(YES) and STAssertTrue(NO) ) just to make sure it's working. I'm using the default apple SenTest libraries following this document.
However, when my tests are running I'm getting this error in the build log :
An internal error occurred when handling command output: -[IDEActivityLogSectionRecorder endMarker]: unrecognized selector sent to instance 0x20310b580
To be clear, it's not affecting the running of the tests at all, just the output into the build window. All the tests run each time so I can tell a pass / fail by looking to see if the build succeeds or fails.
However, when my tests fail I can't find out which one fails because the output seems to stop when it gets to that error.
Does anyone have experience with unit testing / Xcode 4 / this error?
I just posted this on another thread, but I'm going the opposite direction for Xcode 4.
Please see my blog post exploring the topic, leave a comment if you think I'm wrong.
I realise it doesn't directly answer your question, but forget SenTestingKit and use GHUnit. It'll take you about 10 minutes to figure out (much more straightforward than OCUnit) and will save you a lot of headaches. IMHO, Apple should be shipping it with Xcode instead of OCUnit.
GHUnit can run your tests in a true application environment (with a GUI), or on the command line. It literally just drops into your existing project as a separate target.
https://github.com/gabriel/gh-unit

What happened to XCode Build and Analyze results?

This is similar to another question that wasn't really answered: Xcode 3.2: Build & Analyze never finds any issues
I used XCode's Build and Analyze for the first time on a large project and came up with a number of analyzer warnings. I corrected a few and wanted to verify my changes were being 'accepted' by the analyzer. I didn't even look at warnings in a number of files. But when I re-run Build and Analyze, all the warnings are gone.
I have tried: changing my compiler to LVVC GCC 4.2, switching from a debug to a release build, cleaning all (repeatedly), and quitting and reopening XCode. I just can't get the old warnings back.
Build and analyze only analyzes your modified files.
Go to your project settings -> build tab. And check 'Run Static Analyzer'. This runs a full check on all files on each build.
It is how XCode built with. Whenever, you build the project (even using build & analyze), it will build only those files which are modified before the last build. So if you want to have your old warning & analysis result back, do clean all targets from build menu & again build.
I had a similar issue some days ago. I had plenty of warnings, and after some changes in the code the analyzer warnings disappeared. Even a clean build could not bring them back.
By a coincidence I changed the message filter in the build log from Issues Only to All messages.
And there were plenty of messages related to the disappear of analyzer results. The analyzer complained that he could not analyze my files. I'm sorry I don't remember the correct message.
As far as I remember I put some code into the .pch which confused the analyzer completely. After I changed a lot of stuff analyzer was happy again. Magically. I still don't know why that happened and I can't reproduce it.
For whatever reason, none of the solutions above worked for me. The only way I could get the warnings back was to open the project with XCode 4 and analyze it there. I am taking screenshots so I don't lose these warnings. I hope the analyzer works better in XCode 4 in the future.

Minimizing the use of Xcode - how to quickly build and go from source code?

I realize I have to use Xcode to develop for the iphone, but I'm trying to build apps from raw source code generated outside of Xcode.
For example, I would like to "Build and Go" the apple demo "TheElements" (here). (I use this example because it has no .xib files - so Xcode is not needed for the UI).
It works to just unzip and open the .xcodeproj in there, but what if I had generated this code elsewhere and haven't yet used xcode? I.e., I have a directory of files (the contents of the .zip without the xcodeproj stuff):
./Default.png
./Images/*.png
./Classes/*.{h,m}
./Icon.png
./main.m
./Elements.plist
./Info.plist
./TheElements_Prefix.pch
Can I quickly (automatically?) get this built and running in the simulator?
I guess the question also relates to what information is really stored in the xcodeproj. Ideally, there would be some scriptable method for generating the project.pbxproj file, but sadly can't find this.
You might think of the Xcode project file as a glorified Makefile (if you're coming from the Unix world) or a VC solution file (if you're coming from Windows). It's a description of the dependencies between components and the steps required to build, link, and deploy those components. There is no more fundamental "Build and Go" than that.
On the iPhone, Xcode is required to build a viable application (technically, you could chain up the command line invocations used by Xcode—check the build log—but you'd be pretty crazy to bother). You can use a command line invocation (xcodebuild) instead of using the Xcode GUI app, but you still need a project file.