Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested Frameworks? #844

Closed
kgn opened this issue Oct 13, 2015 · 11 comments
Closed

Nested Frameworks? #844

kgn opened this issue Oct 13, 2015 · 11 comments
Labels

Comments

@kgn
Copy link

kgn commented Oct 13, 2015

What is the recommended way to work with nested dependencies. For example I am working on a Caching framework that I want to use CryptoSwift within. Should I include the CryptoSwift.framework in the Xcode project file for my Cache framework? Or should I leave the CryptoSwift out of my Cache framework and only include it in the actual app project?

I can't quite tell from the README how this is intended to work.

@kgn
Copy link
Author

kgn commented Oct 13, 2015

After some testing it looks like I do need to include CryptoSwift in my actual app project. That makes sense based on what is in the README: drag them yourself into your project. But I still am not sure how to properly include the CryptoSwift framework from Carthage into my Cache project so I can import it and build tests.

@kgn
Copy link
Author

kgn commented Oct 13, 2015

Is this what is covered in the Adding frameworks to unit tests or a framework section? Sorry for all the questions, loving the library but still figuring somethings out.

@mdiep mdiep added the question label Oct 13, 2015
@tmspzz
Copy link
Member

tmspzz commented Oct 13, 2015

@kng This should be what is covered in that section.

From what I understand the following is valid for framework that depend on other frameworks.

  • In Build Phases -> Link Binary With Libraries drag the frameworks your framework depends on (form the Carthage/Build directory)
  • if you want to embed the third party frameworks binaries in your framework, after dragging then add a Copy Files Phase

I also have a question related to this

Like you I have a framework FGAuth.framework that depends on other 2 frameworks (Alamofire and Swiftz). I have another project that depends on FGAuth as well as Alamofire and Swiftz.

A more schematic description is X (FGAuth) depends on Y and Z. W (my other project) depends explicitly on X Y (I have them in this other project's Cartfile) and Z.

X (FGAuth) Cartfile looks like this:

github "Alamofire/Alamofire" ~> 3.0
github "typelift/swiftz" ~> 0.3

W's Carfile looks like this:

github "Alamofire/Alamofire" ~> 3.0
github "typelift/swiftz" ~> 0.3
git "file:///Users/blender/Code/Feingold/iOS/FGAuth" "master"

When I build the dependencies for for W this is what I get. I don't have any Copy Phase in X (FGAuth). I wonder why the frameworks are duplicated and how they got there. In my understanding they shouldn't be inside the FGAuth.framework bundle. I am using carthage 0.8.

Image Directory Listing

@mdiep
Copy link
Member

mdiep commented Oct 13, 2015

What is the recommended way to work with nested dependencies

The recommendation is to not nest dependencies—the dependencies should all linked and copied at the app-level.

If dependencies are nested/embedded, then they can't be versioned separately from the framework that depends on them. So if X and Y both depend on Z, Carthage needs to be able to pick a version of Z that works for both X and Y and Z needs to be included only once.

When I build the dependencies for for W this is what I get. I don't have any Copy Phase in X (FGAuth). I wonder why the frameworks are duplicated and how they got there. In my understanding they shouldn't be inside the FGAuth.framework bundle.

You must have a Copy Phase. Carthage isn't going to do this, and Xcode won't unless it's configured to.

@tmspzz
Copy link
Member

tmspzz commented Oct 13, 2015

Thank you for the fast answer!

@mdiep Unfortunately I didn't have a copy phase and building the W project for Archive from Carthage/Checkout indeed produced a .framework without the embedded /Frameworks directory.

  • I deleted Cartfile.resolved and bootstrapped every time
  • Build Clean/ Deep Clean/ Deleted Derived data folder
  • I had one Unit Test target with a copy phase in the framework I was building with carthage, removed that also. Nothing changed.
  • I tried deleting Carthage/ and ~/Library/Caches/org.carthage.CarthageKit/ but that didn't help.
  • I deleted the W project, (which was using carthage to build the FGAuth in the image above) recreated it and the problem solved itself.

There seems to be some cache somewhere because this is not the first time I witness this.

The recommendation is to not nest dependencies—the dependencies should all linked and copied at the app-level.

What is the section Adding frameworks to unit tests or a framework in the README for then? It sound to me exactly like the nested framework case.

If dependencies are nested/embedded, then they can't be versioned separately from the framework that depends on them. So if X and Y both depend on Z, Carthage needs to be able to pick a version of Z that works for both X and Y and Z needs to be included only once.

So would one in this case make use of the Carfile.private?

I can imagine how it's pretty common to have a framework depend on another framework, say for making network request and wanting to distribute just one framework bundle.

In order not to force the network dependency on other projects, would I then put my network framework dependency in the Cartfile.private, add a Copy Phase and via "@rpath" tell my framework to load the networking framework and runtime from inside it's own bundle?

Using an example (framework=F):
Suppose that I am building a Daily Pics App

  • I a build framework which talks to a Daily Kitten Pics backend
  • My Daily Kitten Pics Framework (FDK) which contains all my business logic depends on a networking framework (FN)
  • I build a framework which talks to a Daily Dog Pics backend
  • My Daily Dogs Pics Framework (FDG) which contains all my business logic depends on a networking framework (FN)
  • Finally I build a Daily Picks Framework (FDP) which depends on FDK and FDG
    In my app I would have to copy separately FDP, FDK, FDG and FN

This works fine for me but if I where ever to distribute the bundle of FDP I would have to give to my clients all my dependencies separately and have them copy them one by one, instead of distributing just one bundle.

I realise that this argument can be quite confusing, I hope I have explained myself to the best.
If I am making any wrong assumptions here please let me know.

@mdiep
Copy link
Member

mdiep commented Oct 13, 2015

What is the section Adding frameworks to unit tests or a framework in the README for then? It sound to me exactly like the nested framework case.

You can still use a framework from another framework—you just can't embed frameworks inside each other.

So would one in this case make use of the Carfile.private?

Cartfile.private is meant for dependencies which are used only for testing, like https://github.com/Quick/Quick.

This works fine for me but if I where ever to distribute the bundle of FDP I would have to give to my clients all my dependencies separately and have them copy them one by one, instead of distribution just one bundle.

Yes, that's correct. But (a) it's a minor inconvenience and (b) it has the benefit of actually working in the general case.

@tmspzz
Copy link
Member

tmspzz commented Oct 13, 2015

Ok thank you very much. You have been super helpful.

This clears the issue for me.

However in my opinion the wording in Adding frameworks to unit tests and frameworks (especially in the Copy Phase part) leads people to think that this is possible.

In rare cases, you may want to also copy each dependency into the build product (e.g., to embed dependencies within the outer framework, or make sure dependencies are present in a test bundle)

I would like to take the chance to thank you and all the people working on carthage for all the efforts made in the development and support. Many of my colleagues and I have been using carthage since very early on. Thanks again.

@kgn
Copy link
Author

kgn commented Oct 14, 2015

@mdiep if all frameworks are to be included at the application level what happens if two different frameworks depend on two different versions of a dependency. Say framework A uses X ~> 2.0 and framework B uses X ~> 1.0.

@mdiep
Copy link
Member

mdiep commented Oct 14, 2015

if all frameworks are to be included at the application level what happens if two different frameworks depend on two different versions of a dependency. Say framework A uses X ~> 2.0 and framework B uses X ~> 1.0.

If the versions are 1.0 and 2.0, that won't work no matter what—and Carthage will protect you from it.

Carthage assumes that all dependencies use semantic versioning. A change in the major version signifies that incompatible changes were made. If you try to load 2 different versions of the same framework—whether from the application level or from inside another framework—it's undefined which will load into memory. But either way, you'll have loaded a version that's incompatible with part of your application.

If it's just a minor version requirement, Carthage will pick a version of that framework that's compatible with both requirements. So if a framework requires X ~> 1.2 and another requires X ~> 1.5, Carthage will pick a version that's compatible with both.

@kgn
Copy link
Author

kgn commented Oct 16, 2015

K thanks @mdiep, my questions are answered 👍

@eonist
Copy link

eonist commented Feb 2, 2017

This repo seem to support nested frameworks with carthage support: https://github.com/tristanhimmelman/AlamofireObjectMapper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants