-
Notifications
You must be signed in to change notification settings - Fork 24.3k
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
[iOS] CocoaPods frameworks compatibility: Step 2 #25619
Conversation
The ones you listed are fine to be changed. I had internal diff renaming typesafety stuff to For fabric, most of fabric is already not using <React/, you meant just the ObjC part (RCTFabric)? If so, I think it's ok to move it out. I suggest |
You may want to make these separate PRs for easier merging |
@ericlewis - thoughts? |
Notes: I tested header prefix like |
Summary: For better cocoapods compatibility, refactored TM podspec to be a subspec of ReactCommon, then use `<ReactCommon/` header prefix for all TM files. Relevant efforts: #25619 #25393 Reviewed By: hramos Differential Revision: D16231697 fbshipit-source-id: 38d3418b19978ff54aa0c61b064ac45ac0e1c36c
@jtreanor I landed a few commits to deal with jsireact stuffs:
Let me know if I can help further here. |
Thanks a lot @fkgozali! These changes will be very helpful. |
87ea162
to
eae2948
Compare
eae2948
to
42491b1
Compare
Okay, I have rebased master and @fkgozali's changes have helped a lot. Thank you again! I am still seeing the C++ error I mentioned above, so I'll give more detail here. When I add As you can see, this is the same error I encountered when investigating #25349 that led me to make C++ headers private by default. The problem seems to be that an Objective C file importing the As a hack and to confirm this is the only issue, I was able to get the build working by updating ...
+#ifdef __cplusplus
#import "JSCExecutorFactory.h"
#import "NSDataBigString.h"
#import "RCTCxxBridgeDelegate.h"
#import "RCTMessageThread.h"
#import "RCTObjcExecutor.h"
#import "DispatchMessageQueueThread.h"
#import "RCTCxxMethod.h"
#import "RCTCxxModule.h"
#import "RCTCxxUtils.h"
#import "RCTNativeModule.h"
#import "RCTFollyConvert.h"
+#endif
... This stops the C++ headers from being imported into the umbrella header and the build succeeds. Of course, modifying this file doesn't solve our problem, but confirms it. The only way to customise the umbrella header is to define a custom modulemap and umbrella header. However, I feel like there should be a way to solve the problem without resorting to this. I will keep investigating but I'm open to any ideas at all. |
Hmm, perhaps there's a missing compiler_flag in the individual podspec/subspec to hint that it's C++ code? React-RCTWebSocket.podspec doesn't seem to have any C++ flag configured, so maybe if you look at Xcode workspace, that framework is compiled for ObjC? |
Unfortunately, I don't think that would suffice. If we fix the problem for React-RCTWebSocket and the other RN pods, any user code that imports a React header into an ObjC file would still get this error. |
I think it's fine to require that callsites have .mm extension (ObjC++), not .m (ObjC), given that down the road everything will involve C++ (TurboModule/Fabric). If that's the only concern, I think it's ok to proceed (assuming we fix all podspecs to be C++ compatible) |
Oh, I see. I'll look a little more to see if there is a simple way to avoid that requirement but otherwise I'll proceed as you suggest. I am mostly wondering why this wasn't an issue prior to the podspec split. I'd like to understand what's going on here before choosing the best solution. |
Another approach (not always applicable) is to move the .h imports to the .mm instead of inside another .h. That would isolate the change to just the relevant .mm files, so other libs aren't affected. |
@jtreanor Thank you so much for working on this! I didn't have a chance to review/merge this yet due to unrelated work. cc @hramos @cpojer. I'll get back to this some time next week if others don't get to merge it by then.
Yeah, this is fine. Fabric had missing configuration unrelated to this |
I appreciate all the work going into fixing this issue but my concern is how do we make sure this doesn’t break going forward? It would be a shame if we fixed this now but broke it in another release. Will having this integrated into RNTesterPods make sure that all of these different CocoaPods scenarios don’t break? e.g. |
There's now a CI test to cover standard pods build with RNTester, so that will help prevent future breakage. We'll likely need to add a second variant using |
Yes, we can absolutely add a CI step to integrate and test |
We'll likely need a new RNTester project just for this variant. Let's visit this after we fully resolve this issue. |
I don't think that will be needed. For example, a change like this to - # Uncomment for Swift
- # use_frameworks!
+ use_frameworks! if ENV['USE_FRAMEWORKS'] == 1
Okay, I'll hold off on any changes for this to allow whats here to be reviewed first. |
@@ -32,8 +32,9 @@ Pod::Spec.new do |s| | |||
s.platforms = { :ios => "9.0", :tvos => "9.2" } | |||
s.source = source | |||
s.header_dir = "ReactCommon" # Use global header_dir for all subspecs for use_framework compatibility | |||
s.static_framework = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you help me understand why this line matters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, found the explanation in your summary:
Each podspec now uses s.static_framework = true. This means that a minimum of CocoaPods 1.5 (released in April 2018) is now required. This is needed so that the __has_include conditions can still work when frameworks are enabled.
I think it's worth exploring not using static_framework, but we can do it outside of this PR. I'm not sure if it's 100% possible given the current directory structure.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clear this up completely, here is a more thorough explanation.
In a number of places throughout the codebase, there is code like this:
#if RCT_DEV && __has_include(<React/RCTDevLoadingView.h>)
// Note: RCTDevLoadingView should have been loaded at this point, so no need to allow lazy loading.
RCTDevLoadingView *loadingView = [weakSelf moduleForName:RCTBridgeModuleNameForClass([RCTDevLoadingView class])
lazilyLoadIfNecessary:NO];
[loadingView updateProgress:progressData];
#endif
The trouble is that this code lives in React-Core.podspec
but RCTDevLoadingView
is part of React-DevSupport
. It works fine when not using frameworks but when use_frameworks!
is used and RCT_DEV
is enabled there is an error compiling React-Core.podspec
as RCTDevLoadingView
is not found. This is because React-DevSupport
is not linked with React-Core
.
The solution is to add s.static_framework = true
to each of the podspecs. Now all symbols are linked into the same executable so RCTDevLoadingView
is present at build time. It is necessary to add s.static_framework = true
to all podspecs as static frameworks are not allowed to have dynamic dependencies.
As mentioned above the main disadvantage of this is that it requires CocoaPods 1.5 or later to be used (released in April 2018). Another drawback is that I believe CocoaPods complains if a target has transitive static dependencies. This means any third party podspec that depends on React
would also need to have s.static_framework = true
.
I think it's worth exploring not using static_framework, but we can do it outside of this PR. I'm not sure if it's 100% possible given the current directory structure.
The only way I can think of that would be possible would be to make React-DevSupport
a subspec of React-Core
as it was before the podspec split.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means any third party podspec that depends on React would also need to have s.static_framework = true.
Yeah, this is my worry: it could be too limiting for those libs.
The only way I can think of that would be possible would be to make React-DevSupport a subspec of React-Core as it was before the podspec split.
I was actually trying this on top of your PR, but got a dependency cycle error, so I didn’t proceed. Perhaps it’s worth another look?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was actually trying this on top of your PR, but got a dependency cycle error, so I didn’t proceed. Perhaps it’s worth another look?
I can take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I remember the problem with that now. DevSupport
depends on React-RCTWebSocket
which depends on React-Core
.
If we make React-RCTWebSocket
a subspec too, it will work. I'll open a PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I've done that here: #25816
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fkgozali has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
s.source_files = "**/*.{c,h,m,mm,cpp}" | ||
s.header_dir = "React" | ||
s.source_files = "**/*.{c,m,mm,cpp}" | ||
s.header_dir = "CoreModules" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this one would be a breaking change (more files will be moved here for TurboModule migration), I'll see if I can move it up as a subspec inside React-Core.podspec
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nvm, I think this is meaningless now that you removed the .h files from the list
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, thats right.
This pull request was successfully merged by @jtreanor in 8131b7b. When will my fix make it into a release? | Upcoming Releases |
Thanks for reviewing @fkgozali! |
You’re welcome! Thanks for the all the work. I think as the next steps we can:
|
I've opened a draft PR for this here: #25818. It may require some discussion on the best approach.
PR opened for this here: #25816 as mentioned above. |
Summary: As part of the fix for #25349 I added `s.static_framework = true` to each podspec in repo (see #25619 (comment) for more context). This was required to ensure the existing conditional compilation with `#if RCT_DEV` and `__has_include` still worked correctly when `use_frameworks!` is enabled. However, fkgozali pointed out that it would be ideal if we didn't have this requirement as it could make life difficult for third-party libraries. This removes the requirement by moving `React-DevSupport.podspec` and `React-RCTWebSocket.podspec` into `React-Core.podspec` as subspecs. This means the symbols are present when `React-Core.podspec` is built dynamically so `s.static_framework = true` isn't required. This means that any `Podfile` that refers to `React-DevSupport` or `React-RCTWebSocket` will need to be updated to avoid errors. ## Changelog I don't think this needs a changelog entry since its just a refinement of #25619. Pull Request resolved: #25816 Test Plan: Check `RNTesterPods` still works both with and without `use_frameworks!`: 1. Go to the `RNTester` directory and run `pod install`. 2. Run the tests in `RNTesterPods.xcworkspace` to see that everything still works fine. 3. Uncomment the `use_frameworks!` line at the top of `RNTester/Podfile` and run `pod install` again. 4. Run the tests again and see that it still works with frameworks enabled. Reviewed By: hramos Differential Revision: D16495030 Pulled By: fkgozali fbshipit-source-id: 2708ac9fd20cd04cb0aea61b2e8ab0d931dfb6d5
Summary: This adds a `test_ios_frameworks` job to CircleCI to test the `RNTesterPods` project with `use_frameworks!` enabled. It will ensure the issue in #25349 is not reintroduced as suggested in #25619 (comment). ## Changelog [iOS] [Internal] - Added CircleCI job for testing `RNTesterPods` with `use_frameworks!` enabled. Pull Request resolved: #25818 Test Plan: Tests seem to be failing on `master` at the moment but you can see that the new job builds successfully [here](https://circleci.com/gh/facebook/react-native/103929?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link). You can confirm it installs the pods with `use_frameworks!` by seeing that `Installing pods with use_frameworks!` is at the start of the log for the `Generate RNTesterPods Workspace` step. Reviewed By: hramos Differential Revision: D16495016 Pulled By: fkgozali fbshipit-source-id: 8ef607cc3a152f599d226f9f45d990fba50a65d4
Summary: This is my proposal for fixing `use_frameworks!` compatibility without breaking all `<React/*>` imports I outlined in facebook#25393 (comment). If accepted, it will fix facebook#25349. It builds on the changes I made in facebook#25496 by ensuring each podspec has a unique value for `header_dir` so that framework imports do not conflict. Every podspec which should be included in the `<React/*>` namespace now includes it's headers from `React-Core.podspec`. The following pods can still be imported with `<React/*>` and so should not have breaking changes: `React-ART`,`React-DevSupport`, `React-CoreModules`, `React-RCTActionSheet`, `React-RCTAnimation`, `React-RCTBlob`, `React-RCTImage`, `React-RCTLinking`, `React-RCTNetwork`, `React-RCTPushNotification`, `React-RCTSettings`, `React-RCTText`, `React-RCTSettings`, `React-RCTVibration`, `React-RCTWebSocket` . There are still a few breaking changes which I hope will be acceptable: - `React-Core.podspec` has been moved to the root of the project. Any `Podfile` that references it will need to update the path. - ~~`React-turbomodule-core`'s headers now live under `<turbomodule/*>`~~ Replaced by facebook#25619 (comment). - ~~`React-turbomodulesamples`'s headers now live under `<turbomodulesamples/*>`~~ Replaced by facebook#25619 (comment). - ~~`React-TypeSaferty`'s headers now live under `<TypeSafety/*>`~~ Replaced by facebook#25619 (comment). - ~~`React-jscallinvoker`'s headers now live under `<jscallinvoker/*>`~~ Replaced by facebook#25619 (comment). - Each podspec now uses `s.static_framework = true`. This means that a minimum of CocoaPods 1.5 ([released in April 2018](http://blog.cocoapods.org/CocoaPods-1.5.0/)) is now required. This is needed so that the ` __has_include` conditions can still work when frameworks are enabled. Still to do: - ~~Including `React-turbomodule-core` with `use_frameworks!` enabled causes the C++ import failures we saw in facebook#25349. I'm sure it will be possible to fix this but I need to dig deeper (perhaps a custom modulemap would be needed).~~ Addressed by facebook@3357351. - I haven't got Fabric working yet. I wonder if it would be acceptable to move Fabric out of the `<React/*>` namespace since it is new? � [iOS] [Fixed] - Fixed compatibility with CocoaPods frameworks. Pull Request resolved: facebook#25619 Test Plan: ``` buck build catalyst ``` Everything should work exactly as before, where `use_frameworks!` is not in `Podfile`s. I have a branch on my [sample project](https://github.com/jtreanor/react-native-cocoapods-frameworks) here which has `use_frameworks!` in its `Podfile` to demonstrate this is fixed. You can see that it works with these steps: 1. `git clone [email protected]:jtreanor/react-native-cocoapods-frameworks.git` 2. `git checkout fix-frameworks-subspecs` 3. `cd ios && pod install` 4. `cd .. && react-native run-ios` The sample app will build and run successfully. To see that it still works without frameworks, remove `use_frameworks!` from the `Podfile` and do steps 3 and 4 again. `RNTesterPodsPods` can now work with or without `use_frameworks!`. 1. Go to the `RNTester` directory and run `pod install`. 2. Run the tests in `RNTesterPods.xcworkspace` to see that everything still works fine. 3. Uncomment the `use_frameworks!` line at the top of `RNTester/Podfile` and run `pod install` again. 4. Run the tests again and see that it still works with frameworks enabled. Reviewed By: PeteTheHeat Differential Revision: D16465247 Pulled By: PeteTheHeat fbshipit-source-id: cad837e9cced06d30cc5b372af1c65c7780b9e7a
…25816) Summary: As part of the fix for facebook#25349 I added `s.static_framework = true` to each podspec in repo (see facebook#25619 (comment) for more context). This was required to ensure the existing conditional compilation with `#if RCT_DEV` and `__has_include` still worked correctly when `use_frameworks!` is enabled. However, fkgozali pointed out that it would be ideal if we didn't have this requirement as it could make life difficult for third-party libraries. This removes the requirement by moving `React-DevSupport.podspec` and `React-RCTWebSocket.podspec` into `React-Core.podspec` as subspecs. This means the symbols are present when `React-Core.podspec` is built dynamically so `s.static_framework = true` isn't required. This means that any `Podfile` that refers to `React-DevSupport` or `React-RCTWebSocket` will need to be updated to avoid errors. I don't think this needs a changelog entry since its just a refinement of facebook#25619. Pull Request resolved: facebook#25816 Test Plan: Check `RNTesterPods` still works both with and without `use_frameworks!`: 1. Go to the `RNTester` directory and run `pod install`. 2. Run the tests in `RNTesterPods.xcworkspace` to see that everything still works fine. 3. Uncomment the `use_frameworks!` line at the top of `RNTester/Podfile` and run `pod install` again. 4. Run the tests again and see that it still works with frameworks enabled. Reviewed By: hramos Differential Revision: D16495030 Pulled By: fkgozali fbshipit-source-id: 2708ac9fd20cd04cb0aea61b2e8ab0d931dfb6d5
Summary: This adds a `test_ios_frameworks` job to CircleCI to test the `RNTesterPods` project with `use_frameworks!` enabled. It will ensure the issue in facebook#25349 is not reintroduced as suggested in facebook#25619 (comment). [iOS] [Internal] - Added CircleCI job for testing `RNTesterPods` with `use_frameworks!` enabled. Pull Request resolved: facebook#25818 Test Plan: Tests seem to be failing on `master` at the moment but you can see that the new job builds successfully [here](https://circleci.com/gh/facebook/react-native/103929?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link). You can confirm it installs the pods with `use_frameworks!` by seeing that `Installing pods with use_frameworks!` is at the start of the log for the `Generate RNTesterPods Workspace` step. Reviewed By: hramos Differential Revision: D16495016 Pulled By: fkgozali fbshipit-source-id: 8ef607cc3a152f599d226f9f45d990fba50a65d4
Summary
This is my proposal for fixing
use_frameworks!
compatibility without breaking all<React/*>
imports I outlined in #25393 (comment). If accepted, it will fix #25349.It builds on the changes I made in #25496 by ensuring each podspec has a unique value for
header_dir
so that framework imports do not conflict. Every podspec which should be included in the<React/*>
namespace now includes it's headers fromReact-Core.podspec
.The following pods can still be imported with
<React/*>
and so should not have breaking changes:React-ART
,React-DevSupport
,React-CoreModules
,React-RCTActionSheet
,React-RCTAnimation
,React-RCTBlob
,React-RCTImage
,React-RCTLinking
,React-RCTNetwork
,React-RCTPushNotification
,React-RCTSettings
,React-RCTText
,React-RCTSettings
,React-RCTVibration
,React-RCTWebSocket
.There are still a few breaking changes which I hope will be acceptable:
React-Core.podspec
has been moved to the root of the project. AnyPodfile
that references it will need to update the path.Replaced by [iOS] CocoaPods frameworks compatibility: Step 2 #25619 (comment).React-turbomodule-core
's headers now live under<turbomodule/*>
Replaced by [iOS] CocoaPods frameworks compatibility: Step 2 #25619 (comment).React-turbomodulesamples
's headers now live under<turbomodulesamples/*>
Replaced by [iOS] CocoaPods frameworks compatibility: Step 2 #25619 (comment).React-TypeSaferty
's headers now live under<TypeSafety/*>
Replaced by [iOS] CocoaPods frameworks compatibility: Step 2 #25619 (comment).React-jscallinvoker
's headers now live under<jscallinvoker/*>
s.static_framework = true
. This means that a minimum of CocoaPods 1.5 (released in April 2018) is now required. This is needed so that the__has_include
conditions can still work when frameworks are enabled.Still to do:
IncludingAddressed by 3357351.React-turbomodule-core
withuse_frameworks!
enabled causes the C++ import failures we saw in [iOS] RN 0.60.0-rc.2 fails to build with CocoaPods frameworks #25349. I'm sure it will be possible to fix this but I need to dig deeper (perhaps a custom modulemap would be needed).<React/*>
namespace since it is new? 🤔Changelog
[iOS] [Fixed] - Fixed compatibility with CocoaPods frameworks.
Test Plan
Sample Project
Everything should work exactly as before, where
use_frameworks!
is not inPodfile
s. I have a branch on my sample project here which hasuse_frameworks!
in itsPodfile
to demonstrate this is fixed.You can see that it works with these steps:
git clone [email protected]:jtreanor/react-native-cocoapods-frameworks.git
git checkout fix-frameworks-subspecs
cd ios && pod install
cd .. && react-native run-ios
The sample app will build and run successfully. To see that it still works without frameworks, remove
use_frameworks!
from thePodfile
and do steps 3 and 4 again.RNTesterPods
RNTesterPodsPods
can now work with or withoutuse_frameworks!
.RNTester
directory and runpod install
.RNTesterPods.xcworkspace
to see that everything still works fine.use_frameworks!
line at the top ofRNTester/Podfile
and runpod install
again.