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

Fix build errors when inheriting RCTAppDelegate in Swift modules #35661

Closed
wants to merge 3 commits into from

Conversation

Kudo
Copy link
Contributor

@Kudo Kudo commented Dec 16, 2022

Summary

When inheriting RCTAppDelegate in a module with swift code, the compiler will have a build error when it goes through module headers. because swift does not support cxx headers. we found this issue when we try to inherit the class at Expo's EXAppDelegateWrapper with RCTAppDelegate in new architecture mode.

Changelog

[IOS][FIXED] - Fix build errors when inheriting RCTAppDelegate in Swift modules

Test Plan

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Contributor A React Native contributor. p: Expo Partner: Expo Partner labels Dec 16, 2022
@analysis-bot
Copy link

analysis-bot commented Dec 16, 2022

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 8,464,978 +0
android hermes armeabi-v7a 7,785,570 +0
android hermes x86 8,940,776 +0
android hermes x86_64 8,798,958 +0
android jsc arm64-v8a 9,652,079 +0
android jsc armeabi-v7a 8,386,299 +0
android jsc x86 9,716,461 +0
android jsc x86_64 10,193,883 +0

Base commit: 8ccb861
Branch: main

@analysis-bot
Copy link

analysis-bot commented Dec 16, 2022

Platform Engine Arch Size (bytes) Diff
ios - universal n/a --

Base commit: ba6a05b
Branch: main

@pull-bot
Copy link

PR build artifact for 614dab4 is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@Kudo
Copy link
Contributor Author

Kudo commented Dec 16, 2022

@cipolleschi would be appreciated if you can review this pr when you get a chance 🙇‍♂️

@cipolleschi
Copy link
Contributor

This fix looks more a cure for a symptom rather than the cure for the cause.

When RCT_NEW_ARCH_ENABLED==1, we have to use C++ compiler, so I expected that the __cplusplus flag was already enabled (making this addition a no-op, basically). It feels to me that, if that's not the case, we are actually missing a global configuration. If we proceed with this fix, we may solve this symptom, but the problem could manifest again in the future in other files.

Can we try to understand what's going on and see if we can fix it at the root cause? 🙏

@Kudo
Copy link
Contributor Author

Kudo commented Dec 16, 2022

let me share the detailed error log:

CompileC /Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/Objects-normal/x86_64/EXReactDelegateWrapper.o /Users/kudo/RNNext/node_modules/expo-modules-core/ios/ReactDelegates/EXReactDelegateWrapper.m normal x86_64 objective-c com.apple.compilers.llvm.clang.1_0.compiler (in target 'ExpoModulesCore' from project 'Pods')
    cd /Users/kudo/RNNext/ios/Pods
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -x objective-c -target x86_64-apple-ios13.0-simulator -fmessage-length\=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit\=0 -std\=gnu11 -fobjc-arc -fmodules -fmodules-cache-path\=/Users/kudo/Library/Developer/Xcode/DerivedData/ModuleCache.noindex -fmodules-prune-interval\=86400 -fmodules-prune-after\=345600 -fbuild-session-file\=/Users/kudo/Library/Developer/Xcode/DerivedData/ModuleCache.noindex/Session.modulevalidation -fmodules-validate-once-per-build-session -Wnon-modular-include-in-framework-module -Werror\=non-modular-include-in-framework-module -fmodule-name\=ExpoModulesCore -Wno-trigraphs -fpascal-strings -Os -fno-common -Wno-missing-field-initializers -Wno-missing-prototypes -Werror\=return-type -Wdocumentation -Wunreachable-code -Wno-implicit-atomic-properties -Werror\=deprecated-objc-isa-usage -Wno-objc-interface-ivars -Werror\=objc-root-class -Wno-arc-repeated-use-of-weak -Wimplicit-retain-self -Wduplicate-method-match -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body -Wuninitialized -Wconditional-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion -Wint-conversion -Wbool-conversion -Wenum-conversion -Wno-float-conversion -Wnon-literal-null-conversion -Wobjc-literal-conversion -Wshorten-64-to-32 -Wpointer-sign -Wno-newline-eof -Wno-selector -Wno-strict-selector-match -Wundeclared-selector -Wdeprecated-implementations -Wno-implicit-fallthrough -DPOD_CONFIGURATION_RELEASE\=1 -DCOCOAPODS\=1 -DNS_BLOCK_ASSERTIONS\=1 -DOBJC_OLD_DISPATCH_PROTOTYPES\=0 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator16.2.sdk -fasm-blocks -fstrict-aliasing -Wprotocol -Wdeprecated-declarations -g -Wno-sign-conversion -Winfinite-recursion -Wcomma -Wblock-capture-autoreleasing -Wstrict-prototypes -Wno-semicolon-before-method-body -Wunguarded-availability -fobjc-abi-version\=2 -fobjc-legacy-dispatch -iquote /Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/ExpoModulesCore-generated-files.hmap -I/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/ExpoModulesCore-own-target-headers.hmap -I/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/ExpoModulesCore-all-non-framework-target-headers.hmap -ivfsoverlay /Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/all-product-headers.yaml -iquote /Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/ExpoModulesCore-project-headers.hmap -I/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Products/Release-iphonesimulator/ExpoModulesCore/include -I/Users/kudo/RNNext/ios/Pods/Headers/Private -I/Users/kudo/RNNext/ios/Pods/Headers/Private/ExpoModulesCore -I/Users/kudo/RNNext/ios/Pods/Headers/Public -I/Users/kudo/RNNext/ios/Pods/Headers/Public/DoubleConversion -I/Users/kudo/RNNext/ios/Pods/Headers/Public/ExpoModulesCore -I/Users/kudo/RNNext/ios/Pods/Headers/Public/FBLazyVector -I/Users/kudo/RNNext/ios/Pods/Headers/Public/RCT-Folly -I/Users/kudo/RNNext/ios/Pods/Headers/Public/RCTRequired -I/Users/kudo/RNNext/ios/Pods/Headers/Public/RCTTypeSafety -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-Codegen -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-Core -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-Fabric -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-RCTFabric -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-callinvoker -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-cxxreact -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-graphics -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-jsi -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-jsiexecutor -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-jsinspector -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-logger -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-perflogger -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-runtimeexecutor -I/Users/kudo/RNNext/ios/Pods/Headers/Public/ReactCommon -I/Users/kudo/RNNext/ios/Pods/Headers/Public/Yoga -I/Users/kudo/RNNext/ios/Pods/Headers/Public/fmt -I/Users/kudo/RNNext/ios/Pods/Headers/Public/glog -I/Users/kudo/RNNext/ios/Pods/Headers/Public/hermes-engine -I/Users/kudo/RNNext/ios/Pods/boost -I/Users/kudo/RNNext/ios/Pods/DoubleConversion -I/Users/kudo/RNNext/ios/Pods/RCT-Folly -I/Users/kudo/RNNext/ios/Pods/Headers/Public/React-hermes -I/Users/kudo/RNNext/ios/Pods/Headers/Public/hermes-engine -I/Users/kudo/RNNext/ios/Pods/Headers/Private/React-Core -I/Users/kudo/RNNext/ios/Pods/Headers/Private/React-bridging/react/bridging -I/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Products/Release-iphonesimulator/React-bridging/react_bridging.framework/Headers -I/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/DerivedSources-normal/x86_64 -I/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/DerivedSources/x86_64 -I/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/DerivedSources -F/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Products/Release-iphonesimulator/ExpoModulesCore -F/Users/kudo/RNNext/ios/Pods/hermes-engine/destroot/Library/Frameworks/universal -F/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Products/Release-iphonesimulator/XCFrameworkIntermediates/hermes-engine/Pre-built -F/Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Products/Release-iphonesimulator/React-hermes -fmodule-map-file\=/Users/kudo/RNNext/ios/Pods/Headers/Public/RCTTypeSafety/RCTTypeSafety.modulemap -fmodule-map-file\=/Users/kudo/RNNext/ios/Pods/Headers/Public/React-Core/React/React-Core.modulemap -fmodule-map-file\=/Users/kudo/RNNext/ios/Pods/Headers/Public/React-RCTFabric/RCTFabric/React-RCTFabric.modulemap -fmodule-map-file\=/Users/kudo/RNNext/ios/Pods/Headers/Public/ReactCommon/ReactCommon.modulemap -fmodule-map-file\=/Users/kudo/RNNext/ios/Pods/Headers/Public/React_Codegen/React-Codegen.modulemap -fmodule-map-file\=/Users/kudo/RNNext/ios/Pods/Headers/Public/React_RCTAppDelegate/React-RCTAppDelegate.modulemap -fmodule-map-file\=/Users/kudo/RNNext/ios/Pods/Headers/Public/folly/RCT-Folly.modulemap -fmodule-map-file\=/Users/kudo/RNNext/ios/Pods/Headers/Public/yoga/Yoga.modulemap -DFOLLY_NO_CONFIG -DFOLLY_MOBILE\=1 -DFOLLY_USE_LIBCPP\=1 -Wno-comma -Wno-shorten-64-to-32 -DREACT_NATIVE_MINOR_VERSION\=71 -DRN_FABRIC_ENABLED -DRCT_NEW_ARCH_ENABLED -include /Users/kudo/RNNext/ios/Pods/Target\ Support\ Files/ExpoModulesCore/ExpoModulesCore-prefix.pch -MMD -MT dependencies -MF /Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/Objects-normal/x86_64/EXReactDelegateWrapper.d --serialize-diagnostics /Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/Objects-normal/x86_64/EXReactDelegateWrapper.dia -c /Users/kudo/RNNext/node_modules/expo-modules-core/ios/ReactDelegates/EXReactDelegateWrapper.m -o /Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/Objects-normal/x86_64/EXReactDelegateWrapper.o

