xcodebuild not doing incremental builds - ios

I recently checked out a fresh version of our iOS app from git and built from command line via xcodebuild. I then built a second time using the exact same command, while making no changes to files in the repo whatsoever (not even opening them).
I expected the second build to take no time at all, but it actually took longer than the first:
user$ time xcodebuild -sdk 'iphonesimulator' -scheme 'DemoApp' -configuration 'Debug' -target 'DemoApp' build > /dev/null
real 5m45.849s
user 0m15.270s
sys 0m5.640s
user$ time xcodebuild -sdk 'iphonesimulator' -scheme 'DemoApp' -configuration 'Debug' -target 'DemoApp' build > /dev/null
real 6m8.858s
user 0m12.904s
sys 0m4.198s
If I do builds in xcode with no changes, it builds and runs in a matter of seconds.
Here are things I've tried to get incremental builds on command line:
I tried adding -derivedDataPath ~/Library/Developer/Xcode/DerivedData, but got the same results.
I've added the -incremental flag to other Swift arguments.
I've turned off all shell scripts and ensured no files have changed between builds
Does xcodebuild not support incremental builds? Is there a way to figure out why this is happening?
I'm using the latest Xcode and the new Xcode 10 build system. Most of the code is in swift if that makes any difference.
Edit: changing back to the old build system builds incrementally via xcodebuild in under 30 seconds.
Update:
The way I'm testing this: I have a Jenkins job that will clone the repo and do a hard clean: running xcodebuild clean and deleting the build directory and and derived data directory by hand just in case. Then it does a build. Then it makes no changes and does a build again. The second build is the one I'm timing.

Related

Build multiple targets with xcodebuild in parallel

I'm trying to xcodebuild multiple targets (but not all, just 3/5) in parallel to save time.
I tried already:
do it locally on my Mac by starting background thread for every target and calling xcodebuild on it - no success, build time is the same as calling xcodebuild x times one after another
do it using GitLab CI by creating separate jobs for every scheme - I can see 2 jobs running at the same time in GitLab UI but overall build time does not change
I call xcodebuild like this:
xcodebuild archive -workspace "ProjectName.xcworkspace" -scheme "SCHEME_TO_BUILD" -archivePath $ARCHIVE_PATH -allowProvisioningUpdates -parallelizeTargets -jobs 8
So is it even possible to build multiple targets at once and save some time?

Automatically run tests with each build in Xcode 6

When I run
xcodebuild -workspace ~/Documents/JudgecardXSwift/JudgecardXSwift.xcworkspace -scheme JudgecardXSwift -destination 'platform=iOS Simulator,name=iPhone 6' clean test
from command line, I can successfully run all of my tests.
Now I want to add a run script phase to my Xcode project so it will always run my tests each time I run the app. However, when I added the run script phase with the above xcodebuild command, my build always hangs:
and as you can see, it must be hanging on the run script phase I added, because it has just finished the build phase before it titled Run custom shell script 'Copy Pods Resources':
Is my method of adding a run script phase with the xcodebuild command the proper way to automatically run tests with every build? Why does it cause my build process to hang? Is it causing some kind of infinite loop with each xcodebuild command kicking off another through its run script phase?
Bit late here, so thought I would add my personal experience, but xcodebuild will kick off another build for you, importantly xcodebuild via command line as you have may not run your Build Phases as expected. I have only experienced silent failing copy commands, with those I could view the command in log files, but it did not actually copy the file.
So it may hit an infinite loop, more likely though is it's running through that build, hitting xcodebuild command, and then building as normal without some Build Phases executing properly and thus without running your tests.
In Xcode 9 this works. I've added a run script with:
echo "warning: 🚕🚕🚕 Started running myTests 🚕🚕🚕"
xcodebuild -sdk iphonesimulator -workspace myWorkspace.xcworkspace -scheme "myWorkspaceTests" test -destination 'platform=iOS Simulator,name=iPhone X,OS=11.2' CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
And if one of the tests fail, you're gonna get a build error.

Xcodebuild is not creating an app

I'm trying to create a simulator app to submit to Facebook for review. I've followed their instructions to the letter, but keep running into problems. I am using CocoaPods and have a workspace instead of a plain old project. Here's the command I'm running:
xcodebuild -arch i386 -sdk iphonesimulator8.1 -workspace [APP].xcworkspace -scheme [APP]
I get a ** BUILD SUCCEEDED ** message, but either one of two things will happen:
No build folder is created, and I can't find where the .App file is.
A .App is created in a build folder, but is 0 bytes in size and crashes when running with ios-sim.
I read that changing the Run scheme to 'Release' might fix it, but that didn't do anything. Any ideas?
So, I had the same problem and solved it by doing the following:
I made my app as release build instead of debug in xcode: Product->Scheme->Edit Scheme and then Build Configuration set to Release.
After doing this I then went back to the command line and added a destination for the build:
xcodebuild -arch i386 -sdk iphonesimulator8.1 -workspace [APP].xcworkspace -scheme [APP] -derivedDataPath /path/to/build
If you are still having problems make sure you clean and build all of your targets (pods included) and try the above steps again.
Hope this works; it did for me.

Why won't my build phase scripts be executed when creating an IPA from command line?

