Xcode: project settings vs. target settings - xcode

I'm creating a static lib on Mac OS X for one of our customers, as well as a small cmd line app to test the static lib. The cmd line project has 2 extra library search paths, which meant I was linking to the Debug version in Release mode and just about went crazy, so I tried to get rid of these two paths, but I couldn't find where they were specified. I was looking in the project info, but it turns out they were specified in the target info.
I don't understand the distinction?! Why there are 2 sets of settings, which are essentially the same?! Can someone please enlighten me?

A project can contain multiple targets. For example, an app I write has four - the app itself, a Quick Look plugin, a framework and a bundle that contains Mac OS 10.6-specific functionality that can be dynamically loaded in.
Project settings apply to every single target in the project. Each target can then override individual settings if they need to - for instance, my project's Target SDK is set to 10.5, but the 10.6-specific bundle has it's Target SDK set to 10.6.
In some instances, some settings don't make sense to be in Project Settings - one of these, I guess, is search paths.

You often have multiple targets in a single project - for instance, you might have a framework project with a target for building as a dynamic .framework bundle, and a target for building a static lib. Or your app might have a target for building the app itself, and a target for building some helper command-line tool that it needs to install.
Wherever possible, I'd suggest changing settings at the highest level (in the project settings, and simultaneously changing debug & release configurations), and only customizing the target settings when necessary. Even better, move as many settings as possible into xcconfig files, which seem a much more explicit way of specifying your build setup.

Preface: you ship targets. Your end products are targets. Not projects. Think of a project as the umbrella above multiple targets.
For a more realistic example assume both Uber and Lyft were being developed by the your (umbrella) company.
The company has the following three environments:
Debug
QA
Release
The Debug and Release configs come out of the box with every new project you create. You can create as many additional configs as you want
This would require 3 configurations. To add a QA configuration follow the tutorial here
Did I apply this to the target or project?
I applied it to the project.
Ok so configs are only for projects and not for targets. Right?
Incorrect! It's confusing I know. You have to think of the project as a big container where you create your configs in there.
Then for each target (not project), for following tabs:
General, Resource Tags, Build rules, Info:
There is no difference between different configs
Signing and Capabilities tab:
You can switch between teams and sign it with a different team. This is useful if you want to sign your beta builds with your enterprise certificate but sign your Appstore build with app store certificate.
Build Settings tab:
For almost every variable in this section you can give a different value based on the config. Common Build Settings to customize are:
Architectures - 'Build Active Architecture only'
Build Options 'Debug Information Format'
Packaging
Set the plist you want per configuration.
Change the bundle identifier (Packaging >> Product Bundle Identifier). If you switch values for a field then in the plist you'll see as:
Signing
Code Signing identity
Code Signing Style (Manual or Automatic)
Development team
Provisioning Profile
Apple Clang - Optimization Level
If the values are different then the row's value would be
<Multiple values>
and you basically have to expand that value to see what value is given for debug and what value is given for Release or QA config.
If all the values are the same then you'll just see the value that is given to all of them. By default the values are the same.
Build Phases:
There's no out GUI way of switching based on configuration. However you can still do run certain commands based on the configuration. Example:
if [ "${CONFIGURATION}" = "Debug" ]; then
"${PODS_ROOT}/SwiftLint/swiftlint" autocorrect
"${PODS_ROOT}/SwiftLint/swiftlint"
fi
Summary
Long story short, this allows you to have 2 different apps (targets) with the same code (project), in 3 different environments (dev, QA, release). You create the different environments using configurations.
To learn more on this I highly recommend you to read more about this in depth and understand what configuration files (xcconfig) is. It's much more simpler than you think. It's mainly a key value pair:
AppCoda - Using Xcode Configuration (.xcconfig) to Manage Different Build Settings
NSHipster - Xcode Build Configuration Files

Related

Can an App Extension be conditionally included in a build?