In file included from /Users/kudo/RNNext/node_modules/expo-modules-core/ios/ReactDelegates/EXReactDelegateWrapper.m:6:
In file included from /Users/kudo/RNNext/node_modules/expo-modules-core/ios/ReactDelegates/EXReactDelegateWrapper+Private.h:3:
In file included from /Users/kudo/RNNext/node_modules/expo-modules-core/ios/Swift.h:13:
In file included from /Users/kudo/Library/Developer/Xcode/DerivedData/RNNext-dgsfutaofrmtlgfznlavduhdrrvo/Build/Intermediates.noindex/Pods.build/Release-iphonesimulator/ExpoModulesCore.build/DerivedSources/ExpoModulesCore-Swift.h:763:
In file included from /Users/kudo/RNNext/node_modules/expo-modules-core/ios/ExpoModulesCore.h:12:
In file included from /Users/kudo/RNNext/ios/Pods/Target Support Files/ExpoModulesCore/ExpoModulesCore-umbrella.h:14:
In file included from /Users/kudo/RNNext/node_modules/expo-modules-core/ios/AppDelegates/EXAppDelegateWrapper.h:7:
In file included from /Users/kudo/RNNext/ios/Pods/Headers/Private/React-RCTAppDelegate/RCTAppDelegate.h:14:
/Users/kudo/RNNext/ios/Pods/Headers/Private/React-Core/React/RCTCxxBridgeDelegate.h:8:10: fatal error: 'memory' file not found
#include <memory>
         ^~~~~~~~

in a nut shell, ExpoModulesCore-umbrella.h (to build a clang module) -> EXAppDelegateWrapper.h -> RCTAppDelegate.h -> RCTCxxBridgeDelegate.h. the compiler is clang -x objective-c which doesn't support c++.

i could also upload the RNNext project to github for you if you want to investigate further.

@cipolleschi
Copy link
Contributor

I think that that's the problem. We can't build New Architecture files using Objective-C, we need to use Objective-C++. That's why the files are .mm and not just .m.

Have you tried to set the compiler to c++17? Looking at here it should be possible. Also this post seems useful.

