From 144a1a02b33811ee5de7994f839d603b54636e4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Gu=CC=88ner?= Date: Fri, 10 May 2024 23:33:24 +0300 Subject: [PATCH 1/7] feat(android): add cxxOnly config property --- docs/dependencies.md | 8 ++++++++ docs/platforms.md | 1 + packages/cli-config/src/schema.ts | 1 + packages/cli-types/src/android.ts | 2 ++ 4 files changed, 12 insertions(+) diff --git a/docs/dependencies.md b/docs/dependencies.md index 527693fd6..1374aca73 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -61,6 +61,7 @@ type AndroidDependencyParams = { cxxModuleCMakeListsModuleName?: string | null; cxxModuleCMakeListsPath?: string | null; cxxModuleHeaderName?: string | null; + cxxOnly?: boolean; }; ``` @@ -187,3 +188,10 @@ std::shared_ptr rncli_cxxModuleProvider( return nullptr; } ``` + + +#### platforms.android.cxxOnly + +> Note: Only applicable when new architecture is turned on and for C++ TurboModules. + +When this flag is set to `true`, the dependency will be treated as a C++ only module. This means that the dependency will not be included in the autolinking logic for Java modules. This is useful when you have a C++ only module that does not have any Java code. diff --git a/docs/platforms.md b/docs/platforms.md index 770a8207f..e71aa15cd 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -128,5 +128,6 @@ type AndroidDependencyConfig = { cxxModuleCMakeListsModuleName? : string | null; cxxModuleCMakeListsPath? : string | null; cxxModuleHeaderName? : string | null; + cxxOnly?: boolean; }; ``` diff --git a/packages/cli-config/src/schema.ts b/packages/cli-config/src/schema.ts index 6f4e1ba03..0e0e79eb9 100644 --- a/packages/cli-config/src/schema.ts +++ b/packages/cli-config/src/schema.ts @@ -89,6 +89,7 @@ export const dependencyConfig = t cxxModuleCMakeListsModuleName: t.string().allow(null), cxxModuleCMakeListsPath: t.string().allow(null), cxxModuleHeaderName: t.string().allow(null), + cxxOnly: t.boolean(), }) .allow(null), }) diff --git a/packages/cli-types/src/android.ts b/packages/cli-types/src/android.ts index 109a8142c..690fba0a8 100644 --- a/packages/cli-types/src/android.ts +++ b/packages/cli-types/src/android.ts @@ -35,6 +35,7 @@ export type AndroidDependencyConfig = { cxxModuleCMakeListsModuleName?: string | null; cxxModuleCMakeListsPath?: string | null; cxxModuleHeaderName?: string | null; + cxxOnly?: boolean; }; export type AndroidDependencyParams = { @@ -51,4 +52,5 @@ export type AndroidDependencyParams = { cxxModuleCMakeListsModuleName?: string | null; cxxModuleCMakeListsPath?: string | null; cxxModuleHeaderName?: string | null; + cxxOnly?: boolean; }; From fef5a1563df8c8ceb15e75a0e99318a6fc60aa6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Gu=CC=88ner?= Date: Fri, 10 May 2024 23:34:09 +0300 Subject: [PATCH 2/7] feat(android-autolinking): Dont search for java related properties if cxxOnly is true --- packages/cli-platform-android/src/config/index.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cli-platform-android/src/config/index.ts b/packages/cli-platform-android/src/config/index.ts index f914b33a7..d40b0c4dc 100644 --- a/packages/cli-platform-android/src/config/index.ts +++ b/packages/cli-platform-android/src/config/index.ts @@ -135,8 +135,9 @@ export function dependencyConfig( ? path.join(sourceDir, userConfig.manifestPath) : findManifest(sourceDir); const buildGradlePath = findBuildGradle(sourceDir, true); + const cxxOnly = userConfig.cxxOnly || false; - if (!manifestPath && !buildGradlePath) { + if (!cxxOnly && !manifestPath && !buildGradlePath) { return null; } @@ -147,7 +148,7 @@ export function dependencyConfig( /** * This module has no package to export */ - if (!packageClassName) { + if (!cxxOnly && !packageClassName) { return null; } @@ -193,5 +194,6 @@ export function dependencyConfig( cxxModuleCMakeListsModuleName, cxxModuleCMakeListsPath, cxxModuleHeaderName, + cxxOnly, }; } From 29ad1a88f08bb91aceba7b7b0a5ee0e8433daeb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Gu=CC=88ner?= Date: Fri, 10 May 2024 23:35:49 +0300 Subject: [PATCH 3/7] feat(android-autolinking): Don't autolink cxxOnly modules using the Java packagelist This also ignores them from getting included with gradle dependencies --- .../cli-platform-android/native_modules.gradle | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/cli-platform-android/native_modules.gradle b/packages/cli-platform-android/native_modules.gradle index d304de0e6..44d607f55 100644 --- a/packages/cli-platform-android/native_modules.gradle +++ b/packages/cli-platform-android/native_modules.gradle @@ -185,6 +185,12 @@ class ReactNativeModules { reactNativeModules.forEach { reactNativeModule -> def nameCleansed = reactNativeModule["nameCleansed"] def dependencyConfiguration = reactNativeModule["dependencyConfiguration"] + def cxxOnly = reactNativeModule["cxxOnly"] + + if (cxxOnly) { + return + } + appProject.dependencies { if (reactNativeModulesBuildVariants.containsKey(nameCleansed)) { reactNativeModulesBuildVariants @@ -247,10 +253,14 @@ class ReactNativeModules { "${prefix}${packageName}.${className}${suffix}" }) } - packageImports = packages.collect { + packageImports = packages + .findAll { !it.cxxOnly } + .collect { "// ${it.name}\n${interpolateDynamicValues(it.packageImportPath)}" }.join('\n') - packageClassInstances = ",\n " + packages.collect { + packageClassInstances = ",\n " + packages + .findAll { !it.cxxOnly } + .collect { interpolateDynamicValues(it.packageInstance) }.join(",\n ") } @@ -471,6 +481,7 @@ class ReactNativeModules { reactNativeModuleConfig.put("cxxModuleCMakeListsModuleName", androidConfig["cxxModuleCMakeListsModuleName"]) reactNativeModuleConfig.put("cxxModuleCMakeListsPath", androidConfig["cxxModuleCMakeListsPath"]) reactNativeModuleConfig.put("cxxModuleHeaderName", androidConfig["cxxModuleHeaderName"]) + reactNativeModuleConfig.put("cxxOnly", androidConfig["cxxOnly"]) if (androidConfig["buildTypes"] && !androidConfig["buildTypes"].isEmpty()) { reactNativeModulesBuildVariants.put(nameCleansed, androidConfig["buildTypes"]) From cdcb388d8feed35a684f488e4b9fb11fedc41c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Gu=CC=88ner?= Date: Sat, 11 May 2024 00:09:58 +0300 Subject: [PATCH 4/7] chore: remove unnecessary newline from dependencies --- docs/dependencies.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/dependencies.md b/docs/dependencies.md index 1374aca73..310f8f290 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -189,7 +189,6 @@ std::shared_ptr rncli_cxxModuleProvider( } ``` - #### platforms.android.cxxOnly > Note: Only applicable when new architecture is turned on and for C++ TurboModules. From 9a9117cfcac8c1123441a306e6f5b8b2e6f26f35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Gu=CC=88ner?= Date: Sat, 11 May 2024 13:40:52 +0300 Subject: [PATCH 5/7] chore: remove the cxxOnly property --- docs/dependencies.md | 7 ------- docs/platforms.md | 1 - packages/cli-config/src/schema.ts | 1 - packages/cli-platform-android/native_modules.gradle | 1 - packages/cli-types/src/android.ts | 2 -- 5 files changed, 12 deletions(-) diff --git a/docs/dependencies.md b/docs/dependencies.md index 310f8f290..527693fd6 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -61,7 +61,6 @@ type AndroidDependencyParams = { cxxModuleCMakeListsModuleName?: string | null; cxxModuleCMakeListsPath?: string | null; cxxModuleHeaderName?: string | null; - cxxOnly?: boolean; }; ``` @@ -188,9 +187,3 @@ std::shared_ptr rncli_cxxModuleProvider( return nullptr; } ``` - -#### platforms.android.cxxOnly - -> Note: Only applicable when new architecture is turned on and for C++ TurboModules. - -When this flag is set to `true`, the dependency will be treated as a C++ only module. This means that the dependency will not be included in the autolinking logic for Java modules. This is useful when you have a C++ only module that does not have any Java code. diff --git a/docs/platforms.md b/docs/platforms.md index e71aa15cd..770a8207f 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -128,6 +128,5 @@ type AndroidDependencyConfig = { cxxModuleCMakeListsModuleName? : string | null; cxxModuleCMakeListsPath? : string | null; cxxModuleHeaderName? : string | null; - cxxOnly?: boolean; }; ``` diff --git a/packages/cli-config/src/schema.ts b/packages/cli-config/src/schema.ts index 0e0e79eb9..6f4e1ba03 100644 --- a/packages/cli-config/src/schema.ts +++ b/packages/cli-config/src/schema.ts @@ -89,7 +89,6 @@ export const dependencyConfig = t cxxModuleCMakeListsModuleName: t.string().allow(null), cxxModuleCMakeListsPath: t.string().allow(null), cxxModuleHeaderName: t.string().allow(null), - cxxOnly: t.boolean(), }) .allow(null), }) diff --git a/packages/cli-platform-android/native_modules.gradle b/packages/cli-platform-android/native_modules.gradle index 44d607f55..122560496 100644 --- a/packages/cli-platform-android/native_modules.gradle +++ b/packages/cli-platform-android/native_modules.gradle @@ -481,7 +481,6 @@ class ReactNativeModules { reactNativeModuleConfig.put("cxxModuleCMakeListsModuleName", androidConfig["cxxModuleCMakeListsModuleName"]) reactNativeModuleConfig.put("cxxModuleCMakeListsPath", androidConfig["cxxModuleCMakeListsPath"]) reactNativeModuleConfig.put("cxxModuleHeaderName", androidConfig["cxxModuleHeaderName"]) - reactNativeModuleConfig.put("cxxOnly", androidConfig["cxxOnly"]) if (androidConfig["buildTypes"] && !androidConfig["buildTypes"].isEmpty()) { reactNativeModulesBuildVariants.put(nameCleansed, androidConfig["buildTypes"]) diff --git a/packages/cli-types/src/android.ts b/packages/cli-types/src/android.ts index 690fba0a8..109a8142c 100644 --- a/packages/cli-types/src/android.ts +++ b/packages/cli-types/src/android.ts @@ -35,7 +35,6 @@ export type AndroidDependencyConfig = { cxxModuleCMakeListsModuleName?: string | null; cxxModuleCMakeListsPath?: string | null; cxxModuleHeaderName?: string | null; - cxxOnly?: boolean; }; export type AndroidDependencyParams = { @@ -52,5 +51,4 @@ export type AndroidDependencyParams = { cxxModuleCMakeListsModuleName?: string | null; cxxModuleCMakeListsPath?: string | null; cxxModuleHeaderName?: string | null; - cxxOnly?: boolean; }; From 79bfbd425ddb7b059cd697c34d5a1d66faef7a9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Gu=CC=88ner?= Date: Sat, 11 May 2024 14:48:54 +0300 Subject: [PATCH 6/7] feat: derive if a dependency is pure cxx from other properties --- .../native_modules.gradle | 10 ++--- .../cli-platform-android/src/config/index.ts | 45 +++++++++++-------- packages/cli-types/src/android.ts | 5 ++- 3 files changed, 35 insertions(+), 25 deletions(-) diff --git a/packages/cli-platform-android/native_modules.gradle b/packages/cli-platform-android/native_modules.gradle index 122560496..c797a459f 100644 --- a/packages/cli-platform-android/native_modules.gradle +++ b/packages/cli-platform-android/native_modules.gradle @@ -185,9 +185,8 @@ class ReactNativeModules { reactNativeModules.forEach { reactNativeModule -> def nameCleansed = reactNativeModule["nameCleansed"] def dependencyConfiguration = reactNativeModule["dependencyConfiguration"] - def cxxOnly = reactNativeModule["cxxOnly"] - - if (cxxOnly) { + def isPureCxxDependency = reactNativeModule["isPureCxxDependency"] + if (isPureCxxDependency) { return } @@ -254,12 +253,12 @@ class ReactNativeModules { }) } packageImports = packages - .findAll { !it.cxxOnly } + .findAll { !it.isPureCxxDependency } .collect { "// ${it.name}\n${interpolateDynamicValues(it.packageImportPath)}" }.join('\n') packageClassInstances = ",\n " + packages - .findAll { !it.cxxOnly } + .findAll { !it.isPureCxxDependency } .collect { interpolateDynamicValues(it.packageInstance) }.join(",\n ") @@ -481,6 +480,7 @@ class ReactNativeModules { reactNativeModuleConfig.put("cxxModuleCMakeListsModuleName", androidConfig["cxxModuleCMakeListsModuleName"]) reactNativeModuleConfig.put("cxxModuleCMakeListsPath", androidConfig["cxxModuleCMakeListsPath"]) reactNativeModuleConfig.put("cxxModuleHeaderName", androidConfig["cxxModuleHeaderName"]) + reactNativeModuleConfig.put("isPureCxxDependency", androidConfig["isPureCxxDependency"]) if (androidConfig["buildTypes"] && !androidConfig["buildTypes"].isEmpty()) { reactNativeModulesBuildVariants.put(nameCleansed, androidConfig["buildTypes"]) diff --git a/packages/cli-platform-android/src/config/index.ts b/packages/cli-platform-android/src/config/index.ts index d40b0c4dc..37e4f9345 100644 --- a/packages/cli-platform-android/src/config/index.ts +++ b/packages/cli-platform-android/src/config/index.ts @@ -135,29 +135,38 @@ export function dependencyConfig( ? path.join(sourceDir, userConfig.manifestPath) : findManifest(sourceDir); const buildGradlePath = findBuildGradle(sourceDir, true); - const cxxOnly = userConfig.cxxOnly || false; - - if (!cxxOnly && !manifestPath && !buildGradlePath) { + const isPureCxxDependency = + userConfig.cxxModuleCMakeListsModuleName != null && + userConfig.cxxModuleCMakeListsPath != null && + userConfig.cxxModuleHeaderName != null && + !manifestPath && + !buildGradlePath; + + if (!manifestPath && !buildGradlePath && !isPureCxxDependency) { return null; } - const packageName = - userConfig.packageName || getPackageName(manifestPath, buildGradlePath); - const packageClassName = findPackageClassName(sourceDir); + let packageImportPath = null, + packageInstance = null; - /** - * This module has no package to export - */ - if (!cxxOnly && !packageClassName) { - return null; - } + if (!isPureCxxDependency) { + const packageName = + userConfig.packageName || getPackageName(manifestPath, buildGradlePath); + const packageClassName = findPackageClassName(sourceDir); + + /** + * This module has no package to export + */ + if (!packageClassName) { + return null; + } - const packageImportPath = - userConfig.packageImportPath || - `import ${packageName}.${packageClassName};`; + packageImportPath = + userConfig.packageImportPath || + `import ${packageName}.${packageClassName};`; - const packageInstance = - userConfig.packageInstance || `new ${packageClassName}()`; + packageInstance = userConfig.packageInstance || `new ${packageClassName}()`; + } const buildTypes = userConfig.buildTypes || []; const dependencyConfiguration = userConfig.dependencyConfiguration; @@ -194,6 +203,6 @@ export function dependencyConfig( cxxModuleCMakeListsModuleName, cxxModuleCMakeListsPath, cxxModuleHeaderName, - cxxOnly, + isPureCxxDependency, }; } diff --git a/packages/cli-types/src/android.ts b/packages/cli-types/src/android.ts index 109a8142c..9b998ff00 100644 --- a/packages/cli-types/src/android.ts +++ b/packages/cli-types/src/android.ts @@ -25,8 +25,8 @@ export type AndroidProjectParams = { export type AndroidDependencyConfig = { sourceDir: string; - packageImportPath: string; - packageInstance: string; + packageImportPath: string | null; + packageInstance: string | null; dependencyConfiguration?: string; buildTypes: string[]; libraryName?: string | null; @@ -35,6 +35,7 @@ export type AndroidDependencyConfig = { cxxModuleCMakeListsModuleName?: string | null; cxxModuleCMakeListsPath?: string | null; cxxModuleHeaderName?: string | null; + isPureCxxDependency?: boolean; }; export type AndroidDependencyParams = { From 55ce9cc227ff4d9875efb8f96d452f0cd1c4874e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Gu=CC=88ner?= Date: Fri, 5 Jul 2024 13:17:06 +0300 Subject: [PATCH 7/7] docs: document pure cxx linking --- docs/autolinking.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/docs/autolinking.md b/docs/autolinking.md index 93e54bc56..6f4892da5 100644 --- a/docs/autolinking.md +++ b/docs/autolinking.md @@ -70,6 +70,26 @@ You’re already using Gradle, so Android support will work by default. On the iOS side, you will need to ensure you have a Podspec to the root of your repo. The `react-native-webview` Podspec is a good example of a [`package.json`](https://github.com/react-native-community/react-native-webview/blob/master/react-native-webview.podspec)-driven Podspec. Note that CocoaPods does not support having `/`s in the name of a dependency, so if you are using scoped packages - you may need to change the name for the Podspec. +### Pure C++ libraries + +Alternatively, if you have a pure C++ library and don't want to use Gradle, you can still use autolinking. You need to update your `react-native.config.js` to include the following: + +```js +// react-native.config.js +module.exports = { + dependency: { + platforms: { + android: { + sourceDir: 'path/to/your/c++/code', + cxxModuleCMakeListsPath: `relative/path/to/CMakeLists.txt`, // This is relative to the sourceDir. + cxxModuleCMakeListsModuleName: 'MyModule', // This is the name of the CMake target. + cxxModuleHeaderName: 'MyHeader', // CLI will include this header while linking. + }, + }, + }, +}; +``` + ## How can I customize how autolinking works for my package? A library can add a `react-native.config.js` configuration file, which will customize the defaults, example: