From 3737c58322b50582baff6b40a325305f18ddd429 Mon Sep 17 00:00:00 2001 From: Nisarga Date: Tue, 3 Feb 2026 00:30:59 +0530 Subject: [PATCH 1/4] Fix init-windows C++ codegen include to use codegenConfig.name --- vnext/templates/cpp-lib/template.config.js | 129 ++++-------------- vnext/templates/cpp-lib/windows/MyLib/MyLib.h | 31 ++--- 2 files changed, 38 insertions(+), 122 deletions(-) diff --git a/vnext/templates/cpp-lib/template.config.js b/vnext/templates/cpp-lib/template.config.js index a7a44e113b3..8b877894905 100644 --- a/vnext/templates/cpp-lib/template.config.js +++ b/vnext/templates/cpp-lib/template.config.js @@ -10,9 +10,6 @@ const crypto = require('crypto'); const existsSync = require('fs').existsSync; const path = require('path'); const username = require('username'); -const util = require('util'); - -const glob = util.promisify(require('glob')); const templateUtils = require('../templateUtils'); @@ -62,9 +59,6 @@ async function preInstall(config = {}, options = {}) { const {exExists, exConfig, exOptions} = resolveArgs(config, options); if (exExists) { - if (exOptions?.logging) { - console.log('Running cpp-app template preInstall() for example...'); - } await exampleTemplateConfig.preInstall(exConfig, exOptions); } } @@ -91,27 +85,22 @@ async function getFileMappings(config = {}, options = {}) { libConfig?.project?.windows?.projects[0]?.projectGuid ?.replace('{', '') .replace('}', '') ?? crypto.randomUUID(); - const currentUser = username.sync(); // Gets the current username depending on the platform. - - // Check for existing codegen spec files - const codegenPath = path.join(projectRoot, 'windows', projectName, 'codegen'); - let existingSpecFiles = []; - let firstSpecName = null; - if (existsSync(codegenPath)) { - try { - const specFiles = await glob('*Spec.g.h', {cwd: codegenPath}); - existingSpecFiles = specFiles; - if (specFiles.length > 0) { - // Extract the spec name from filename (e.g., "NativeMyModuleSpec.g.h" -> "MyModuleSpec") - const firstFile = specFiles[0]; - firstSpecName = firstFile.replace(/^Native/, '').replace(/\.g\.h$/, ''); - } - } catch (e) { - // If we can't read the codegen directory, continue with empty array - } + const currentUser = username.sync(); + + const pkgJsonPath = path.join(projectRoot, 'package.json'); + if (!existsSync(pkgJsonPath)) { + throw new Error('package.json not found in user library root'); + } + + const pkgJson = require(pkgJsonPath); + + if (!pkgJson.codegenConfig?.name) { + throw new Error( + 'codegenConfig.name is required in package.json for C++ libraries', + ); } - const cppNugetPackages = []; + const codegenName = pkgJson.codegenConfig.name; const replacements = { useMustache: true, @@ -119,16 +108,11 @@ async function getFileMappings(config = {}, options = {}) { name: projectName, pascalName: templateUtils.pascalCase(projectName), - namespace: namespace, - namespaceCpp: namespaceCpp, + namespace, + namespaceCpp, + codegenName, - // Codegen spec files information - existingSpecFiles: existingSpecFiles, - hasExistingSpecFiles: existingSpecFiles.length > 0, - firstSpecFile: existingSpecFiles.length > 0 ? existingSpecFiles[0] : null, - firstSpecName: firstSpecName, - - rnwVersion: rnwVersion, + rnwVersion, rnwPathFromProjectRoot: path .relative(projectRoot, rnwPath) .replace(/\//g, '\\'), @@ -140,56 +124,32 @@ async function getFileMappings(config = {}, options = {}) { projectGuidUpper: `{${projectGuid.toUpperCase()}}`, currentUser, - devMode, + useNuGets: !devMode,// default is to use published NuGets except in devMode, change to true here if you want to test devMode and nugets simultaneously + addReactNativePublicAdoFeed: true || isCanary,// Temporary true for all new projects until code-signing is restored, see issue #14030 - useNuGets: !devMode, // default is to use published NuGets except in devMode, change to true here if you want to test devMode and nugets simultaneously - addReactNativePublicAdoFeed: true || isCanary, // Temporary true for all new projects until code-signing is restored, see issue #14030 - - cppNugetPackages, + cppNugetPackages: [], }; let fileMappings = []; - const templateFiles = await glob('**/*', { - cwd: __dirname, - ignore: 'template.config.js', - nodir: true, - }); + const templateFiles = templateUtils.getTemplateFiles(__dirname); for (const file of templateFiles) { const fileMapping = { - from: path.resolve(__dirname, path.normalize(file)), - to: path.normalize(file), + from: file.from, + to: file.to.replace(/MyLib/g, projectName), replacements, }; - + // Don't copy example files if there is no example in the destination if (!exExists && fileMapping.to.startsWith('example')) { continue; } - // Perform simple file renames - const fileName = path.basename(fileMapping.to); - switch (fileName) { - case '_gitignore': - fileMapping.to = path.join(path.dirname(fileMapping.to), '.gitignore'); - break; - case 'NuGet_Config': - fileMapping.to = path.join( - path.dirname(fileMapping.to), - 'NuGet.config', - ); - break; - } - - // Rename files with MyLib in the name - fileMapping.to = fileMapping.to.replace(/MyLib/g, projectName); - fileMappings.push(fileMapping); } - // Add the file mappings from the cpp-app template for the example app if (exExists) { const exampleFileMappings = await exampleTemplateConfig.getFileMappings( exConfig, @@ -198,11 +158,7 @@ async function getFileMappings(config = {}, options = {}) { for (const exFileMap of exampleFileMappings) { exFileMap.to = path.join('example', exFileMap.to); - - // Only add the file map if there isn't a mapping from this cpp-lib template - if (fileMappings.filter(fm => fm.to === exFileMap.to).length === 0) { - fileMappings.push(exFileMap); - } + fileMappings.push(exFileMap); } } @@ -210,15 +166,13 @@ async function getFileMappings(config = {}, options = {}) { } async function postInstall(config = {}, options = {}) { - const {libConfig, libOptions, exExists, exConfig, exOptions} = resolveArgs( - config, - options, - ); + const {libConfig, libOptions} = resolveArgs(config, options); const projectName = libConfig?.project?.windows?.projects[0]?.projectName ?? libOptions?.name ?? 'MyLib'; + const namespace = libOptions?.namespace ?? projectName; const namespaceCpp = namespace.replace(/\./g, '::'); @@ -229,7 +183,7 @@ async function postInstall(config = {}, options = {}) { { codegenConfig: { windows: { - namespace: namespaceCpp + 'Codegen', + namespace: `${namespaceCpp}Codegen`, outputDirectory: `windows/${projectName}/codegen`, separateDataTypes: true, }, @@ -238,31 +192,6 @@ async function postInstall(config = {}, options = {}) { true, // save options from command true, // if a "files" property exists, make sure "windows" is included ); - - if (exExists) { - const {rnwVersion} = templateUtils.getRnwInfo(exConfig, exOptions); - - // Update example package.json with new scripts and dependencies - await templateUtils.updateProjectPackageJson(exConfig, exOptions, { - scripts: { - windows: 'npx @react-native-community/cli run-windows', - 'test:windows': 'jest --config jest.config.windows.js', - }, - dependencies: { - 'react-native-windows': rnwVersion, - }, - devDependencies: { - '@rnx-kit/jest-preset': '^0.1.17', - }, - }); - - // Install recently added dependencies - await templateUtils.runNpmInstall(libConfig, libOptions); - - console.log( - '\nRun the example app on Windows:\n\n > yarn example windows\n', - ); - } } module.exports = { diff --git a/vnext/templates/cpp-lib/windows/MyLib/MyLib.h b/vnext/templates/cpp-lib/windows/MyLib/MyLib.h index 21b7bb402ef..78930441922 100644 --- a/vnext/templates/cpp-lib/windows/MyLib/MyLib.h +++ b/vnext/templates/cpp-lib/windows/MyLib/MyLib.h @@ -3,20 +3,14 @@ #include "pch.h" #include "resource.h" -#if __has_include("codegen/Native{{ pascalName }}DataTypes.g.h") - #include "codegen/Native{{ pascalName }}DataTypes.g.h" +#if __has_include("codegen/Native{{ codegenName }}DataTypes.g.h") + #include "codegen/Native{{ codegenName }}DataTypes.g.h" #endif + // Note: The following lines use Mustache template syntax which will be processed during -// project generation to produce standard C++ code. If existing codegen spec files are found, -// use the actual filename; otherwise use conditional includes. -{{#hasExistingSpecFiles}} -#include "codegen/{{ firstSpecFile }}" -{{/hasExistingSpecFiles}} -{{^hasExistingSpecFiles}} -#if __has_include("codegen/Native{{ pascalName }}Spec.g.h") - #include "codegen/Native{{ pascalName }}Spec.g.h" -#endif -{{/hasExistingSpecFiles}} +// project generation to produce standard C++ code. The spec filename is derived from +// `codegenConfig.name` in the user library's package.json, which is the single source of truth. +#include "codegen/Native{{ codegenName }}Spec.g.h" #include "NativeModules.h" @@ -29,15 +23,8 @@ REACT_MODULE({{ pascalName }}) struct {{ pascalName }} { // Note: Mustache template syntax below will be processed during project generation - // to produce standard C++ code based on detected codegen files. -{{#hasExistingSpecFiles}} - using ModuleSpec = {{ namespaceCpp }}Codegen::{{ firstSpecName }}; -{{/hasExistingSpecFiles}} -{{^hasExistingSpecFiles}} -#if __has_include("codegen/Native{{ pascalName }}Spec.g.h") - using ModuleSpec = {{ namespaceCpp }}Codegen::{{ pascalName }}Spec; -#endif -{{/hasExistingSpecFiles}} + // to produce standard C++ code based on the codegenConfig.name value. + using ModuleSpec = {{ namespaceCpp }}Codegen::{{ codegenName }}Spec; REACT_INIT(Initialize) void Initialize(React::ReactContext const &reactContext) noexcept; @@ -49,4 +36,4 @@ struct {{ pascalName }} React::ReactContext m_context; }; -} // namespace winrt::{{ namespaceCpp }} \ No newline at end of file +} // namespace winrt::{{ namespaceCpp }} From ad8dde7f19f4435cedb4ff6fc98d5799d6c0d01b Mon Sep 17 00:00:00 2001 From: Nisarga Date: Wed, 4 Feb 2026 09:29:27 +0530 Subject: [PATCH 2/4] Change files --- ...ative-windows-cfdd68ec-b1ee-45a8-8c1e-e8f2b1b0f5c5.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/react-native-windows-cfdd68ec-b1ee-45a8-8c1e-e8f2b1b0f5c5.json diff --git a/change/react-native-windows-cfdd68ec-b1ee-45a8-8c1e-e8f2b1b0f5c5.json b/change/react-native-windows-cfdd68ec-b1ee-45a8-8c1e-e8f2b1b0f5c5.json new file mode 100644 index 00000000000..bd5bb87284f --- /dev/null +++ b/change/react-native-windows-cfdd68ec-b1ee-45a8-8c1e-e8f2b1b0f5c5.json @@ -0,0 +1,7 @@ +{ + "type": "none", + "comment": "Fix init-windows C++ codegen include to use codegenConfig.name", + "packageName": "react-native-windows", + "email": "nisargakshetty@gmail.com", + "dependentChangeType": "none" +} From 4c555fc36d3c10fd279fc118dd158e7f51d0d3d8 Mon Sep 17 00:00:00 2001 From: Nisarga Date: Wed, 4 Feb 2026 09:32:58 +0530 Subject: [PATCH 3/4] Change files --- ...eact-native-windows-9f6d4d88-2c94-44e8-8b2d-30812ad99472.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename change/{react-native-windows-cfdd68ec-b1ee-45a8-8c1e-e8f2b1b0f5c5.json => react-native-windows-9f6d4d88-2c94-44e8-8b2d-30812ad99472.json} (100%) diff --git a/change/react-native-windows-cfdd68ec-b1ee-45a8-8c1e-e8f2b1b0f5c5.json b/change/react-native-windows-9f6d4d88-2c94-44e8-8b2d-30812ad99472.json similarity index 100% rename from change/react-native-windows-cfdd68ec-b1ee-45a8-8c1e-e8f2b1b0f5c5.json rename to change/react-native-windows-9f6d4d88-2c94-44e8-8b2d-30812ad99472.json From b1dd612b4c222d80c28b41e884da50a31884d07f Mon Sep 17 00:00:00 2001 From: vineethkuttan <66076509+vineethkuttan@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:30:36 +0530 Subject: [PATCH 4/4] format changes --- vnext/templates/cpp-lib/template.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vnext/templates/cpp-lib/template.config.js b/vnext/templates/cpp-lib/template.config.js index 8b877894905..117f57b58df 100644 --- a/vnext/templates/cpp-lib/template.config.js +++ b/vnext/templates/cpp-lib/template.config.js @@ -125,8 +125,8 @@ async function getFileMappings(config = {}, options = {}) { currentUser, devMode, - useNuGets: !devMode,// default is to use published NuGets except in devMode, change to true here if you want to test devMode and nugets simultaneously - addReactNativePublicAdoFeed: true || isCanary,// Temporary true for all new projects until code-signing is restored, see issue #14030 + useNuGets: !devMode, // default is to use published NuGets except in devMode, change to true here if you want to test devMode and nugets simultaneously + addReactNativePublicAdoFeed: true || isCanary, // Temporary true for all new projects until code-signing is restored, see issue #14030 cppNugetPackages: [], }; @@ -141,7 +141,7 @@ async function getFileMappings(config = {}, options = {}) { to: file.to.replace(/MyLib/g, projectName), replacements, }; - + // Don't copy example files if there is no example in the destination if (!exExists && fileMapping.to.startsWith('example')) { continue;