@Kudo
Copy link
Contributor Author

Kudo commented Dec 16, 2022

we have c++17 and i changed the EXAppDelegateWrapper to .mm already. the problem is from other .m file in our module, e.g. the EXReactDelegateWrapper.m. when it references the swift generated header, i.e. the ExpoModulesCore-Swift.h, it looks up the modulemap and the umbrella header. and then it goes through ExpoModulesCore-umbrella.h -> EXAppDelegateWrapper.h -> RCTAppDelegate.h -> RCTCxxBridgeDelegate.h error chain. do it make sense to you?

@cipolleschi
Copy link
Contributor

Can't you rename all those .m to .mm? That is the actual right fix... If they import some header which requires C++ or Objective-C++, they should be .mm.


There is something I'm struggling to understand. How can you successfully compile if:

  • You run the RCT_NEW_ARCH_ENABLED=1, importing some Objective-C++ headers
  • without the __cpluplus flag?

In other words... We have two use cases: NewArch enabled/disabled.

  • With the New Arch disabled, can you confirm that everything builds fine already? (the RCT_NEW_ARCH_ENABLED is equal to 0, therefore those headers should be excluded)
  • With the New Arch enabled, those headers are needed... but you are including them only when the __cplusplus flag is turned on... So, when it is turned off, those headers are not available, therefore you can not run the New Architeture. Then, the RCT_NEW_ARCH_ENABLED should have been equal to 0 in the first place.

I hope I clarified my struggle with these use cases. I don't think that the issue is in the React native codebase, but more on how the project is set up.

@Kudo
Copy link
Contributor Author

Kudo commented Dec 19, 2022

Can't you rename all those .m to .mm?

then we should rename all .m to .mm even those .m doesn't import RCTAppDelegate. that is not quite correct.

NewArch enabled/disabled.

yes you are right, the only problem is when RCT_NEW_ARCH_ENABLED=1

Minimal Reproducible Example

well, to demonstrate the complicated problem, i've tried to have a minimal reproducible example with create-react-native-library. you could check with my repo here: https://github.com/Kudo/test-swift-module

Steps:

  1. yarn
  2. cd example ; open ios/TestSwiftModuleExample.xcworkspace

i have my repro in commit history: https://github.com/Kudo/test-swift-module/commits/main

  • Kudo/test-swift-module@440e163400 - the repro. it's little complicated:
    • TestSwiftModule is a module with objective-c and swift interoperability
    • ObjcSwiftInterop.m calls to TestSwiftModule.swift, so it needs the TestSwiftModule-Swift.h swift generated header.
    • TestSwiftModule.swift inherits ObjcMultiply.m, so it needs the TestSwiftModule.h and TestSwiftModule-umbrella.h. and in the swift generated header, e.g. "$HOME/Library/Developer/Xcode/DerivedData/TestSwiftModuleExample-doouuozeuqeyrrcincfceivjjjbt/Build/Products/Debug-iphonesimulator/TestSwiftModule/Swift Compatibility Header/TestSwiftModule-Swift.h", it has the #import <TestSwiftModule/TestSwiftModule.h> import.
    • CustomAppDelegate.h is an independent class which is nothing to do with other classes, and it has .mm already.
    • you could try to build the project when git checkout 440e163400. the error chain is from ObjcSwiftInterop.m -> TestSwiftModule-Swift.h -> TestSwiftModule.h -> TestSwiftModule-umbrella.h -> CustomAppDelegate.h -> RCTAppDelegate.h -> RCTCxxBridgeDelegate.h
  • Kudo/test-swift-module@17fe4b5 we may need DEFINES_MODULE in RCTAppDelegate for swift integration
  • Kudo/test-swift-module@b44909e we can add #if __cplusplus in CustomAppDelegate.h, but there's a build error from main.m
  • Kudo/test-swift-module@3e51058 - change main.m -> main.mm works
  • Kudo/test-swift-module@db21524 - if we don't touch main.m, the workaround i am going to have.