I'm starting work on 2 app extensions, and I'd like to set up my builds as follows:
Builds intended for the App Store should not include either extension
Builds intended for TestFlight should include the extension that is almost ready
Local builds should include both extensions
Currently, I have a different build configuration for each of these to show and hide other aspects of the app (and compiler flags in some cases too). I use fastlane to make my builds.
As far as I can tell, the only ways to add or remove an app extension would be:
Duplicate the main target twice and use one for each of the above builds (drawback - must maintain 3 copies of the target until the extensions are fully complete)
Manually add/remove the extension before building (drawback - impossible to make both TestFlight and App Store builds from a given branch in a CI environment because manual intervention is required)
Can anyone think of a better solution for conditionally including the app extensions?

Declare a common Xcode variable for use in plist for all Xcode targets in a project/workspace

I have an Xcode project, which has multiple targets. I want to define a variable somewhere (a variable for build number, to be precise) where I can reference as the Bundle version in the Info.plist of each project without updating them individually. e.g. I'll set bundle version to $(BUILD_NUMBER) once (I've made up the name) for each target then I'll increment that BUILD_NUMBER variable on each release. Is this possible? If yes, how? I've seen Adding a build configuration in Xcode and How to create variables for use in Xcode build settings values? but the settings are greyed out:
First, you need to go to Build Settings and select a configuration (possibly Debug or Release). Then Add Conditional Setting or Add User-Defined Setting options will be enabled. This link illustrates how it is done.
Second, it might be error-prone to manually increment build number especially after some other developers step in and start working on the same project. You might want to consider using some CI solutions like fastlane instead. It makes use of agvtool for app versioning so you might want to also look at that as well.

In an Xcode 4 workspace, how do I cascade build settings & configs to subprojects

Overview
I'm using static libraries and Xcode 4 workspaces to effect modularity in iOS development, an increasingly common technique. For example, I might have a workspace which contains an App project, and a Library project, like so1:
You would then have a scheme to build these that looked something like this:
What I would like to do is have the "App build" control the "Library build" it initiates, in at least a couple of ways:
Map App configurations (e.g. Debug, AdHoc) to arbitrary Library configurations
Passing through some subset of -D defines, and/or specifying these for the library build.
I'll deal with each of these in their own section, but it's worth making a few clarifications.
Clarifications
I'm using App/Library here as an easy proxy for any Superproject/Subproject relationship you may have.
From what I've seen, Xcode 3 style embedded subprojects don't seem to work any differently in Xcode 4 than workspace "peers". I'd love to be wrong about this.
I know I could do almost anything with a "Run Build Script" build phase, and xcodebuild. But I'm trying to work within the system here, where the dependencies are specified in the scheme, and otherwise somewhat loosely coupled.
The Library exists to be used in more than just this project, and so you cannot arbitrarily load it up with junk specific to this App's build, or reference anything particular to the App or Workspace. For the general case, this rules out including static .xcconfig from the App project as a way to convey build information from the App to the Library.
Building the Library outside the workspace sacrifices too much, not an option.
Configuration Mapping
As I understand it, building a particular App configuration will:
If a configuration exists in the Library of the same name, it will build the Library using that.
Otherwise, it will build the active configuration of the Library, as specified in the Library's project file.
To my knowledge, without resorting to the aforementioned run-build-script hack, that is the extent of the control one has over subproject build configurations. Please tell me different.
Ideally, I would be able to specify (in the scheme, presumably):
AppConfigA -> LibConfig1
AppConfigB -> LibConfig2
While Debug, AdHoc, & Release may be the only configurations some ever use, complex projects often outgrow that.
Defines
I've not yet found way to pass -D defines from the App build to the Library, without resorting to xcodebuild, which can take, e.g., an .xcconfig file.
The App's build settings can be accessed in Library build run-build-script phase. However, doing that introduces a dependency in the Library on the App project, which for good reason is verboten (cf. Clarifications). But even then, I haven't found a way to use those settings to directly control the Library's build (much2).
So crazy it just might...
One scheme I came up with while writing this would be:
The Library bases it's build configurations on an empty (dummy) LibraryExternals.xcconfig file within it's own project.
A clean of Library deletes that file. A standalone build of the Library will create an empty one if it does not already exist.
That file is overwritten by an App Build run-build-script phase, and contains anything the app wants to communicate to the Library build.
Seems kind of complicated, but I'm looking for anything right now. I'll push this to an answer if nothing better comes along.
1 Apps shown are Max OS X. I find command line apps make for simpler tests. Same applies.
2 Cf. Info.plist preprocessing, which I learned about during this investigation.
If you modify your project structure to use a single project with multiple targets then each target's build settings will automatically inherit from the project. From there, you can modify ones that you want to be different, or select an individual setting and press the delete key to set it to the default specified by the project.

