react-native
react-native copied to clipboard
Redefinition of 'Native....SpecJSI' . Error when building with a custom turbo module
Description
Redefinition of 'Native....SpecJSI' . Error when building with a custom turbo module. I strictly followed the instructions for create turbo module https://reactnative.dev/docs/the-new-architecture/pillars-turbomodules
Steps to reproduce
--
React Native Version
0.73.2
Affected Platforms
Runtime - iOS
Areas
TurboModule - The New Native Module System
Output of npx react-native info
System:
OS: macOS 14.2.1
CPU: (12) arm64 Apple M3 Pro
Memory: 99.55 MB / 18.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 18.19.0
path: ~/.nvm/versions/node/v18.19.0/bin/node
Yarn:
version: 1.22.21
path: /opt/homebrew/bin/yarn
npm:
version: 10.2.3
path: ~/.nvm/versions/node/v18.19.0/bin/npm
Watchman:
version: 2023.12.04.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.14.3
path: /Users/skinnynpale/.rbenv/shims/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 23.2
- iOS 17.2
- macOS 14.2
- tvOS 17.2
- visionOS 1.0
- watchOS 10.2
Android SDK: Not Found
IDEs:
Android Studio: 2023.1 AI-231.9392.1.2311.11076708
Xcode:
version: 15.2/15C500b
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.9
path: /usr/bin/javac
Ruby:
version: 3.0.6
path: /Users/skinnynpale/.rbenv/shims/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 18.2.0
wanted: 18.2.0
react-native:
installed: 0.73.2
wanted: 0.73.2
react-native-macos: Not Found
npmGlobalPackages:
"*react-native*": Not Found
Android:
hermesEnabled: true
newArchEnabled: true
iOS:
hermesEnabled: true
newArchEnabled: true
Stacktrace or Logs
/Users/skinnynpale/Library/Developer/Xcode/DerivedData/a4ord-cnymkqjxmmqjnmfdnnckwsbdoigs/Build/Products/Debug-iphonesimulator/React-Codegen/React_Codegen.framework/Headers/RTNCustomAppBrowserSpec/RTNCustomAppBrowserSpec.h:34:22 Redefinition of 'NativeCustomAppBrowserSpecJSI'
hi @skinnynpale can you share the repository you are using?
hi @skinnynpale can you share the repository you are using?
sorry, only turbo module https://github.com/skinnynpale/RTNCustomAppBrowser
thanks, I'll have a look at this tomorrow morning!
thanks, I'll have a look at this tomorrow morning!
I tried running this, it worked https://github.com/deepthisareddy19/turbonativemodules but when I pulled out the turbo module (folder RTNCalculator) and installed it in our application, the error is still the same even with it
Hi @skinnynpale, I tried to repro but I couldn't.
You can find my reproducer here this is public, so you should be able to see it.
I think that the problem is with your specific setup. So, we can investigate it a little:
- If you click on the Error in Xcode, it should show you where are the redefinitions, pointing to the various files where they are defined. One definition is in
RTNCalculatorSpec.h
file. We need to understand where is the other. - Could it be that your app's
package.json
(not the Turbomodule's one) define acodegenConfig
key as well? If yes, it could be that, when running the codegen, we generate the codegen for the library and then the codegen for the app generate the library once again, and we end up with 2 declaration of the JSI interface.
Let me know what you find!
Hi @skinnynpale, I tried to repro but I couldn't.
You can find my reproducer here this is public, so you should be able to see it.
I think that the problem is with your specific setup. So, we can investigate it a little:
- If you click on the Error in Xcode, it should show you where are the redefinitions, pointing to the various files where they are defined. One definition is in
RTNCalculatorSpec.h
file. We need to understand where is the other.- Could it be that your app's
package.json
(not the Turbomodule's one) define acodegenConfig
key as well? If yes, it could be that, when running the codegen, we generate the codegen for the library and then the codegen for the app generate the library once again, and we end up with 2 declaration of the JSI interface.Let me know what you find!
Thank you for your reply!
- any ideas?
Even deleting the "generated" folder from the rtn-calculator itself, where there was another instance creation, did not help
Hi @skinnynpale, I tried to repro but I couldn't.
You can find my reproducer here this is public, so you should be able to see it.
I think that the problem is with your specific setup. So, we can investigate it a little:
- If you click on the Error in Xcode, it should show you where are the redefinitions, pointing to the various files where they are defined. One definition is in
RTNCalculatorSpec.h
file. We need to understand where is the other.- Could it be that your app's
package.json
(not the Turbomodule's one) define acodegenConfig
key as well? If yes, it could be that, when running the codegen, we generate the codegen for the library and then the codegen for the app generate the library once again, and we end up with 2 declaration of the JSI interface.Let me know what you find!
there is no codegenConfig in our project's package.json
@cipolleschi oh my...
i deleted -DRCT_NEW_ARCH_ENABLED=1 from section Other C++ Flags under Apple Clang — Custom Compiler flags and commented this line and now the build was compiled
We experience the same in react-native-google-mobile-ads: https://github.com/invertase/react-native-google-mobile-ads/issues/532
@dylancom can you provide a reproducer?
I have the same problem. I did the TurboModule example with RTNCalculator. I did step by step multiple times and it seems that the same error occurs. I also cleaned the npm modules and iOS pod files multiple times.
@dylancom can you provide a reproducer?
@cipolleschi I have faced same as the issue. We can create an empty project and set flag RCT_NEW_ARCH_ENABLED=1 on pod install script and built.
I'm sorry, but I need a reproducer from you, guys. I build new empty apps with React Nativ and the New Architecture every day as that is my main focus, but I can't reproduce this issue in any way. :(
@eflashcards which commands are you using to create an empty project? @dumbravaandrei22 are you sure you followed the tutorial correctly? For example, here skinnynpale deleted a line inadvertently and it make everything fail... @dylancom can you provide a reproducer?
@cipolleschi My scripts:
- Install Admob:
yarn add react-native-google-mobile-ads
- Install pod as Script In package.json from root Project. "pod-i": " cd ios && NO_FLIPPER=1 USE_FRAMEWORKS=static RCT_NEW_ARCH_ENABLED=0 pod install && cd ..",
USE_FRAMEWORDS= static as this: https://docs.page/invertase/react-native-google-mobile-ads#optionally-configure-ios-static-frameworks Also note:
...
use_frameworks! :linkage => :static
$RNFirebaseAsStaticFramework = true
$RNGoogleMobileAdsAsStaticFramework = true
....
flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled
linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
use_frameworks! :linkage => linkage.to_sym
end
linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
use_frameworks! :linkage => linkage.to_sym
end
...
target 'YourApp' do
...
end
I used to fix in my code like this to test and It fixed but not a correct fix @cipolleschi
Due to duplicated definition when doing codegen. So It may be from codegen issues - I think so!
@eflashcards thanks for the reproducer steps and the heads up with the pragmas. It might be that we forgot to add #pragma once
in the codegen? 🤔
Yes @cipolleschi . I used to code objective-c & C/C++. When we include a header file. We must check If the class defined or not to avoid duplication from #import / #include from two other places.
- If the Class A has defined in File B (import A.h), we should skip in the File C (import A.h). Preprocessor format:
#ifndef A_H #define A_H
class A { ... }
#endif
I managed to repro it locally! :D
One think I noticed is that both RNTCalculator.h
and RNTCalculator.mm
both import the same file.
- RNTCalculator.h
+#import <RNTCalculatorSpec/RNTCalculatorSpec.h>
NS_ASSUME_NONNULL_BEGIN
@interface RNTCalculator : NSObject <NativeCalculatorSpec>
- RNTCalculator.mm
+#import "RNTCalculatorSpec.h"
#import "RNTCalculator.h"
@implementation RNTCalculator
// ...
So, what happens is that, when Xcode builds the RNTCalculator.mm
, it takes the RNTCalculatorSpec
once because it has been explicitly imported by line 1, and then it takes it another time because the #import "RNTCalculator.h"
import the RNTCalculatorSpec
transitively.
The first line can be removed:
-#import "RNTCalculatorSpec.h"
#import "RNTCalculator.h"
@implementation RNTCalculator
// ...
And everything will work fine ==> The error goes away.
That said, this is a bit brittle. I'd like to see if we can find a systematic approach to solve this.
cc. @eflashcards @dylancom @dumbravaandrei22 @skinnynpale @javache
We'll probably end up applying the @eflashcards suggestions in codegen directly. For some reasons, #pragma once
does not work in this case.
For some reasons - I found a quick fix for the error on React Native Google Mobile Ads by this patch:
diff --git a/node_modules/react-native-google-mobile-ads/ios/RNGoogleMobileAds/RNGoogleMobileAdsModule.mm b/node_modules/react-native-google-mobile-ads/ios/RNGoogleMobileAds/RNGoogleMobileAdsModule.mm
index 9e48dec..8c25534 100644
--- a/node_modules/react-native-google-mobile-ads/ios/RNGoogleMobileAds/RNGoogleMobileAdsModule.mm
+++ b/node_modules/react-native-google-mobile-ads/ios/RNGoogleMobileAds/RNGoogleMobileAdsModule.mm
@@ -21,9 +21,9 @@
#import <React/RCTUtils.h>
#import "RNGoogleMobileAdsModule.h"
-#ifdef RCT_NEW_ARCH_ENABLED
-#import "RNGoogleMobileAdsSpec.h"
-#endif
+// #ifdef RCT_NEW_ARCH_ENABLED
+// #import "RNGoogleMobileAdsSpec.h"
+// #endif
#import "common/RNSharedUtils.h"
@implementation RNGoogleMobileAdsModule
This line makes duplicated code: https://github.com/invertase/react-native-google-mobile-ads/blob/d438bf24e1caa479570772be8a78c35ac09cebe5/ios/RNGoogleMobileAds/RNGoogleMobileAdsModule.mm#L25 While It is importing here: https://github.com/invertase/react-native-google-mobile-ads/blob/d438bf24e1caa479570772be8a78c35ac09cebe5/ios/RNGoogleMobileAds/RNGoogleMobileAdsModule.h#L22C1-L22C56
@cipolleschi @dylancom Though I think that should be fixed from the codegen. But some magic thing is from the import. When we import header file in .m and .mm files => #pragma once is not working is in case. My suggestion: We should only import xxxxSpec.h or xxxxTurbo.h in the header file. Then we import the module's header file in to main module (.mm) file.
I.E:
// MyNativeModule.h
#pragma once
... import your turbo.h or Specs.h files here
// MyNativeModule.mm
#import "MyNativeModule.h"
...Please don't import your turbo.h or Specs.h files here
=> Because in my project now - My app is still crash for some reasons which I am investigating. But I can build by my above patch.
Yes, #pragma once
doesn't seem to work on iOS when using codegen.
I do agree to everything @eflashcards mentioned:
- I fixed the docs, here, to make sure that there is only one import of those files.
- I'm working on a Codegen change to add the
#include
guards here.
Hopefully, we will be able to fix this for good soon and systematically..