Xcode project templates: How can I specify a static library dependency? - ios

I am trying to create an Xcode project template that contains two compilable targets, with one target (an app) dependent on the other (a static lib).
Everything works so far, except that I cannot figure out how to specify the actual dependency in the template so that it shows up in the Target Dependencies section of the Build Phases tab of the app target of an Xcode project created from the template.
I've configured the TemplateInfo.plist of the project as follows:
The Components section identifies the static library project template and successfully brings the contents of that template, and its target, into the app project. And once everything is compiled, the static library is successfully linked in the end, by Item 3 in the OTHER_LDFLAGS entry.
But try as I might, the Dependencies section of the template does not cause the static lib to appear in the Target Dependencies section of the Build Phases tab of the app target. I've tried specifying the dependency using the numeric values 0 and 1, and I've tried it as a string using the name of the static library target (cocos2d), but none of these work.
In the end, in each Xcode project created from this template, I'm left with users having to perform the step of navigating to the Target Dependencies section of the Build Phases tab of the app target, and manually selecting and adding the static library target. Although this is a relatively simple task, it shouldn't be necessary at all.
Can anyone advise me on how to configure the template dependencies so this manual step is not necessary?

As you've indicated, the Dependancies tag under Targets references target array indices. In the example you've posted, your dependency is under Components.
Components appear to be add as targets after the targets from your template file are added to the project. If you reference the Cocoa Touch Application template provided with Xcode, Cocoa Touch Application Unit Testing Bundle is included as a component.
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Temlpates/Application
Looking at the plist for the Cocoa Touch Application Unit Testing Bundle, there is a dependency on target 0. Given components appear to be added after "local" targets, target 0 is
present in the project when the unit test target is added and a dependency is created against the primary target.
Attempting this in reverse by adding a dependency on target 1 in the Cocoa Touch Application does not work.
The only work around that I've been able to find is to move Components to Ancestors and duplicate the Targets items from each component in the Targets section of your template. From there you can reference the indices of any components included in your targets array.
You should note that even with this technique, targets appear to be added to the project in order and you only seem to be able to set dependancies on indices that have already been added (i.e. index 0 cannot reference index 2).

Related

What targets should I be adding my files to in my xcode project

I'm working on an xcode app using swift and xcode 8.1.
I keep adding files such as pictures and .plist files to my main folder with my storyboard, but each time it asks what targets I want to add it to. Should I be adding it to my test targets as well? If so, why? Whats the rule to know what targets to add it to.
No, you shouldn't add your files to the test target. Unit test target has access to your application files anyway.
According to the Apple documentation, target is a single build artifact. Because of that, you should only add the files which are building blocks of a specific target.
A target specifies a product to build and contains the instructions for building the product from a set of files in a project or workspace. A target defines a single product; it organizes the inputs into the build system—the source files and instructions for processing those source files—required to build that product. Projects can contain one or more targets, each of which produces one product.
For the most basic scenario with one application target and two test targets the general rule is as follows
Add application classes to the application target.
Add unit test case classes to the unit tests target.
Add UI test classes to the ui tests target.
In more complex scenarios you can have more targets in your application. You can have iMessage extension, share extension etc. You can also have multiple targets for building variants of the same applications but the general rule stays the same.

Interdependent frameworks Xcode

I'm working on a set of (internal use only) frameworks that encapsulate various elements of my development process. Some of these frameworks are dependent on one another, but I'd like to keep them separate so as to be more manageable. I'm running into various compiler errors now which I think have to do with the dependencies overlapping.
At the moment all of these frameworks and an app share the same workspace as different projects. How can I configure my app and frameworks to compile in this situation?
Here's the boiled down idea:
App dependencies: A.framework B.framework C.framework D.framework
A.framework dependencies none
B.framework dependencies A.framework
C.framework dependencies A.framework B.framework
D.framework dependencies none
More info:
Currently, in C.framework, I have dragged A and B.frameworks into the "Frameworks" folder. I read elsewhere to do that an to not Link Binary With Libraries. Either way, I get a compiler error for some functions that are in the headers of both A and B.framework:
ld: symbol(s) not found for architecture armv7
The build settings for A & B have "Build Active Architectures Only" set to NO and valid architectures set to include "armv7".
B.framework, however has no issue building.
Update :
I'm now able to get the App to build, by Linking Binaries in each of the targets... however it immediately crashed with this error :
dyld: Library not loaded: #rpath/A.framework/A
Referenced from: /var/containers/Bundle/Application/94488FD7-B731-4E6B-86E6-3D2F09BB4E04/App.app/App
Reason: image not found
The problem most likely causing this error message is related to the libraries not building in the correct order.
One possible solution to the order the libraries get built lies in adding all dependent libraries as sub-projects to the main project. This is appropriate when all projects are owned and maintained by the same entity, as the OP mentioned.
Add each project to the main one by going to "Build Phases -> Link Binary With Libraries.", then add each framework project file using the "+" button. Then go to each sub-project, and add it's dependencies.
For B.framework project, go to "Link Binary With Libraries.", and add A.framework as a dependency.
Similarly, for C.framework, add A.framework and B.framework, as dependencies.
As a suggestion, also add all frameworks to "Link Binary With Libraries.", under the main project, all of them get used.
One thing to keep an eye out in such situation, is to make sure there are no circular dependencies, and dependencies don't get added multiple times in different projects.
The image below shows an example of a similar setup to the one in the OP. There is a FrameworkTest project. All 4 frameworks are added as "Link Binary With Libraries." under it. For FrameworkB, FrameworkA is added under "Link Binary With Libraries.". Similarly workflow for FrameworkC. Xcode seemed to figure out the dependencies without the need for "Target Dependancies" settings. This project builds and runs. Haven't gotten as far as calling items from each framework.
Another solution to this, using a workspace would be to have one top level project, and move each framework as a sub-project. Then add each framework to the top-level project's "Embedded Frameworks" section.
Use the "Link Binary With Libraries." section of each framework sub-project, to define its dependencies.
Ok, so I seem to have gotten past this in the following way.
Instead of having my workspace have each framework as a separate "top-level" project, I moved the framework projects into sub projects of the App project.
Then, I added each framework to the App's "Embed Frameworks" section (and was able to remove it from "Link Binary.." and "Target Dependencies" sections.
Within each framework, I used the "Link Binary..." section to include the dependent frameworks.
I'm not sure that I understand all the pieces to why this works, but at least I can move on!
Thanks #vel-genov for your help!
Make sure these settings are correct:
FRAMEWORK_SEARCH_PATHS (in Build Settings)
Link Binary With Libraries (in Build Phases)
INSTALL_PATH (change to #rpath for all frameworks) (in Build Phases)
#rpath (Runpath Search Paths) (add #executable_path/../Frameworks for your app and all frameworks that need embedded another framework) (in Build Settings)

How does Xcode find implicit target dependencies?

Xcode finds dependencies automatically sometimes. I think is is ok when I am the one who is defining the relationships and when I get lazy ...
But more than often I find myself facing an existent (medium to large size) project with several targets. Since the project has been made by someone else I find it very difficult to understand what targets depends on what since not all the relationships are explicit.
What are the rules Xcode use to find such relationships? ( I hope I can understand the logic so run it in my mind and maybe save me some time in the future) Or What makes a target qualifiable to be implicitly dependant of another?
A target and the product it creates can be related to another target. If a target requires the output of another target in order to build, the first target is said to depend upon the second. If both targets are in the same workspace, Xcode can discover the dependency, in which case it builds the products in the required order. Such a relationship is referred to as an implicit dependency.
Source: iOS Developer Library → Xcode Concepts → Xcode Target
This answer applies to Xcode 8.x, and I think for Xcode 9.0.
First off, you need to be sure that "Find Implicit Dependencies" is enabled in the the Build panel of the Scheme that you are attempting to build.
A target "A" can be made "implicitly" dependent on target "B" in two ways:
Target A has a "Link Binary With Libraries" build phase that has a library in its list that has the same name as a Product of B. This product can either be in the same project or another project in the workspace. Note that I said "same name". Just because you chose libA.a from target A doesn't mean that implicit dependencies will build it if you have another libA.a product in a different target. See below for details.
Target A has a "Copy Files Phase" that copies a file with a base name that matches a product of B. Normally a "Copy files" build phase cannot refer to a file that isn't in the same project as its target, but you can set up a dependency across projects if you create a dummy file for the "copy file" phase to copy that has the same name as a product of B. For example, if you have a workspace that contains two projects ProjectA and ProjectB. ProjectA has TargetA that creates libA.a, and ProjectB has TargetB that creates libB.a. TargetA could get TargetB to build libB.a by having a "fake" zero byte file as part of TargetA that happened to be named libB.a, and this would be sufficient to get libB.a made, even though the libB.a referred to in the "Copy Files" phase is a totally different file than the product output of the TargetB build. If you check the "Copy Only When Installing" box, Xcode won't actually perform the copy, but will still resolve the dependency. You can actually delete the fake file off your drive that you created solely to have something to put in the "Copy Files" phase (but you must leave it in your project).
So why would anyone ever want to do the horror that is "2"? I can come up with a couple of reasons.
TargetA needs some some files copied/generated by TargetB, but TargetB doesn't generate a library to link to. You could probably work around this by having TargetB generate up a small dummy library, but that may be painful for other reasons.
Let's say I had projectA, targetA and libA.a (and equivalents for project B, C and D), and libA.a depended on libB.a and libC.a which both needed libD.a to be built first (possibly some headers and/or sources generated). You could do it all using the "Link With Libraries" phase (aka solution #1) but in that case you would end up with two copies of the .o files in libD in the final linked version of libA. If you do this deep enough (eg a workspace that has 40 projects that have varying levels of dependencies on one another) you will quickly end up with huge library files with several identical .o files in them, and your link times will become horrific.
If you think these are contrived situations, I'm currently hitting both of them moving some legacy code from a series of explicit dependencies to implicit dependencies. Why am I moving to implicit dependencies? Because explicit dependencies in Xcode require project nesting, and once you get enough explicit dependencies, the project browser gets extremely slow, and you will see a lot of beachballs inside of Xcode for random things.
What happens if you happen to have two targets inside the same workspace that generate products with the same name and depend upon them from a third target? Implicit dependencies will pick one. It appears to do a match based on the base name of the product (so foo/bar.a and baz/bar.a are the same), and will pick the first one it finds.
Xcode Implicit Dependency
Xcode Dependency[About] is a dependency required to build a selected target.
Implicit dependency
source code aka Non-compiled dependencies. Xcode allows to add a dependency from the whole workspace. A good example is a Project from GitHub or CocoaPods[About] with source code
closed code aka Precompiled dependencies aka External - external binary, CocoaPods, Carthage with closed code
Implicit dependency is a dependency that is necessary to successfully build a target, but aren’t explicitly defined.
Specified in General -> Framework, Libraries, and Embedded Content or `Embedded Binaries and Linked Frameworks and Libraries[Link vs Embed]
No dependency in Build Phases -> Dependencies || Target Dependencies
To turn on this functionality[No such module]
Edit Scheme -> Build -> Find Implicit Dependencies
[Explicit dependency]
[Vocabulary]

Xcode: What is a target and scheme in plain language?

Yeah the title says it :-) What do they mean in plain English language? I really don't understand the explanation on Apple's website and I need to rename my target and I'm afraid that nothing works after that..
I've added in Workspace and Project too!
Workspace - Contains one or more projects. These projects usually relate to one another
Project - Contains code and resources, etc. (You'll be used to these!)
Target - Each project has one or more targets.
Each target defines a list of build settings for that project
Each target also defines a list of classes, resources, custom scripts etc to include/ use when building.
Targets are usually used for different distributions of the same project.
For example, my project has two targets, a "normal" build and an "office" build that has extra testing features and may contain several background music tracks and a button to change the track (as it currently does).
You'll be used to adding classes and resources to your default target as you add them.
You can pick and choose which classes / resources are added to which target.
In my example, I have a "DebugHandler" class that is added to my office build
If you add tests, this also adds a new target.
Scheme - A scheme defines what happens when you press "Build", "Test", "Profile", etc.
Usually, each target has at least one scheme
You can autocreate schemes for your targets by going to Scheme > Manage Schemes and pressing "Autocreate Schemes Now"
A target is an end product created by running "build" in Xcode. It might be an app, or a framework, or static library, or a unit test bundle. Whatever it is, it generally corresponds to a single item in the "built products" folder.
A scheme represents a collection of targets that you work with together. It defines which targets are used when you choose various actions in Xcode (Run, Test, Profile, etc.) Often, you will have just one scheme, which uses the main app target for the Run, Archive, and Profile actions, and a unit test target for the Test action. If you were building two related apps, you might have two schemes that used the same unit test bundle but different app targets.
The main benefit of schemes (introduced in Xcode 4) is that they allow you to switch between running your app and your unit tests without needing to toggle the selected target.
I am a visual person, hence to explain the concept I will be using a diagram.
When you have multiple targets they can be one-to-one matched with Xcode's Run,Test,Profile actions, this concept defines a scheme
A target is a version of your Project,i.e targets differ slightly in classes & resources to use during built time. A project can have multiple built time setting for separate distribution requirements.
Xcode structure
Workspace
-> Project
-> Target
-> Dependency
-> Scheme
-> Action
-> Build Configuration
-> Build Configuration File(.xcconfig)
Workspace (.xcworkspace) - is a container of multiple projects. It was created as a next step of cross-project references[About]
Workspace contains all schemes from included projects
Workspace handles all implicit dependencies[About]
Observations:
It is safe to work with different projects inside the same workspace and do not catch
//if you try to open two projects on two Xcode instances
Couldn't load Project.xcodeproj because it is already opened from another project or workspace
Cocoapods[About] working with workspace where creates Pods project
Project (.xcodeproj) - It is a container for targets and scheme. It defines code files, resources...
Also Projects manages Build Configuration(changed by scheme) and Build Configuration File[About]
You can convert existing Project into Workspace
File -> Save As Workspace...
[Workspace vs Project]
Target - PBXNativeTarget section. Defines a specific set of build settings that generate:
Application target
Library and framework targets
Test
Aggregate[About]. E.g. it is used to create a Universal framework or Umbrella framework
Scheme
Contains action(run, test, profile, analyze, archive) + configuration(additional arguments, [Build Configuration], diagnostic)
Scheme can be shared which helps you in CI, Carthage[Example]... and located:
<project_path>/<project_name>.xcodeproj/xcshareddata/xcschemes
Dependency - Targets can have dependencies. Dependency is a source link against. These dependencies can be linked statically or dynamically[About] There are two types of them:
Explicit Dependency[About] - Source code of the dependency that is located in the same project or nested project
Implicit Dependency[About] - Source/closed code of the dependency that is located in the project that is a part of the same workspace.
[Vocabulary]
tldr; Targets contain instructions to build a module/framework/library or an App/end Product e.g. instructions to build a watchOS app and an iOS App. Schemes know how to respond to certain actions e.g. a build action or test action or archive action.
Make sure you See WWDC16 video — Introduction to Xcode [45:13]. If you wanted to gain deeper knowledge then watch the entirety of the video. The video is simple to follow yet very foundational. My answer is mostly off of that.
Scheme
A scheme is how you specify what you want to run and it also contains
information about how you want to run it.
For example, I could have a project with an iOS app and a Watch app,
and in that case, I would have one scheme to run my iOS app and one
scheme to run my Watch app
Run will run my app in the debugger.
Test will run my tests.
Profile will run my app in instruments so I can measure its
performance.
Analyze will run Xcode's static analyzer and help catch problems I
might otherwise have missed.
And finally, the Archive action will build my app for release and put
it in the archive that I can then use to distribute to my testers or
to the App Store or to save for future crash log de-symbolication, or
symbolication.
Project
A project is a document that you use to organize your code an
resources in Xcode.
You have references to source code files and resource files on disc,
targets which actually build those files into products like your app,
Build settings which configure how your targets build their products,
and schemes which configure how you perform actions, such as Run, with
your targets.
Now, to access your project settings, you select your project in the
navigator, you select the popover at the top of the editor, and select
your project there.
Target
You have references to source code files and resource files on disc,
targets which actually build those files into products like your app,
Build settings which configure how your targets build their products,
and schemes which configure how you perform actions, such as Run [test, build], with
your targets.
A target contains the instructions to build one thing like an app or a
framework.
The thing that your target produces is called its product. The set of
steps that your target takes to build its product are called build
phases.
And lastly, a target has Build settings to configure how it builds its
product.
Now, one thing to note is that both projects and targets have Build
settings, and targets inherit the value set at the project level but
can override them with a target-specific value.
A target's build phases do things like cause dependencies to build
first, compile the source files in that target, and link the target
against libraries and frameworks.
To summarize:
Targets
Helps put a set of files together to build/run a product/module/package
Usually it ends up just being a product you ship to app store.
But often it can be a module that you just run unit-tests against it.
Like a single app can have an iOS target along with a watchOS target. Or just a single iOS Target. Or a single iOS target along with a test target, etc.
If you go to your target's Build Phase >> Compile Sources you'll see every file that's being built for that target. Example:
To explicitly quote Apple docs:
A target specifies a product to build and contains the instructions for building the product from a set of files in a project or workspace. A target defines a single product; it organizes the inputs into the build system—the source files and instructions for processing those source files—required to build that product. Projects can contain one or more targets, each of which produces one product.
The instructions for building a product take the form of build settings and build phases, which you can examine and edit in the Xcode project editor. A target inherits the project build settings, but you can override any of the project settings by specifying different settings at the target level. There can be only one active target at a time; the Xcode scheme specifies the active target.
A target and the product it creates can be related to another target. If a target requires the output of another target in order to build, the first target is said to depend upon the second. If both targets are in the same workspace, Xcode can discover the dependency, in which case it builds the products in the required order. Such a relationship is referred to as an implicit dependency. You can also specify explicit target dependencies in your build settings, and you can specify that two targets that Xcode might expect to have an implicit dependency are actually not dependent. For example, you might build both a library and an application that links against that library in the same workspace. Xcode can discover this relationship and automatically build the library first. However, if you actually want to link against a version of the library other than the one built in the workspace, you can create an explicit dependency in your build settings, which overrides this implicit dependency.
Schemes
A given target can be put through different actions.
build
run
test
profile
archive
You can have a scheme that has all the diagnostics enabled (which makes debugging slow) vs. a scheme that doesn't have any. Or a scheme that runs certain performance related tests vs. a scheme that runs both unit-tests and performance tests. You can edit a scheme so that it performs such actions as:
Building multiple targets
Executing scripts before or after any action
Sending emails before or after any action
Running with memory management diagnostics
Producing either a debug or release build for any action.
For more on that see Customizing the build schemes for a project
To put it all together:
Once you hit run, Xcode will look at the selected scheme. It will find its associated target(s). Use the Build Phases of that target and its Build Settings (any Project Settings that isn't overridden by the target settings will get included) to build a product into the selected destination (the destination can be an iPhone simulator or a physical iPhone or watchOS, etc).
AGAIN WATCH THE WWDC VIDEO!
My take:
Target -- a lower abstraction -- various kinds of builds. Each target has its own Build Settings (so if you split into several targets, take care of that huge sheet individually for each target). Targets have a convenient way of including/excluding files, so you can configure the build effectively on a per-file basis.
Scheme -- a higher abstraction -- guides a target through various ways of deployment (Run, Test, Archive). Has modest ways of configuring the build through Environment Parameters, but employs the Build Settings from the target. Creating / editing / deleting schemes is cheaper and easier than targets.
You can have several schemes guiding one target in several different ways.

Compile different files for device/simulator in XCode

I'm including a 3rd party library (sources) with my static library. It it intended for device only (since it includes some ARM assembly routines) and I do not wish to build it for the simulator (I just want my app to compile there so I can test the GUI).
Creating another target for simulator only is not an option since my projects reference my library as a dependency and it would be a nightmare to maintain.
Adding #if (TARGET_OS_IPHONE) for those files is not an option as well since these are not my original sources and I would like to update them easily for updates (there are more than 200 files there and I do not with to modify all of them)
I'm looking for a way (similar to #if (TARGET_OS_IPHONE) in source files) which will work from the IDE itself (so I can exclude a file from the actual build process based on my target architecture). The only thing I found is an option to exclude/include a file from a target - but not for a specific architecture.
Is there a way to set architecture conditions per specific files?
Your best bet would be to separate the third party library into a new target that builds it as a static framework. Set it as a dependency for your project, and then set the static framework to be conditionally linked as described by Apple here: http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/ios_development_workflow/115-Configuring_Applications/configuring_applications.html#//apple_ref/doc/uid/TP40007959-CH19-SW7
You can add a new target by selecting the Project in the project navigator and then hitting the Add Target button at the bottom of the Editor pane. You can setup a cocoa touch static library and then assign the relevant .m or .c files to belong only to that target. Then select your app's target and add the static framework in the "Target Dependencies" section of the Build Phases tab.
You can conditionally include/exclude files in Xcode using EXCLUDED_SOURCE_FILE_NAMES based on sdk. For example:
EXCLUDED_SOURCE_FILE_NAMES[sdk=*simulator*] = something.cpp something_else.cpp
See Conditional Compilation article for more details

Resources