Conclusion

even though most module doesn't have such complicated objc <-> swift mixed code. i think there is a problem from react-native currently. when building main.m even in new architecture mode, we don't pass RCT_NEW_ARCH_ENABLED=1 compiler flag, that AppDelegate.h is different when building main.m and AppDelegate.mm. it is coincidently work because we only pass NSStringFromClass([AppDelegate class]) in main.m.

i'll leave a problem and discuss here. maybe we don't have to land this pr as we could apply the workaround internally.

Kudo added a commit to expo/expo that referenced this pull request Dec 19, 2022
# Why

sdk 48 may come next year and react-native 0.71 may be released this year. it's good to have react-native 0.71 support for our modules. if users want to upgrade 0.71, they could change their project to be a bare project for the early preview.

# How

- [core][av][gl] because 0.71 doesn't serve android aar along with npm package, the aar extraction from `node_modules/react-native/android/**/*.aar` will break on 0.71. 0.71 also ships modules with prefab support. it's good to rewrite the gradle/cmake files to link with prefab modules. that would reduce much complexity. however, to be backward compatible with 0.70, i moved most logic to `ExpoModulesCorePlugin.applyLegacyReactNativeLibsExtractionPlugin` and `legacy/CMakeLists.txt`. so that we could be backward compatible and easily remove the isolated code after we drop sdk 47 support.
- [dev-launcher] add 0.71 sources because new parameter to `DevSupportManagerBase`
- [core][dev-menu] fix ios build errors for jsc because 0.71 moved the header to `<React-jsc/JSCRuntime.h>`
- [core][autolinking] integrate the `RCTAppDelegate` with our `EXAppDelegateWrapper`. that would simply the install-expo-modules migration where we only need the change `RCTAppDelegate -> EXAppDelegateWrapper` in AppDelegate.h. however, integrate RCTAppDelegate comes with some issues from expo-modules-core. [this commit](2959477) changes many code and i'll try to explain here:
  - RCTAppDelegate is in `React-RCTAppDelegate` pod, which does not define module. we define module for it in our patch system in autolinking.
  - defines `RCT_NEW_ARCH_ENABLED` as RCTAppDelegate
  - in new architecture mode, RCTAppDelegate comes with [more cxx dependencies](https://github.com/facebook/react-native/blob/03b17d9af7e4e3ad3f9ec078b76d0ffa33a3290e/Libraries/AppDelegate/RCTAppDelegate.h#L12-L18) for fabric. that's why we should add more header search paths and also move to EXAppDelegateWrapper.mm.

# Test Plan

- [x] ci passed
- [x] bare-expo build and launch
- [x] bare-expo nightlies build and launch
- [x] fabric-tester build and launch
- [x] fabric-tester nighties build and launch (should apply [the patch to fabric-tester](https://gist.github.com/Kudo/417a5159cb01a400ecee22ad4985d287))
- [x] rn 0.71-rc4 project build and launch (could apply [the patches](https://gist.github.com/Kudo/7448c733f12e700c7fbed76251fa3553) for testing)
- [x] rn 0.71-rc4 project (new architecture) build and launch ([this pr](facebook/react-native#35661) for react-native is required)
- [x] rn 0.71-rc4 project (use_frameworks!) build and launch
@cipolleschi
Copy link
Contributor

Something feels off, to me.

when building main.m even in new architecture mode, we don't pass RCT_NEW_ARCH_ENABLED=1 compiler flag, that AppDelegate.h is different when building main.m and AppDelegate.mm.

  • The RCT_NEW_ARCH_ENABLED=1 is set at project level by Cocoapods. Here the post install phase and here the logic
  • If pod install is invoked with RCT_NEW_ARCH_ENABLED=1, this works
  • If pod install are installed using the parameters of use_react_native!, this line should take care of setting the environment variable.
  • When RCT_NEW_ARCH_ENABLED=1, the __cplusplus flag must be true as well (so the suggested fix does not look right, it should basically do nothing).

I'll try to explore better why we have the RCT_NEW_ARCH_ENABLED=1 with __cplusplus set to false and fix this root problem.

Repro

I don't think I have time to try the repro in these days, but I'll give it a shot.

I also created these guides in these days, that works with Swift Modules, and I have not encountered any of these problems.

So, I'm even more inclined to think that there could be a problem in the setup more than in React Native.

@Kudo
Copy link
Contributor Author

Kudo commented Dec 19, 2022

when building main.m even in new architecture mode, we don't pass RCT_NEW_ARCH_ENABLED=1 compiler flag, that AppDelegate.h is different when building main.m and AppDelegate.mm.

since main.m is resident in app project, you should update the app's project.pbxproj. those cocoapods post_install handlers don't update this. that's why compiling for main.m doesn't have RCT_NEW_ARCH_ENABLED=1 even ENV['RCT_NEW_ARCH_ENABLED']=1.

https://github.com/react-native-community/RNNewArchitectureLibraries/tree/feat/turbomodule-swift
https://github.com/react-native-community/RNNewArchitectureLibraries/tree/feat/swift-event-emitter

these examples are not complicated enough 😑. you need both objc -> swift and swift -> objc to trigger the problem. that's why i have a swift class inherits objc class in my repro.

feel free to visit this whenever you get a chance (maybe) next year. i could workaround the problem internally before that. if you have any questions, either replying here or ping me on discord. i can help to clarify the questions for you.

@cipolleschi
Copy link
Contributor

Screenshot 2022-12-19 at 16 04 38

This is a new application created with the template, and with the pods installed with RCT_NEW_ARCH_ENABLED=1.

As you can see, the main app has the flag properly set in the Other Cplusplus Flags. React Native seems fine to me.

I made another test, stepping into the flags in the main.m file with the debugger. And yes, it skips them, but it does not skips them in the AppDelegate.mm.
If we rename it main.mm, it works.


I tried to set the RCT_NEW_ARCH_ENABLED=1 flag also in the OTHER_CFLAGS. With this setup, the problem presents even with a fresh app.
Screenshot 2022-12-19 at 16 16 03

I think that the root problem is that RCTCxxBridgeDelegate uses the namespaces and it exposes the a std::unique_ptr which resides in <memory>. We should have wrapped in a more compatible type, probably.


I have to think about this, because I don't like that solution, tbh. It looks like that .h files never has the __cplusplus flag set to true, and they are treated as c files, when they should be considered cpp files.

@Kudo
Copy link
Contributor Author

Kudo commented Dec 19, 2022

As you can see, the main app has the flag properly set in the Other Cplusplus Flags. React Native seems fine to me.
I made another test, stepping into the flags in the main.m file with the debugger. And yes, it skips them, but it does not skips them in the AppDelegate.mm.
If we rename it main.mm, it works.

oh yes you are right. since main.m is objc, so the compile flag should be "other c flags" (OTHER_CFLAGS). it has -DRN_FABRIC_ENABLED but not -DRCT_NEW_ARCH_ENABLED=1

@cipolleschi
Copy link
Contributor

What happens if we put the -DRCT_NEW_ARCH_ENABLED=1 flag also in the Others C Flags of the RCTAppDelegate pod? 🤔
Perhaps this fixes the problem completely.

@Kudo
Copy link
Contributor Author

Kudo commented Dec 19, 2022

What happens if we put the -DRCT_NEW_ARCH_ENABLED=1 flag also in the Others C Flags of the RCTAppDelegate pod?

if we add -DRCT_NEW_ARCH_ENABLED=1 and still stick on main.m, then the build error should expose to an app created from react-native template. maybe we should both add -DRCT_NEW_ARCH_ENABLED=1 and use main.mm where that feel more correct. however, i'm not 100% confident whether renaming main.mm would break other apps or not.

@cipolleschi
Copy link
Contributor

cipolleschi commented Dec 20, 2022

I investigated this a little bit more. I think that the right fix is to forward declare the class that are needed and use import them in the implementation file only.

So, the changes are:

  • In the RCTAppDelegate.h
#import <UIKit/UIKit.h>

#if RCT_NEW_ARCH_ENABLED
// When the new architecture is enabled, the RCTAppDelegate imports some additional headers

- #import <React/RCTCxxBridgeDelegate.h>
- #import <React/RCTSurfacePresenterBridgeAdapter.h>
- #import <ReactCommon/RCTTurboModuleManager.h>
+ @class RCTSurfacePresenterBridgeAdapter;
+ @class RCTTurboModuleManager;

#endif

// ...
#if RCT_NEW_ARCH_ENABLED
/// Extension that makes the RCTAppDelegate conform to New Architecture delegates
- @interface RCTAppDelegate () <RCTTurboModuleManagerDelegate, RCTCxxBridgeDelegate>
+ @interface RCTAppDelegate ()
  • In the RCTAppDelegate.mm
#if RCT_NEW_ARCH_ENABLED
+ #import <React/RCTCxxBridgeDelegate.h>
+ #import <React/RCTSurfacePresenterBridgeAdapter.h>
+ #import <ReactCommon/RCTTurboModuleManager.h>
#import <React/CoreModulesPlugins.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <react/config/ReactNativeConfig.h>

static NSString *const kRNConcurrentRoot = @"concurrentRoot";

- @interface RCTAppDelegate () {
+ @interface RCTAppDelegate () <RCTTurboModuleManagerDelegate, RCTCxxBridgeDelegate> {
  std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
  facebook::react::ContextContainer::Shared _contextContainer;
}
@end

#endif

In this way, the header file does not have to import any C++ class, because they are limited to the implementation file, which is already, correctly, a .mm file, and the header file can be compiled with C.

Could you give these changes a try in your setup? If they work, we can try and bring them in 0.71.0/0.71.1.
What do you think?

@Kudo
Copy link
Contributor Author

Kudo commented Dec 21, 2022

it's a clever idea and works like a charm. thanks @cipolleschi!

Kudo added a commit to expo/expo that referenced this pull request Dec 21, 2022
sdk 48 may come next year and react-native 0.71 may be released this year. it's good to have react-native 0.71 support for our modules. if users want to upgrade 0.71, they could change their project to be a bare project for the early preview.

- [core][av][gl] because 0.71 doesn't serve android aar along with npm package, the aar extraction from `node_modules/react-native/android/**/*.aar` will break on 0.71. 0.71 also ships modules with prefab support. it's good to rewrite the gradle/cmake files to link with prefab modules. that would reduce much complexity. however, to be backward compatible with 0.70, i moved most logic to `ExpoModulesCorePlugin.applyLegacyReactNativeLibsExtractionPlugin` and `legacy/CMakeLists.txt`. so that we could be backward compatible and easily remove the isolated code after we drop sdk 47 support.
- [dev-launcher] add 0.71 sources because new parameter to `DevSupportManagerBase`
- [core][dev-menu] fix ios build errors for jsc because 0.71 moved the header to `<React-jsc/JSCRuntime.h>`
- [core][autolinking] integrate the `RCTAppDelegate` with our `EXAppDelegateWrapper`. that would simply the install-expo-modules migration where we only need the change `RCTAppDelegate -> EXAppDelegateWrapper` in AppDelegate.h. however, integrate RCTAppDelegate comes with some issues from expo-modules-core. [this commit](2959477) changes many code and i'll try to explain here:
  - RCTAppDelegate is in `React-RCTAppDelegate` pod, which does not define module. we define module for it in our patch system in autolinking.
  - defines `RCT_NEW_ARCH_ENABLED` as RCTAppDelegate
  - in new architecture mode, RCTAppDelegate comes with [more cxx dependencies](https://github.com/facebook/react-native/blob/03b17d9af7e4e3ad3f9ec078b76d0ffa33a3290e/Libraries/AppDelegate/RCTAppDelegate.h#L12-L18) for fabric. that's why we should add more header search paths and also move to EXAppDelegateWrapper.mm.

- [x] ci passed
- [x] bare-expo build and launch
- [x] bare-expo nightlies build and launch
- [x] fabric-tester build and launch
- [x] fabric-tester nighties build and launch (should apply [the patch to fabric-tester](https://gist.github.com/Kudo/417a5159cb01a400ecee22ad4985d287))
- [x] rn 0.71-rc4 project build and launch (could apply [the patches](https://gist.github.com/Kudo/7448c733f12e700c7fbed76251fa3553) for testing)
- [x] rn 0.71-rc4 project (new architecture) build and launch ([this pr](facebook/react-native#35661) for react-native is required)
- [x] rn 0.71-rc4 project (use_frameworks!) build and launch

(cherry picked from commit d4cd4df)
@cipolleschi
Copy link
Contributor

I'm glad to hear that! Would you update this PR with the suggested changes, so that I can import and land it? Or should I do it myself?

Copy link
Contributor

@cipolleschi cipolleschi left a comment

Choose a reason for hiding this comment

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

Thanks for doing this! 🙏

I still have a small doubt about forward declaring the classes without the #if RCT_NEW_ARCH_ENABLED guard. But let's see if the CI complains about that. 👍

@facebook-github-bot
Copy link
Contributor

@cipolleschi has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@pull-bot
Copy link

PR build artifact for 097ce3b is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@Kudo
Copy link
Contributor Author

Kudo commented Dec 30, 2022

thanks @cipolleschi for the great idea and help. i've tested old architecture on my end and it works well. also the ios circle ci jobs look fine but those android ci jobs break at unstable sonatype maven server. please let me know whatever i can help.

@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label Dec 30, 2022
@facebook-github-bot
Copy link
Contributor

@cipolleschi merged this pull request in 5eb25d2.

@Kudo Kudo deleted the rctappdelegate-swift branch December 30, 2022 15:13
@Kudo
Copy link
Contributor Author

Kudo commented Dec 30, 2022

thanks for the great help 👍

kelset pushed a commit that referenced this pull request Jan 19, 2023
)

Summary:
When inheriting `RCTAppDelegate` in a module with swift code, the compiler will have a build error when it goes through module headers. because swift does not support cxx headers. we found this issue when we try to inherit the class at Expo's [`EXAppDelegateWrapper`](https://github.com/expo/expo/blob/main/packages/expo-modules-core/ios/AppDelegates/EXAppDelegateWrapper.h) with RCTAppDelegate in new architecture mode.

## Changelog

[IOS][FIXED] - Fix build errors when inheriting RCTAppDelegate in Swift modules

Pull Request resolved: #35661

Test Plan:
- ci passed
- tested with expo's setup: expo/expo#20470

Reviewed By: rshest

Differential Revision: D42293851

Pulled By: cipolleschi

fbshipit-source-id: 8a173279db070cc0008c6f8214093951f504dcc1
OlimpiaZurek pushed a commit to OlimpiaZurek/react-native that referenced this pull request May 22, 2023
…ebook#35661)

Summary:
When inheriting `RCTAppDelegate` in a module with swift code, the compiler will have a build error when it goes through module headers. because swift does not support cxx headers. we found this issue when we try to inherit the class at Expo's [`EXAppDelegateWrapper`](https://github.com/expo/expo/blob/main/packages/expo-modules-core/ios/AppDelegates/EXAppDelegateWrapper.h) with RCTAppDelegate in new architecture mode.

## Changelog

[IOS][FIXED] - Fix build errors when inheriting RCTAppDelegate in Swift modules

Pull Request resolved: facebook#35661

Test Plan:
- ci passed
- tested with expo's setup: expo/expo#20470

Reviewed By: rshest

Differential Revision: D42293851

Pulled By: cipolleschi

fbshipit-source-id: 8a173279db070cc0008c6f8214093951f504dcc1
@cipolleschi cipolleschi mentioned this pull request Oct 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Contributor A React Native contributor. Merged This PR has been merged. p: Expo Partner: Expo Partner
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants