Skip to content

The C++ Turbo Module template uses a Kotlin implementation on Android #829

Description

Description

I'm not sure if I'm missing something obvious but when creating the library template for a Turbo Module using C++ for Android & iOS there is a default example implementing a multiply function. However, on Android the implementation for this function is in Kotlin and it doesn't use the shared C++ library.

When the JS code calls multiply it comes into the code here.

Is there any reason why the OnLoad.cpp file isn't used to register the turbo module in this case as described here: pure-cxx-modules#android

Packages

  • create-react-native-library
  • react-native-builder-bob

Selected options

  1. npx create-react-native-library cppLibraryTest
  2. ? What is the name of the npm package? › cpp-lib-test
  3. ? What type of library do you want to develop? › Turbo Module
  4. ? Which languages do you want to use? › C++ for Android & iOS

Link to repro

N/A

Environment

System:
  OS: macOS 15.0.1
  CPU: (11) arm64 Apple M3 Pro
  Memory: 90.06 MB / 18.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 23.7.0
    path: /opt/homebrew/bin/node
  Yarn:
    version: 3.6.1
    path: /opt/homebrew/bin/yarn
  npm:
    version: 11.2.0
    path: /opt/homebrew/bin/npm
  Watchman:
    version: 2025.02.17.00
    path: /opt/homebrew/bin/watchman
Managers:
  CocoaPods:
    version: 1.16.2
    path: /opt/homebrew/opt/ruby/bin/pod

Activity

  1. Zach-Dean-Attractions-io commented on Apr 25, 2025

    @Zach-Dean-Attractions-io
    Author

    I think the fix is relatively straightforward to call the native multiply implementation from the Kotlin implementation

    package com.cpplibtest
    
    import com.facebook.react.bridge.ReactApplicationContext
    import com.facebook.react.module.annotations.ReactModule
    
    @ReactModule(name = CppLibTestModule.NAME)
    class CppLibTestModule(reactContext: ReactApplicationContext) :
      NativeCppLibTestSpec(reactContext) {
    
      override fun getName(): String {
        return NAME
      }
    
      // Example method
      // See https://reactnative.dev/docs/native-modules-android
      override fun multiply(a: Double, b: Double): Double {
    -   return a * b
    +   return nativeMultiply(a, b)
      }
    
      companion object {
        const val NAME = "CppLibTest"
    
    +   @JvmStatic
    +   external fun nativeMultiply(a: Double, b: Double): Double
    
    +   init {
    +     System.loadLibrary("cpp-lib-test")
    +   }
      }
    }

    I think it should be possible to use a pure C++ implementation as described here though whereas this methodology is more of a Kotlin implementation which calls into shared C++ code using the JNI. I'll try take a look into this.

  2. Zach-Dean-Attractions-io commented on Apr 25, 2025

    @Zach-Dean-Attractions-io
    Author

    Oh I see this template has been removed: #818

    Is there any plan to support a pure C++ module template in the future? With React Native 0.79.0 there is a way to register pure C++ modules via the codegen spec, so I think this should allow for a pure C++ self contained library implementation.

  3. satya164 commented on Apr 25, 2025

    @satya164
    Member

    Is there any plan to support a pure C++ module template in the future

    I haven't managed to write a C++ library that works. The official docs only cover how to write one in existing app, https://reactnative.dev/docs/the-new-architecture/pure-cxx-modules, but trying to use same approach with a library doesn't seem to work with autolinking.

    If you figure out how then PR or a sample library I can turn into a template is welcome.

  4. Zach-Dean-Attractions-io commented on Apr 28, 2025

    @Zach-Dean-Attractions-io
    Author

    I did manage to get iOS working by adding code to the consuming app's AppDelegate file to register the module. I think React Native 0.79.0 released something in the codegen process to declare your native modules and it would link them for you but I ran into a crash when trying this. I asked in the reactwg repo here about it: reactwg/react-native-new-architecture#286

    However, I stumbled across this youtube video https://www.youtube.com/watch?v=KURIqiCPbco and they used an Objective-C file in the library and registered the native module in the + (void) load function.

    #import <Foundation/Foundation.h>
    #import "MyCpp.h"
    #import <ReactCommon/CxxTurboModuleUtils.h>
    
    
    @interface OnLoad : NSObject
    @end
    
    @implementation OnLoad
    
    using namespace facebook::react;
    
    + (void) load {
      registerCxxModuleToGlobalModuleMap(
        std::string(MyCpp::kModuleName),
        [](std::shared_ptr<CallInvoker> jsInvoker) {
          return std::make_shared<MyCpp>(jsInvoker);
        }
      );
    }
    
    @end

    This is working for me. I'm going to watch the Android version next and try implementing that. If I get both working I'll either share a repo or create a PR (if time allows).

    I'll also ask in the reactwg repo to check this is best practise.

  5. Zach-Dean-Attractions-io commented on Apr 28, 2025

    @Zach-Dean-Attractions-io
    Author

    Ok I have Android working too thanks to the author's other video https://www.youtube.com/watch?v=ibgHObp8YwA&t=8s

    This repo has the changes for Android & iOS react-native-pure-cpp-turbo-module-library. If I get time I could attempt a PR to add it into the create-react-native-library project, but I also might wait for a review from the RN team to check this is best practice and if there are any mistakes that I have made or other problems this solution may cause.

  6. satya164 commented on Apr 30, 2025

    @satya164
    Member

    @Zach-Dean-Attractions-io thank you! i'll check it out

  7. satya164 commented on May 3, 2025

    @satya164
    Member

    @Zach-Dean-Attractions-io I was able to setup a sample with the latest template based on your example https://github.com/satya164/react-native-pure-cpp-turbo-module-library

    However, before we can include it as a template, we would want to disable includeGeneratedCode, and while it works on iOS, it doesn't seem to work on Android.

  8. Zach-Dean-Attractions-io commented on May 6, 2025

    @Zach-Dean-Attractions-io
    Author

    Hi @satya164

    I did see in this PR #819 it was planned to remove includesGeneratedCode: true. I was quite confused (due to my own lack of understanding) about the documentation on that flag and managed to clear up my understanding here: reactwg/react-native-new-architecture#272 (reply in thread). I think I will include includesGeneratedCode: true in my project since if I don't include it and the consuming app runs codegen for me, it still might be using an incompatible version of React Native.

    However, that doesn't matter really as the library template should work with includesGeneratedCode: true / false and not just one option. I'll try take a look this week but I'm not too clued in to how everything works under the hood myself so might have to ask in the react working group.

  9. Zach-Dean-Attractions-io commented on May 9, 2025

    @Zach-Dean-Attractions-io
    Author

    I haven't had much time to look into it sorry.

    However, from what I can see there is a file generated called autolinking.json and this file includes

    "android": {
      "cmakeListsPath": "/Users/zachdean/Desktop/react-native-pure-cpp-turbo-module-library/android/build/generated/source/codegen/jni/CMakeLists.txt",
    }
    

    Then in the Gradle task GenerateAutolinkingNewArchitecturesFileTask.kt this json file is used to write a file example/android/app/build/generated/autolinking/src/main/jni/Android-autolinking.cmake and this looks like:

    # This code was generated by [React Native](https://www.npmjs.com/package/@react-native/gradle-plugin)
    cmake_minimum_required(VERSION 3.13)
    set(CMAKE_VERBOSE_MAKEFILE on)
    
    # We set REACTNATIVE_MERGED_SO so libraries/apps can selectively decide to depend on either libreactnative.so
    # or link against a old prefab target (this is needed for React Native 0.76 on).
    set(REACTNATIVE_MERGED_SO true)
    
    add_subdirectory("/Users/zachdean/Desktop/react-native-pure-cpp-turbo-module-library/android/build/generated/source/codegen/jni/" PureCppTurboModuleLibrarySpec_autolinked_build)
    add_subdirectory("/Users/zachdean/Desktop/react-native-pure-cpp-turbo-module-library/android/" PureCppTurboModuleLibrarySpec_cxxmodule_autolinked_build)
    
    set(AUTOLINKED_LIBRARIES
      react_codegen_PureCppTurboModuleLibrarySpec
    react-native-pure-cpp-turbo-module-library
    )
    

    The first add_subdirectory line causes an issue because the generated code isn't shipped with the library. Looking at the code that generates the Android-autolinking.cmake file, I expected that if I set cmakeListsPath: null in react-native.config.js then it might avoid this add_subdirectory command but that doesn't seem to work it is still populated with that default path.

    I manually set it to null in the autolinking.json file

    "android": {
      "cmakeListsPath": null,
    }
    

    But then I run into another error.

    CMake Error at example/node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake:103 (target_link_libraries):
        Cannot specify link libraries for target
        "react_codegen_RNPureCppTurboModuleLibrarySpec" which is not built by this
        project.
    

    The generated CMake file adds a library react_codegen_PureCppTurboModuleLibrarySpec, which I assume doesn't get built if the generated code isn't shipped with the library. Although I would expect the consuming app would generated the CMake file to add this library, otherwise it wouldn't be possible to create a C++ library without includesGeneratedCode: true. Maybe the app needs to also include what this generated CMake file would have done.

    However, some of the paths here such as react/renderer/components/RNPureCppTurboModuleLibrarySpec/*.cpp don't seem to exist if includesGeneratedCode: true isn't specified. I thought that the consuming app might generated them in a build folder but I can't see that it does.

    Another example is PureCppImpl.h includes RNPureCppTurboModuleLibrarySpecJSI.h which is in the generated folder but doesn't seem to be created in the example app if the generated code isn't there. Unless the error just occurs before it can generate those files.

    # Copyright (c) Meta Platforms, Inc. and affiliates.
    #
    # This source code is licensed under the MIT license found in the
    # LICENSE file in the root directory of this source tree.
    
    cmake_minimum_required(VERSION 3.13)
    set(CMAKE_VERBOSE_MAKEFILE on)
    
    file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS *.cpp react/renderer/components/RNPureCppTurboModuleLibrarySpec/*.cpp)
    
    add_library(
      react_codegen_RNPureCppTurboModuleLibrarySpec
      OBJECT
      ${react_codegen_SRCS}
    )
    
    target_include_directories(react_codegen_RNPureCppTurboModuleLibrarySpec PUBLIC . react/renderer/components/RNPureCppTurboModuleLibrarySpec)
    
    target_link_libraries(
      react_codegen_RNPureCppTurboModuleLibrarySpec
      fbjni
      jsi
      # We need to link different libraries based on whether we are building rncore or not, that's necessary
      # because we want to break a circular dependency between react_codegen_rncore and reactnative
      reactnative
    )
    
    target_compile_options(
      react_codegen_RNPureCppTurboModuleLibrarySpec
      PRIVATE
      -DLOG_TAG=\"ReactNative\"
      -fexceptions
      -frtti
      -std=c++20
      -Wall
    )
    

    I might have to ask this in the react working group because I can't quite see that it is possible but I am sure that's more my lack of understanding.

  10. Zach-Dean-Attractions-io commented on May 9, 2025

    @Zach-Dean-Attractions-io
    Author

    Ok I think I have found the problem. I took a look at the recent version of create-react-native-library and the turbo module template which works correctly. When you build the consuming app it generates the code in the android directory that the module requires.

    This isn't happening in this project and so the build fails. I think this is due to the fact there is no build.gradle in the android directory which configures the React Native plugin.

    If you clone this repo you should be able to remove includesGeneratedCode: true and build android successfully.

    You may not need the files within android/src/main but I think you need the build.gradle file.

    I think it is this code that lets the React Native Plugin know our library is using codegen.

    react {
     jsRootDir = file("../src/")
     libraryName = "PureCppTurboModuleLibrary"
     codegenJavaPackageName = "com.purecppturbomodulelibrary"
    }
    
  11. satya164 commented on May 9, 2025

    @satya164
    Member

    @Zach-Dean-Attractions-io thanks a lot for the investigation. I'll check it out. ideally it shouldn't need a build.gradle (react-native-community/cli#2387) but i guess that's something to be fixed.

  12. Zach-Dean-Attractions-io commented on May 9, 2025

    @Zach-Dean-Attractions-io
    Author

    Ah right I see! I'm not sure in that case sorry. Let me know what you find.

  13. ShamKarthik-TA commented on May 26, 2025

    @ShamKarthik-TA

    @Zach-Dean-Attractions-io thanks a lot for the investigation. I'll check it out. ideally it shouldn't need a build.gradle (react-native-community/cli#2387) but i guess that's something to be fixed.

    @satya164 I tried out your repo with the fixes but still the same error exists, am I missing any configs

    https://github.com/satya164/react-native-pure-cpp-turbo-module-library

    CMake Error at example/node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake:103 (target_link_libraries):
        Cannot specify link libraries for target
        "react_codegen_RNPureCppTurboModuleLibrarySpec" which is not built by this
        project.
    
  14. satya164 commented on May 26, 2025

    @satya164
    Member

    @Zach-Dean-Attractions-io thanks a lot for the investigation. I'll check it out. ideally it shouldn't need a build.gradle (react-native-community/cli#2387) but i guess that's something to be fixed.

    @satya164 I tried out your repo with the fixes but still the same error exists, am I missing any configs

    https://github.com/satya164/react-native-pure-cpp-turbo-module-library

    CMake Error at example/node_modules/react-native/ReactAndroid/cmake-utils/ReactNative-application.cmake:103 (target_link_libraries):
        Cannot specify link libraries for target
        "react_codegen_RNPureCppTurboModuleLibrarySpec" which is not built by this
        project.
    

    You can revert the last commit to have a working implementation with includesGeneratedCode: true. Right now it's not possible to disable it, looks like bug in autolinking.

  15. Navipro70 commented on Jul 13, 2025

    @Navipro70

    I'm confused a lot of current documentation for pure C++ module implementation by the way of separated package

    I was able to add C++ module into existed react-native project by docs, so that was a challenge for a while, but I've passed it successfully. So the next step I was going to separate this module from existed project to a npm library, and at the point I'm struggling with it now :(

    I've succesfully linked C++ module with IOS project, it was pretty much the same as in docs. Bring C++ code, make static library by podspec, write wrapper in Obj-C++, also an important thing is to add modulesProvider in codegenConfig in package.json - all is done.

    But Android... I've tried a way from docs and it fails up at CMakeLists.txt at include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake) on a build phase of android from example folder. So I've tried a lot of CMakeLists.txt configs, OnLoad.cpp from docs and much more but even if app was build successfully, it cannot find my native C++ module. I cannot recognize what I'm doing wrong because I don't even know what I should to do. All previous ways that I saw don't work for me (a lot of them are above)

    "react-native": "0.79.2",
    "react-native-builder-bob": "^0.40.12",
    "create-react-native-library": "0.51.1"
    
  16. Navipro70 commented on Jul 13, 2025

    @Navipro70

    Holy cache... Just deleted generated code from build directories in both android folders from root and example, rebuilt and all became working, for a point ./gradlew clean didn't help

    So would like to share my milestones to make pure C++ module working on android:

    1. Add build.gradle CMakeLists native build to android section (path is your relative path from android folder):
      externalNativeBuild {
        cmake {
          path "CMakeLists.txt"
        }
      }
    
    
    1. Add react-native.config.js with following code, replace names with your module names:
    module.exports = {
        dependency: {
            platforms: {
                /**
                 * @type {import('@react-native-community/cli-types').IOSDependencyParams}
                 */
                ios: {},
                /**
                 * @type {import('@react-native-community/cli-types').AndroidDependencyParams}
                 */
                android: {
                    cxxModuleCMakeListsModuleName: 'react-native-cryptopp',
                    cxxModuleCMakeListsPath: 'CMakeLists.txt',
                    cxxModuleHeaderName: 'NativeCryptopp',
                },
            },
        },
    };
    
    1. CMakeLists.txt for the following code, replace names with your module names:
    cmake_minimum_required(VERSION 3.4.1)
    project(NativeCryptopp)
    
    set (CMAKE_VERBOSE_MAKEFILE ON)
    
    add_library(react-native-cryptopp            STATIC
      ../cpp/NativeCryptopp.cpp
    )
    
    target_include_directories(
      react-native-cryptopp PUBLIC ../cpp
    )
    
    target_link_libraries(react-native-cryptopp
      jsi
      reactnative
      react_codegen_RNCryptoppSpec
    )
    
    
    1. Delete all files in android/src/main/java except the {YOUR_GENERATED_MODULE_NAME}Package.kt and make it empty (need for linking, but as I saw at @satya164 repo it can be deleted as well, but I didn't found a way to do it) like this:
    package com.cryptopp
    
    
    import com.facebook.react.BaseReactPackage
    import com.facebook.react.bridge.NativeModule
    import com.facebook.react.bridge.ReactApplicationContext
    import com.facebook.react.module.model.ReactModuleInfo
    import com.facebook.react.module.model.ReactModuleInfoProvider
    import java.util.HashMap
    
    class CryptoppPackage : BaseReactPackage() {
      override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
        return null
      }
    
      override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
        return ReactModuleInfoProvider {
          val moduleInfos: MutableMap<String, ReactModuleInfo> = HashMap()
    
          moduleInfos
        }
      }
    }
    
    

    Don't forget to delete all build before building a new one.

  17. Zach-Dean-Attractions-io commented on Jul 14, 2025

    @Zach-Dean-Attractions-io
    Author

    Hi @Navipro70

    You should be able to use https://github.com/Zach-Dean-Attractions-io/react-native-pure-cpp-turbo-module-library for a working example of a pure C++ turbo module on both iOS and Android. Although it does use includesGeneratedCode: true in the codegen configuration and an extra configuration in react-native.config.js to support that, but that may or may not be a problem for you.

  18. Navipro70 commented on Jul 14, 2025

    @Navipro70

    @Zach-Dean-Attractions-io
    Hello!
    Thank you for helping out. I figured it out without includeGeneratedCode, if anybody need one more project as an example, you're welcome 😁: https://github.com/Navipro70/react-native-crypto-cpp

    Also sorry for a little mess above, my issue and messages isn't fully belong to original one but I found it helpful for other because didn't found the way myself in docs and other sources. But what a point we have now? For me personally it would be nice to have:

    1. Updated React Native documentation for https://reactnative.dev/docs/the-new-architecture/create-module-library. Because for pure C++ it's incorrect, you don't need OnLoad.cpp, moreover, CMakeLists.txt changing a lot when you copy code and pretty much other stuff already mentioned here.
    2. Create C++ Turbo Modules template in create-react-native-library. Because as I remember I started my project with just pure native mobile files (Obj-C and Kotlin) and didn't have an option for pure C++ module creation.

    @Zach-Dean-Attractions-io you also mentioned that you have wrote a question/issue to a react-native, may you please give us a link to it? And also what do you think about my millstones above? Thanks.

  19. nocanstillbb commented on Sep 27, 2025

    @nocanstillbb

    I want to know how to remove the codegen of .kt. I use turbomoduel in c++ on both Android and iOS, but every time I modify Nativexxx.ts, kotlin also needs to be modified, otherwise there will be a compilation error.

  20. nocanstillbb commented on Sep 27, 2025

    @nocanstillbb

    I want to know how to remove the codegen of .kt. I use turbomoduel in c++ on both Android and iOS, but every time I modify Nativexxx.ts, kotlin also needs to be modified, otherwise there will be a compilation error.

    modify .kt files under turbomodule-library/android/src/main/java/com/ folder, don't inherit the glue code, you won't get an error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions