Scheme Script vs. Build Phase Script - xcode

After I make a build I want to copy some files into my Xcode project.
I discovered that I could do this either in
In "Build Phases" with a custom build step.
I can also execute scripts before and after the different "tasks" in the Scheme editor:
Build (This is where I could add my script)
Run
Test
Profile
Analyze
Archive
I don't completely understand the differences / possible implications between the two approaches and I am wondering when to choose either approach. Thanks for clarification.

After I make a build I want to copy some files into my Xcode project.
I assume you want to copy files to your build product, not the Xcode project.
There are several subtle differences between scheme and build phase scripts. Here are some of them:
Scheme scripts are part of the scheme, so sharing with other developers is more configurable. Build phase scripts on the other hand are part of the target and cannot be skipped simply by choosing another scheme.
Scheme scripts can run before the dependency checking. So you can use them to modify source files and get up to date results. This is not possible with build phase scripts.
The information passed to the script in environment variables differs slightly. Depending on what information you need you sometimes have to choose right kind of script.
Build phase scripts are run conditionally only if the build process succeeds until their place in the target.
Build phase scripts can be configured to only run when input files changed.

There isn't much difference between the two, however you have more control where, in the build sequence, the build phases scripts are run and so this is preferable (for example you could modify files that have already been copied by standard Xcode build phases).
I always use Build Phases scripts myself and have never used Scheme scripts. They are more visible and more manageable.

Related

Change build settings prior to project build

I wrote a ruby script that changes some build settings through a .xcconfig file.
(Don't ask me why, but it improves our workflow quite a bit; different environments etc.)
And I put it in the first row (after 'Target Dependencies') in my Build Phases.
The only problem is when I build my app the variables defined in that xcconfig file are not used for that particular build. But for the build that follows.
The only reasonable explanation would be that the project build parameters are already set when the Build Phases start.
So my question is quite simple:
Is it possible to run a script before the project gets build. So I'm talking about pressing ⌘ + R; first my script runs and then fires up the project build.
Stuff I tried:
Using 'pre-actions' in build schemes
Using an 'External Build System' target
Using an 'Aggregate' target
None of them seem to give me the desired result

How to better split FAKE build script for Teamcity

Without Teamcity I would put everything into one big .fsx script and just "fire and forget" it. It would be OK to have a single script for the build, doing all the work.
But when we put .fsx script into Teamcity, everything changed. Teamcity has nice build log and build steps features, but putting all logic into the same script and build step resulted in HUGE build log.
We have build and tests in a single .fsx script, and I was going to place distributive building into it either. But now I don't think that this is a great idea. Perhaps it would be better to split this build script into several build scripts and run them in several build steps?
But with several scripts it's not too convenient to run build locally, without Teamcity if we need to. Or we can have several small build scripts for every task ans one build script for the local build calling all these small scripts.
What is the best solution for this?
This is my personal opinion and not a "best solution": I would not use multiple build steps or build pipelines in Teamcity since this will lead to vendor lock in.
That said if you still want to use build pipelines then use a single build file and make heavy use of FAKE's build targets and conditional dependencies.
if isLocalBuild then
A
==> B
==> C
So you can still run it locally like before.
In TeamCity define a build pipeline which calls only one target in every build step (using FAKE.exe target=A).
Well, I suppose I've done something similar to #forki23 suggestion. I've put everything into a single .fsx, defined several target's chains not related to each other, like this:
Clean ==> Build
BuildTests ==> RunTests
SignExes ==> PackDistr
and on each build step I call one "leaf" target, i.e.
Step1: fake build.fsx target=Build
Step2: fake build.fsx target=RunTests
Step3: fale build.fsx target=PackDistr
Locally, I created several .bat files for building locally, and I've defined target's call order in these .bat files. But I suppose it would really be better to use the isLocalBuild value as #forki23 suggested. This would make build logic more encapsulated into single .fsx script and that's great!

How to create Target that always runs at the end of a build

I've got a vxcproj with configuration type Driver and am trying to edit the project file to add a custom target that will always run at the end of building the project. I want it to run even if the standard build system detects it doesn't need to build anything.
I'm having a hard time trying to work out where to attach my target. If I attach to AfterBuild or PostBuildEvent, my target won't run if there's nothing to build.
If you're interested, I need this target to run run StampInf and Inf2Cat tasks as the built in versions of those don't suit my purposes. The built in ones always run and dirty outputs, causing knock on rebuilding which I don't want in an incremental build.
Add a project of type General + Makefile. VS cannot optimize the build for these type of projects, the custom Build Command Line setting you specify always runs. You'll typically need to set the project dependencies to ensure it runs last.

Dynamically adding resources to XCode project, always one cycle behind

I need to assemble resources for an application depeding on XCode build settings. The easiest way to achieve this, is through a build script phase. Although this works, this somehow always builds my target with resources one version lagging (a second build is needed to get things really up-to-date).
The Resources folder is a reference to a folder in which my script (or rather, custom built command line tool called from script) copies the appropriate resources. The run script build phase is the first (topmost) phase in my target.
A solution I've found on the web somewhere, is to create an "External Target" and add that to the original target's build phases (by dragging the External target onto the original target). This does indeed seem to fix the "one version behind" issue, but I cannot seem to get the current target's environment variables to be passed to this "External target".
Why is XCode not including the just updated resources? What other alternatives are there?
You could try to define an internal target (say, "ResourceTarget") and make the main target dependent on ResourceTarget. Then let your script run in the script build phase of ResourceTarget, so the resources are all updated when the second target is build.
That way, environment variables should be the same.

Specifying a subproject's Configuration in Xcode

I have an Xcode project (A) referencing another project (B). By default (as far as I understand it) Xcode will implicitly build the configuration for the B dependency that matches the configuration of the A's target (e.g., "Debug"). But what if I want, say, A to build as "Debug" and the B to build as "Release"? How would I go about specifying that in Xcode?
I don't know of any easy approach, but you can brute-force it by calling xcodebuild directly for the dependency with a "Run Script" build phase.
I know it was just an example, but if your real goal is that the sub-project be a Release (no symbols) build, then you may have a better experience by just building the sub-project into a library or framework and checking the resulting binary into your version control system. Whenever I have a piece of the system that seldom changes and that I don't want debug symbols for, I go ahead and build it as a static library and check it in. I often go ahead and move the code elsewhere as well (with a README file with the .a that says where the code is and how it was built). This saves time on both build and checkout and is invaluable for large projects in my experience.
This might help: if the configuration of the project A is not found, Xcode will build Release config as a fallback (or maybe the first config of the list).
Then you can "force" the link using this tip: Xcode custom build configuration causes "library/file not found" for static libraries
Yes, this is not naturally supported by Xcode; when you build a target, it builds one configuration of itself and of all dependent targets.
The workaround, as Rob mentioned, is to have a dependent target that's an Aggregate Target type that comprises a single Run Script build phase, which simply invokes xcodebuild -configuration Release (or whatever).
You can specify the default 'fallback' configuration in the project info.
Change from:
Use 'Release' for command-line builds.
to:
Use 'Debug' for command-line builds.
And default will be 'Debug'.
Diffs of project file:

Resources