Question - short version:
Why won't my build phase scripts be executed when creating an IPA from the command line?
When I'm running xcodebuild to create an IPA the predefined build phase scripts does not get executed. Why is that?
Question - lengthy version:
I have a workspace with a scheme I want to create an IPA out of from command line.
This works fine except for one thing; I have two scripts in the build phases of the target that is used to put the correct app version (CFBundleShortVersionString) and the correct svn revision number (CFBundleVersion). These to scripts works fine when archiving from xcode but for some reason they do not get run when archiving from command line.
First of all why is that?
Here are the scripts that are working (if archiving form xCode)
When archiving and creating the IPA from the command line I do (the essentials)
# Building
xcodebuild ARCHS="armv7 armv7s" ONLY_ACTIVE_ARCH=NO -workspace MyWorkspace.xcworkspace/ -scheme MyScheme CONFIGURATION_BUILD_DIR=${PROJECT_BUILD_DIR} -configuration Release clean build
# Creating IPA
/usr/bin/xcrun -sdk iphoneos PackageApplication -v "${PROJECT_BUILD_DIR}/${APPLICATION_NAME}.app" -o "${IPA_OUTPUT_PATH}/${APPLICATION_NAME}.ipa"
It works and creates an IPA but none of the build phase scripts gets executed leaving both the revision number and version number untouched.
All suggestions are appreciated!
UPDATE DUE TO BDASH's ANSWER
Instead of making a clean build I make an install as
xcodebuild install ARCHS="armv7 armv7s" ONLY_ACTIVE_ARCH=NO -workspace MyWorkspace.xcworkspace/ -scheme MyScheme CONFIGURATION_BUILD_DIR=${PROJECT_BUILD_DIR} -configuration Release
The predefined script will IN FACT be executed (can be seen in the project version number) with no errors during the install. However the created IPA will have a size of ~300 bytes (instead of ~10MB) and cannot be installed on a device.
Building the app before installing it, i.e.
# Building
xcodebuild clean build ARCHS="armv7 armv7s" ONLY_ACTIVE_ARCH=NO -workspace MyWorkspace.xcworkspace/ -scheme MyScheme CONFIGURATION_BUILD_DIR=${PROJECT_BUILD_DIR} -configuration Release
# Installing
xcodebuild install ARCHS="armv7 armv7s" ONLY_ACTIVE_ARCH=NO -workspace MyWorkspace.xcworkspace/ -scheme MyScheme CONFIGURATION_BUILD_DIR=${PROJECT_BUILD_DIR} -configuration Release
and then creating the IPA will result in an IPA with executed version script and of correct size BUT it is not possible installing it on a device. Trying to put it on a device will give an error message saying
"The program "MyApp" was not installed on you iPhone device "My Device" because an unknown error has occurred."
You have "Run script only when installing" checked for at least one of the script phases. That phase won't be run when using the build action to xcodebuild, only if using the install action.

How to create XCode archive without a clean build

We have a fairly large code base that takes a long time to clean build. Whenever we archive the build (Product->Archive) the archive process first cleans all, then builds.
This seems unnecessary and time-consuming, we would like to be able to create an archive without a clean build. Incremental builds should be fine.
Does anybody know how to disable the "clean all" step during the XCode archive process? Thank you so much, my searches on this have come up with nothing but advice on how to make a build faster (which is not useful advice for us).
Yes, it is possible.
As I suspected would be the case this can be done from the command-line. It took us a while to figure this out. Here is an excerpt from our TeamCity build scripts. Basically you generate a build (clean or incremental is your choice), then generate and .ipa from the build. Here is one option (developer identity and provision profile ID removed of course):
export CODESIGN_ALLOCATE="/Applications/Xcode.app/Contents/Developer/usr/bin/codesign_allocate"
xcodebuild -project <PROJECT NAME>.xcodeproj -target <PROJECT NAME> -configuration Release -sdk iphoneos -arch armv7 ONLY_ACTIVE_ARCH=NO CONTRIB_PATH=%system.agent.home.dir%/Contrib2 CODE_SIGN_IDENTITY="iPhone Developer: <DEV NAME> (ID)"  
PROVISIONING_PROFILE=<PROFILE ID>
rm -rf Payload
mkdir Payload
cp -R build/Release-iphoneos/ Payload/
rm ~/<PROJECT NAME>.ipa
xcrun -sdk iphoneos PackageApplication -v Payload/<PROJECT NAME>.app -o ~/<PROJECT NAME>.ipa --sign "iPhone Developer: <DEV NAME> (ID)" --embed ~/Library/MobileDevice/Provisioning\ Profiles/<PROFILE ID>.mobileprovision
How about setting up a continuous integration server, so that every commit can trigger a process that results in an archived build. . . (hopefully after running tests, etc first), as well as publishing API docs, et al.
It will still take the same amount of time, but since its running in the background after every checkin of code, and the latest release candidate will always be available - you probably won't notice.
Otherwise, you run into a headache where you have to do your development in Release mode instead of debug, etc - its just not going to work.
Here's an example of an (OSX) project that includes a build script that can be run by a continuous integration server. I used Bamboo, but if you want something free there's also eg Jenkins:
https://github.com/jasperblues
In the above project, each successful build (triggered whenever someone commits code) publishes API docs and test coverage reports back up to the github page. . . for an iOS project you could also have it do archiving.
Incremental builds are not fine for Archive. The point of the clean is because sometimes you can get issues in incremental builds that a clean fixes. That's an acceptable problem to have during development, but Archive is intended for distribution builds, and distribution builds should not have this risk at all.
Not to mention, your normal build process is building a Debug build, and Archive is going to build a Release build, so you're going to need to rebuild most of the app anyway (anything that changed since your last Release build).

Resources