Xcode external build tool target with dependencies on built executables - xcode

I am writing a swift CLI app, and am doing acceptance testing on it using Bats (Bash Automated Testing System). I have an "external build tool" target that invokes bats from a shell script. This target declares dependencies on a few CLI app executable targets (including my main app). Then I have a scheme that builds the Bats target and also runs an XCTest target.
I haven't been able to consistently guarantee that the executable dependencies finish building completely before the Bats script is invoked. Whether I declare my scheme as parallelizable or not, I will inconsistently run into issues where the Bats script is invoked, but it can't find one of the executables it depends on since it hasn't yet been added to $TARGET_BUILD_DIR.
From the build logs, I can always see that the needed executable target has finished compiling, but when the issue occurs, the target is conspicuously missing completed steps for Link <executable>, Sign <executable>, and Register execution policy exception for <executable>.
My best interpretation of the problem is that Xcode releases locks for the target with the dependencies only once all dependencies have finished compiling, and not necessarily when the builds for those targets have completed fully.
The most reliable workaround I have found is to sleep 1 in my shell script before invoking Bats. I also tried putting an aggregate target in between my external build tool target and the dependencies, but this didn't work reliably. Is there a way to have Xcode delay execution of the external build tool until the build of the dependent targets has fully completed?

Related

XCTest: running tests fails with Cycle inside X; building could produce unreliable results in project with CocoaPods and Carthage

After upgrading my project to Xcode 12, the test suite stopped working. The tests target doesn't compile, fails with:
Cycle inside <redacted>Tests; building could produce unreliable results. This usually can be resolved by moving the shell script phase '[CP] Embed Pods Frameworks' so that it runs before the build phase that depends on its outputs.
Cycle details:
→ Target '<redacted>Tests' has copy command from '/Applications/Xcode12.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework' to '<redacted>/Library/Developer/Xcode/DerivedData/<redacted>-bxjgdjscysiavpfrzmquaqdkncsl/Build/Products/Debug-iphonesimulator/<redacted>.app/Frameworks/XCTAutomationSupport.framework'
○ Target '<redacted>Tests': CodeSign <redacted>/Library/Developer/Xcode/DerivedData/<redacted>-bxjgdjscysiavpfrzmquaqdkncsl/Build/Products/Debug-iphonesimulator/<redacted>.app/PlugIns/<redacted>Tests.xctest/Frameworks/CryptoSwift.framework
○ That command depends on command in Target '<redacted>Tests': script phase “[CP] Embed Pods Frameworks”
The script is the last build phase in the target so I'm a bit lost. Any clue? Thank you.
I found a solution for my issue. The error is mentioning CodeSign and it is related with Frameworks/CryptoSwift.framework (this framework is linked using Carthage), so I guessed that it has nothing to do with CocoaPods but with the way that Carthage frameworks are included in the test bundle.
Just remove the "Code Sign On Copy" from the Carthage build phase.

Xcode 9 perform a custom command on clean

I need to run a custom shell script on the clean step in Xcode (Xcode 9 to be exact). I have a set of makefiles that build my dependencies, initially I was calling this script in the run script phase, but then the outputs of these makefiles never get cleaned. So I though that if I handled the Xcode environemnt variable ${ACTION} in this script then it could also clean them. The issue is - the script is not called on clean.
There were several posts regarding this so here is what I've tried:
Making an additional aggregate target. I added the target and put a script that handles ${ACTION} from the build environment, but that script is never executed upon clean. When cleaning there is only a Clean.remove clean line in build log.
Making an external build system target (some older posts stated an external script target, but I could not find that in Xcode 9). This then allows me to execute a custom script (if I replace the default /usr/bin/make command to my script), but in this case the ${ACTION} environment variable is not set (I verified this in the build output, it always has export ACTION= in it), thus I cannot distinguish between clean and build phases.
Regarding the aggregate target, it has the output files property, if I specify them - could that make Xcode clean them?
A bit of a zombie, but closest to the issue that I am seeing. This appears to be a bug in the new build system. Using the old build system, the action is set. Two options here:
Use the Legacy build system.
Use separate external targets that call your script and manually pass the action parameter required and swap schemes manually as needed.

How do I add compile sources via a run script build phase in XCode?

I have an XCode project which I would like to add source files to via scripting.
Is it possible to add compile sources via a run script build phase?
If so, how would I go about this?
I haven't found any documentation or examples of this, so I'm not sure it's possible.
You can create target that runs script. In this script any sources could be passed to xcodebuild arguments.
If this is not what is needed, XCode project by itself is an xml, so any files could be added to any targets, but project should be reloaded after, so I don't know how to add files to target withing runnign this target build.

Extra verbose output from mdtool?

I'm working on a project in Xamarin.iOS, and it happens to go through a build server (running on a Mac).
The build seems to commonly fail, but even with the --verbose or -v it seems to Silently fail. For example, right now, it seems to fail after optimizing the graphics for iOS. The last line of the build says Build complete -- 0 errors, 0 warnings. But then I get a Build step 'Execute shell' marked build as failure from Jenkins. I know that this is a failure in the mdtool build, because I have had a successful build before, and I know there are several more steps before it actually succeeds.
The next step in the successful process should be Compiling to native code, but for some reason it fails before getting to that, or at least outputting it to the console.
Thanks in advance for the help!
There's a few places in the mdtool build logic that didn't properly catch exceptions when executing shell programs which I (hopefully) fixed for Xamarin Studio 4.0.2.
Without seeing the full build log it's hard to say for sure, but it might be that whatever shell command that it is trying to execute either doesn't exist or isn't marked with execute permissions.
The programs that I can think of off the top of my head that mdtool will invoke for the iOS builds are:
pngcrush (optimizes .png files)
plutil (optimizes .plist and .strings files)
codesign (although this one gets called after compiling to native code)
and of course, mtouch which is what is used to compile IL to native code. The mtouch command is part of Xamarin.iOS while the other 3 utilities are part of Mac OS X (or Xcode).
The solution for the other person with a similar problem that I helped debug a week or 2 ago was because he had modified his PATH environment that launchd launched apps with to not include /usr/bin and so mdtool couldn't find the utility programs listed above.
I'm not very familiar with Jenkins (I know we use it at Xamarin, but I'm not part of the team that does), so make sure that the PATH environment that it launches mdtool under is setup to include /usr/bin.
Hope that helps.

Automatically Creating A Zip after Code Signing in Xcode

I have a custom script step in my build process that zips the executable. However this is executing before the executable is signed which is pretty useless.
Is there a way to zip the build output after the code is signed, within the Xcode build process. I can certainly do it externally if i need to, but I'd like to make it part of my Xcode build script.
Generally you'd create an Aggregate Target that first builds your main target, then runs a Run Script Build Phase to postprocess it.

Resources