How to manage transitive dependency for local Xcode projects - ios

I have two Objective C dynamic frameworks X and Y and another Objective C app Z.
All these frameworks and apps have been created by me locally. Framework X is the very base framework used by framework Y and the app Z. So the dependency graph is something like the following:
Y ---> X
Z ---> X
Z ---> Y (---> X)
I want all my targets to be debuggable and to pick the platform tools based on run destination (device/simulator). So I have added dependencies as sub-projects to the main projects and have linked them with the dependent projects to generate implicit dependencies by Xcode.
The set up 1 and 2 works great independently. But I am struggling with the set up 3 which is creating duplicate build rules for the target X due to transitive dependency on it (target Y and Z both depends on it) and subsequently failing the build process.
Anyone has any idea on how to deal with this situation? Thanks in advance!

It seem that in Objective-C, We can't link a dynamic framework to another dynamic framework, or to a command line tool. It's always raise an exception, when running in production
Dyld Error Message:
Library not loaded: #rpath/XFrameworks.framework/Versions/A/XFrameworks
For your situation, What I think might solve your problem
X (Core features) can be built in static library
Y can be built in type of dynamic framework
will link with X library
or link with others (I mean some another code base)
Z (your application) will link with Y framework

Actually there is a way through which I could finally solve the issue of transitive dependency in Xcode. I have to use Workspace (.xcworkspace) rather than a Xcode project (.xcodeproj).
To get it done use the following steps:
Close all related and open Xcode projects.
Create a new Workspace in the root directory from File > New >
Workspace. Open the workspace by double clicking onto it and
drag/drop the required projects to the workspace.
Add the independent framework (X in my question) output to both of
the dependent project targets (Y and Z) by adding it under the
Framework and Libraries section. Embed the dynamic library only to
the top level application (Z) and do not embed it to the
intermediate dependent target library (Y).
Add the intermediate framework (Y) to the root level app under
Framework and Libraries section and embed it to the root app bundle.
This setup works like a charm for me without ever creating duplicate build rules and it spontaneously picked up the dependency as well.
Obviously, you can not do this if your independent framework is a static library and in that case it will be linked to both the dependent targets causing duplicate symbols issue during linking.

Related

Why Am I Not Able To Embed My Custom Framework?

I have a very simple framework project, MyFramework, that builds successfully. The framework defines a single, global function, myFunction.
The framework also defines 2 global variables: MyFrameworkVersionNumber and MyFrameworkVersionString (These 2 variables were created for me by Xcode)
I have a very simple application project, MyApplication. I am adding the framework to the application project by dragging and dropping the framework package (i.e. the MyFramework.framework in DerivedData that was produced by building the framework) onto the Xcode Navigator and then selecting the framework in the Embedded Binaries section of the project's General tab.
If I add code to MyApplication that references the variable MyFrameworkVersionNumber then I am able to successfully build and run MyApplication.
If I add code to MyApplication that references the function myFunction then I am not able to build MyApplication.
First Update
I suddenly remembered that Carthage does exactly what I am trying to do. So, I used Carthage to build MyFramework and Voila! - I can drag/drop the Carthage build of the framework into the application project and successfully use it. So now my inquiry has become: What does Carthage know that I do not?
Oh for heaven's sake! It turned out to be so simple. MyFramework was being built for a Generic iOS Device (arm64 architecture). MyApplication was being built for a simulator (x86_64 architecture). As soon as I matched those two up all was well. The reason that the Carthage build worked so well is that it produces a universal binary (i.e. one that contains both architectures).
I still do not understand why the MyFrameworkVersionNumber global variable was able to be accessed regardless of the architecture. But I am okay with deferring that little mystery as some arcane bit of information that will be revealed in the goodness of time (perhaps something such as that it is in a header that is structured the same for both architectures).

Link one framework with multiple sub projects in Xcode workspace

I have a workspace that contains multiple projects - Project A and Project B. In this case, Project B is a dependency of Project A. When Project A is built, project B is then added as a dynamic framework to Project A.
- Project A
- Framework 1
- Project B
- Framework 1
Both Project A and Project B rely on a framework (Framework 1). I add this framework to both projects by going Build Settings -> Framework Search Paths -> Add path to Framework 1. When I compile the project, I get Xcode warnings saying:
Class XXX is implemented in both PATH 1 and PATH 2. One of the two will be used. Which one is undefined.
What I really want to do is to tell Xcode to link the Framework with both sub projects but to understand that this is one common library that doesn't need to be duplicated. I have two questions:
Is this possible?
If it's not possible, will this warning cause any problems? For example, is it that Xcode will just use the source code from either Framework location or is it that Xcode could run parallel instances of the framework code which could cause issues with singletons being duplicated.

Xcode Swift: how to import a Swift project

I have made an Xcode Swift project ("Project1"). In a new project ("Project2"), I have trouble adding project 1.
I have tried adding project 1 to project 2's build phases (target dependancies, compiled sources, link binary with libraries); didn't work. When adding to the compiled sources, it wouldn't work no matter which option I chose (folder references, groups, copy if needed).
I get no compiler errors at:
import Project1
But when I try to use a class from project 1, I get the error "Use of undeclared type".
I have also tried to following links with no success:
External library usage in xcode
Xcode : Adding a project as a build dependency
Xcode how to add an external project
Both projects are in Swift (iOS).
I'd be very thankful if someone helped me with this issue.
Update: Project 1 is not a framework - it's an iOS app. I need to use some of its classes in project 2. The problem is that project 1 uses the Objective C library Common Crypto via a bridging header. When I manually add project 1 classes into project 2, I get an error ("unresolved identifier") in the project 1 Swift code that uses Common Crypto.
So in a nutshell: I have an iOS app (project 1), which is in Swift but uses Common Crypto via bridging header. When I add a number of classes from project 1 into project 2, it cannot resolve the references (in project 1) to Common Crypto variables.
Assuming Project1is a Framework and Project2 is an application using the framework:
Create a virgin Workspace (Xcode File -> new -> Workspace) named TestWorkspace
From the Finder, drag the Project1.xcodeprojfile to the TestWorkspace
From the Finder, drag the Project2.xcodeprojfile to the TestWorkspace, above Project1
Edit your TestWorkspace schemas Build setup:
Add Project1 and Project2
make sure Project1 is above Project2
Untick "Paralellize Build" to assure Project1 is build first
Build
Select Project2s target -> General
Drag artefact project1.framework(in Productsgroup) to "Linked Framworks and Libraries"
Note: To be visible for the client, all classes and methods in your project1.framework have to be public or open. Finde detailed information in Apples documentation.
Edit: As you have CommonCrypto as a dependency you will have to add the module to your Project2 project instead to solve your issues ( this is the easiest without resorting to an umbrella framework ). Add a run script build phase and include http://pastebin.com/1vmiqffu
-- Credits: Script 'stolen' from: https://github.com/henrinormak/Heimdall
Ok so I'm going to assume here that Project1 actually has a framework as a target. What are the access permissions set on the types you are trying to use?
Here are a couple of catchya's with Swift and frameworks as I encountered them:
You do not have a bridging header, instead your framework includes headers of non-Swift dependencies inside the header file of your framework ( ModuleName.h ). This also means these will be available to whatever project you import them to. As far as I know you need to use a module.modulemap in order to make use of private headers and includes.
All Swift Classes / Structs / Definitions in general are internal by default. It is a very good design choice and it forces you to think about the access rights on every component you write. Keeping things private by default makes it easier to only open stuff that really needs to be open ( public, open ), allowing for easier code maintenance since you know that private things are only accessed within the same context. ( Otherwise: error )
For some more assistance this link might be of help to you on how to do some fundamentals:
your first ios framewok (swift)

InterProject communication in XCode

My project architecture is, a workspace which has two projects(Project A & Project B). Project A has three more sub projects(Project X , Project Y, Project Z).
Workspace
Project A
Project x
Project y
Project z
Project B
Project B is more a kind of utility project. It needs to be re used in Project A, Project x,Project y, Project z and elsewhere it could be. I am starting to do a prototype. But face challenges in linking Project B in other projects. Every time i need to add the .a file manually into all other projects. Do we have any solution to dynamically link?
I tried this approach as well. I moved project B inside Project A below Project z. But i was not able to access the classes in Project x, y, z because all the projects are in the same level.
Any solution to dynamically link projects in the same level?
You need to add Project B as Target Dependency from Build Phases to other projects, that way Project B is built and added to other projects just as you'd like.

NoClassDefFoundError importing a library project

I'm currently writing a unit test project using the version 4.6.1 (Windows Vista + Eclipse). My project is divided in 3 part:
A. Unit test application (type:CLDC application)
B. Application to be tested (type:CLDC application)
C. A library project (type: library,no .jar file imported)
The A project should reference the code present in B (and of course even in C). I would like to specify that I can run without problems the project B (referencing C). My problems start when I try to run the project A.
I performed the following operations:
changing the B project type from CLDC application to library
B references the project C
A references the project B
set all project as "Active for Blackberry"
Basically A sees the two other project as two nested libraries.
The code is built successfully,but the problem is that when a class of the C library is called by B during the execution, the following exception is thrown:
NoClassDefFoundError
No detail message
Any help would be really appreciated.
Many Thanks
A NoClassDefFoundError means that A cannot find C at runtime. The usual cause is that C failed to be deployed onto the target device (simulator or real device).
Solution 1:
For project A under Project->Properties->Java Build Path ensure C (your library project) is listed under 'Projects' and the corresponding checkbox checked on the 'Order and export' tab. This should ensure that the library is exported during the build and deployment process.
Solution 2:
In project A add a symbolic link (right click project->Build Path->Link Source) to the library C source. This will force the library's source code to be included when project A is built.

Resources