Using global properties or build steps in TeamCity

I have a lot of projects in my TeamCity server, for building and testing multiple sites. We use Selenium RC to test the sites every night, and I would like to reuse one step or configuration instead of having copies in each project.
I have looked into using Templates, but they only seem to be accessible from the project it is defined in. The same goes for properties, as I tried to put paths and some shared values in system or environment properties and using copied build steps using those shared properties.
But it all fails, as none of these methods seem to be usable across projects. How do you solve this type of issue? It must be possible somehow, right?
As per my comments for your question you can use a single template configuration build across multiple Projects.
See TeamCity documention for information on how to do this.
TeamCity has a new feature (as of 8.0) that supports global configs/parameters/env variables. 8.0 supports the new concept of project organization/nesting, and as part of that feature set all projects now inhert from the "Root" project. And on that root project you can specify a number of things, including parameters, etc. This does not appear to support build steps.
They documented the change in http://youtrack.jetbrains.com/issue/TW-11202.
--
You could achieve a "global property" by creating a dummy build configuration which has your shared properties then for all your builds which need access to the global properties you create a build dependency. When your real build configuration is called it will first call the dependent build configuration (which does nothing meaningful) then it passes the properties from the dependent config (with a dep.bt prefix instead of just the system prefix).
Depending on the logic you need in a shared build step you may be able to actually perform real logic in the dependent build (it won't be able to inherit any properties or VCS details from the "real" build).
Since this is a bit outdated, and the answers above aren't completely clear, thought I would post how I did this with TeamCity 8+.
Basically, a template can be used within the project and its children. If you move a template to the parent, it becomes available to all the siblings of the original project.
Go to the template.
Click the "Move" button (bottom-right pane).
Select a parent (or root).
Note: If the template is attached to a VCS root that is bound to the current project, you'll first have to move the VCS root to the same level to which you're trying to move the template.

How should I manage dependencies across projects in an Xcode workspace?

I'm working on an iOS app project, and add the json-framework project to the workspace. The project navigator on the left shows both projects, and the build scheme selector shows the schemes from both projects too. Now I want to add the libjson.a target from the json-framework project as a dependency on the iOS app target in the other project. The expected result is that whenever the app target is built, it builds (if necessary) the library target and links the app target against it. Here are the ways I've tried to do this:
Build both as part of the same scheme. The way I try this is to edit the scheme for my app, adding 'libjson.a' to the 'Build' portion of the scheme, and by the way "Find Implicit Dependencies" is checked. Then I go to the target editor for my app target, and in "Build Phases"->"Link Binary With Libraries", I choose 'libjson.a' from the list of workspace libraries.
When I subsequently try to build the scheme, I see it build the library target, but building the app target fails with linker error "Library not found for -ljson" - suggesting that it hasn't actually discovered that the library has been built. Indeed in the project navigator, the entry under the app project for the library is still red indicating that the file doesn't exist.
Add the json target as an explicit dependency. To try this, I don't modify the build scheme, but go to the target editor for my app target and click the add button under 'Target Dependencies'. No targets from other projects in the workspace show up, so this is a non-starter.
Drag the JSON project into the other project, then add the target as a dependency. This is what I would have done in Xcode 3. In the project navigator, I grab the library project and drag it over the app project. This brings up the usual 'add files' pane, which I just dismiss by clicking 'Finish'.
There are now two entries for the library project in the project navigator: one at the top level, and one under the app project. I can now add the library target as a dependency of the app target using the target editor, and can link against it without error in the link libraries phase. But it looks broken: there are multiple entries for the same project in the navigator. Is there a different way to do this?
What should be considered the "Xcode 4-ish" way of connecting these targets in different projects in the same workspace? It would seem lacking if multiple projects in the same workspace can't actually interact with each other.
Thanks,
Graham.
I’ve just set a test project up, pretty much as you describe in version 3, by creating a new workspace and dragging the two Xcode project into it, nested as shown.
You can delete the sibling project if you have it already.
Hitting build on this and it just works, as far as I can see.
I imagine there is internal path-confusion if you have two projects, and I’d be inclined to fiddle with location settings in "View"->"Utilities"->"File Inspector" and see what effect that has.
Another thing to try is to set your paths up in Xcode "Preferences…"->"Source Trees" and refer to them that way, as described here: Easy, Modular Code Sharing Across iPhone Apps: Static Libraries and Cross-Project References
HTH. Andy W.
I managed to get dependencies between projects in a workspace to work as I described here: http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/.
Unfortunately I can't find a way to get Xcode to discover implicit dependencies or index everything in the build as advertised. I found workaround to both but I'm hoping that less manual configuration will be needed as Xcode 4 matures.
I was going to ask the same question, thinking that my own solution couldn't be right. But I don't see it mentioned here, and it does seem to work. Clearly XCode 4 is a work in progress. :)
I have a workspace with two projects: a static library and an app which uses the library. The projects are siblings. Each project has its own scheme, and each scheme is set to only build one target. In other words, I added two projects to the workspace and that's it.
To add the static library as a dependency of the app, I just drag the libsomething.a product from the library project (Project Navigator) into the "Link Binary with Libraries" list for the app target. That's it. Now when I build the app the library project is built first and then linked. Interestingly, when I modify the app's scheme to use a different configuration (eg, Release instead of Debug), the library is built using the same configuration.
So it works, and there is clearly some automatic dependency checking going on here. But it feels wrong. Then again, so does the modal scheme editor/manager and lack of a workspace object in the project navigator... I never thought I'd say it, but the Visual Studio UI (bleh) is a lot clearer.
My bullet-proof solution to do this :
Create "Per Debug-Release / Per Architecture" settings in Build Settings in the Main project (not the lib), to include either
../MyLibProject/build/Debug-iphoneos
or
../MyLibProject/build/Release-iphonesimulator
or
etc..
depending on the configuration (you can create those kind of configuration by clicking on the + next to Debug or Release and choose either "Any iOS Simulator SDK" or "any iOS SDK".
You need to do that for both "Header Search Path" (in case your library copy some headers files, which is more than likely) AND for "Library Search Paths". Which means that for each setting, you'll probably end-up with 4 different paths (debug sim , debug ios, release sim, release ios).
That would make sure the configuration of both projects match.
Now, to auto-compile the lib, that is to create the dependency, you can use the "Build Phase -> Link to Binary With Libraries -> + -> select the .a file" advice given above.
That's the only way I managed to have something that builds and link correctly for every environment on xcode 4.5
Note : I even added the -lmyLib flag in "other linker flags", but i'm not sure that's really necessary
I've had some success with creating framework-like static libraries, though it's not a perfect solution.
I see the next variants:
Explicit dependency in a project[About]
Implicit dependency in a workspace[About]
See the Xcode user guide: Xcode Concepts -> Xcode workspace under 'Projects in a Workspace Share a Build Directory'.
All projects in a single workspace share a build directory. Dependencies are discovered automatically and build if needed:
"Xcode examines the files in the build directory to discover implicit dependencies. For example, if one project included in a workspace builds a library that is linked against by another project in the same workspace, Xcode automatically builds the library before building the other project, even if the build configuration does not make this dependency explicit. You can override such implicit dependencies with explicit build settings if necessary. For explicit dependencies, you must create project references."

Resources