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

Improve de-duplication for non-trivial cases #4146

Merged
merged 53 commits into from
Feb 23, 2016
Merged

Improve de-duplication for non-trivial cases #4146

merged 53 commits into from
Feb 23, 2016

Conversation

mrackwitz
Copy link
Member

Attempts to fix #4034.
Attempts to fix #3838.

Given that there is an integration like:

target 'FooApp' do
  platform :osx, '10.10'
  pod 'BananaKit'
end

target 'FooAppEx' do
  platform :osx, '10.10'
  pod 'BananaKit'
end

target 'BarApp' do
  platform :ios, '9.0'
  pod 'BananaKit'
end

target 'BarAppEx' do
  platform :ios, '9.0'
  pod 'BananaKit'
end

The analyzer will generate a model with the following pod targets:

  • Pods-FooApp-BananaKit with aggregate targets Pods-FooApp and Pods-FooAppEx
  • Pods-BarApp-BananaKit with aggregate targets Pods-BarApp and Pods-BarAppEx

So even though a pod is used on multiple platforms, the analyzer is able to recognize that it could be reused between app and its extension on the same platform in this example, but generally not limited to that.

The problem is that the pod target will be build in a scoped build dir, which is not available from all apps and pod targets. To stick with the example: the scoped build dir is added to the FRAMEWORK_SEARCH_PATHS of FooApp but not FooAppEx, because the deduplication/scoping logic makes at some places in the code the assumption if a pod target is scoped than just one target definition belongs to it. This may seem to be easily solved by just adding the same framework search path to FooAppEx as well, but this wouldn't work in any case, because there could be other dependencies from FooApp, which are build with e.g. other subspecs and so not thought for FooAppEx, but become visible which can cause indeterministic behavior and warnings because there are two (or more versions) of the same framework in the framework search paths.

So the solution is to change the way, they are scoped and ensure that pods targets are built to a directory, which doesn't cause clashes with other pod targets. But this will cause massive changes to the integration, likely breaking for anything relying on how scoped targets where named before.
Where a scoped target was named before Pods-MyAppExtension-BananaKit, the name/scope now indicates what's special about the build variant, which allow these cases:

  1. BananaKit-iOS: if BananaKit was used on different platforms
  2. BananaKit-iOS9.0: if BananaKit was used on different platforms and versions
  3. BananaKit-PalmTree-Leaf: if BananaKit was used with different sets of subspecs, the name shows which subspecs are special to the specific target, leaving out common subspecs
  4. BananaKit-MyApp-MyAppExtension: if both of the condition above apply, the name shows all target definitions where it is in use
  5. BananaKit-iOS9.0-PalmTree-Leaf: if both of the condition above apply, the name uses both schemes in combination

The order here is relatively arbitrary, but tries to prefer a shorter and simpler target name first, as especially 3. & 4. can become ugly and very long.

ToDo

  • Test for case 2, if relevant?
  • Test for case 3 with multiple subspec names
  • Test for case 4 with multiple target names
  • Test for case 5 with multiple target names
  • Rebuild integration specs
  • Changelog

Note

In case of 1. the scoping of the build products could be dropped, because the default $CONFIGURATION_BUILD_DIR covers already a scoping by platform and architecture.

⚠️ Transitive dependencies are still causing a duplication with the target based naming scheme.

@mrackwitz mrackwitz added the t2:defect These are known bugs. The issue should also contain steps to reproduce. PRs welcome! label Sep 9, 2015
@neonichu
Copy link
Member

neonichu commented Sep 9, 2015

🎉

I wonder though if we should simply throw an error in the application extension case, since we already know that duplicated dependencies will lead to problems when archiving apps. Maybe at least show a warning that this probably won't work?

end
end

Hash[result.map { |d,name| [d,name.gsub('/', '_')] }]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spacing. Use tr instead of gsub

@mrackwitz
Copy link
Member Author

I wonder though if we should simply throw an error in the application extension case, since we already know that duplicated dependencies will lead to problems when archiving apps. Maybe at least show a warning that this probably won't work?

Throw an error or print a warning when app and app extension don't share the same dependency? We would need first be able to recognize whether both belong to each other.

@neonichu
Copy link
Member

@mrackwitz true, but shouldn't be too hard to obtain that information. Will look into that.

@@ -94,15 +94,15 @@ def generate
#
def generate_settings_to_import_pod_targets
if target.requires_frameworks?
framework_header_search_paths = pod_targets.select(&:should_build?).map do |target|
build_pod_targets = pod_targets.select(&:should_build?)
framework_header_search_paths = build_pod_targets.map do |target|
if target.scoped?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like it no longer needs to be a conditional

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed.

@segiddins
Copy link
Member

This looks very good! Biggest thing for me is seeing a bevy of unit tests around the method that generates scope suffixes.
We also need to investigate if there's a max length we can make a pod target's name

@segiddins
Copy link
Member

@mrackwitz I can pick this up if you want, just let me know what needs to be done

@segiddins
Copy link
Member

@mrackwitz I tried to rebase this yesterday but ran into some issues. Could you please handle rebasing it?

@benasher44
Copy link
Member

Noted in #3838 that I think I'm having a similar issue, and I'm using 1.0.0.beta.2. I'm happy to give this branch a try and see if it solves my issue described there and report back, once this gets PR rebased.

@jafara
Copy link

jafara commented Jan 23, 2016

Would love to see this land!

@mrackwitz
Copy link
Member Author

I have reawaked this PR and extended it with the outstanding tests. In progress of that, I fixed the naming scheme as seen in the updated comment above as well, so that the names stay consistent. But this needs still further testing with real-world projects, especially with those, which where concerned from this issue.

@@ -6,6 +6,16 @@ To install release candidates run `[sudo] gem install cocoapods --pre`

## Master

##### Breaking
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a bug fix, not a breaking change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I classified it as breaking because it will cause huge changes to the integration. Actually it shouldn't break anything beside podfile installation hooks, which could be affected by any change. But then I would rather say it's an enhancement. This PR is still labeled as defect, because it predates #4147. Since that was merged, everything what is left here to do was more a known feature limitation, I guess.

@benasher44
Copy link
Member

Okay, I just tried this out, and it still won't compile, but the error is slightly different. To start out, there's one thing that stands out as a something that looks weird/incorrect. The file in question that won't compile has a framework search path that looks like this:

-F/Users/basher/Code/iphone/Pods/"/Users/basher/Library/Developer/Xcode/DerivedData/Yelp-fyngslzoeilfvcblkbskorhepqvd/Build/Products/Debug-iphonesimulator/Pods-YelpShared-Yelp"

It looks like it's trying to make it so that it has the framework search paths of /Users/basher/Code/iphone/Pods/ and /Users/basher/Library/Developer/Xcode/DerivedData/Yelp-fyngslzoeilfvcblkbskorhepqvd/Build/Products/Debug-iphonesimulator/Pods-YelpShared-Yelp. The syntax here for specifying multiple framework search paths seems funny/incorrect, and the correct include paths should be

  • /Users/basher/Library/Developer/Xcode/DerivedData/Yelp-fyngslzoeilfvcblkbskorhepqvd/Build/Products/Debug-iphonesimulator (this is where the pod framework is whose subspec is used by one target and whose pod framework in its entirety is used by a pod in the main target)
  • /Users/basher/Library/Developer/Xcode/DerivedData/Yelp-fyngslzoeilfvcblkbskorhepqvd/Build/Products/Debug-iphonesimulator/Pods-YelpShared-Yelp

Let me know if you need more info to help debug this. If it helps, /Users/basher/Code/iphone/Pods is $(SRCROOT)/Pods

@segiddins
Copy link
Member

Is there any chance this will also fix #4751?

@benasher44
Copy link
Member

Commit 4333212 still working for me.

@segiddins
Copy link
Member

@mrackwitz if this is no longer a WIP, it gets a 👍 from me. Great job! 🚀

@mrackwitz mrackwitz changed the title [WIP] Improve de-duplication for non-trivial cases Improve de-duplication for non-trivial cases Feb 23, 2016
@mrackwitz
Copy link
Member Author

Okay, let's 🚢 it!

mrackwitz added a commit that referenced this pull request Feb 23, 2016
Improve de-duplication for non-trivial cases
@mrackwitz mrackwitz merged commit d504d84 into master Feb 23, 2016
@mrackwitz mrackwitz deleted the mr-fix-scoping branch February 23, 2016 10:19
@neonichu
Copy link
Member

@orta
Copy link
Member

orta commented Feb 23, 2016

oh, wow

MRW I overhear somebody in my office make a really clever pun

mrackwitz added a commit that referenced this pull request Mar 12, 2016
Targets use since #4146 individual build directories in all cases, not only these.
mrackwitz added a commit that referenced this pull request Mar 12, 2016
The behavior changed drastically with #4146, so that relying on this outside of this class was in most cases wrong.
segiddins pushed a commit that referenced this pull request Mar 13, 2016
Targets use since #4146 individual build directories in all cases, not only these.
segiddins pushed a commit that referenced this pull request Mar 13, 2016
The behavior changed drastically with #4146, so that relying on this outside of this class was in most cases wrong.
efirestone pushed a commit to efirestone/CocoaPods that referenced this pull request May 17, 2016
efirestone pushed a commit to efirestone/CocoaPods that referenced this pull request May 17, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
t2:defect These are known bugs. The issue should also contain steps to reproduce. PRs welcome!
Projects
None yet
7 participants