Description
scripts/codegen/generate-artifacts-executor/generateReactCodegenPodspec.js → getInputFiles() builds the Generate Specs script phase input_files from a find over the app's codegenConfig.jsSrcsDir. When that directory contains no Native*.{js,ts} / *NativeComponent.{js,ts} files, execSync(find …) returns an empty string, ''.trim().split('\n') is [''], and the single empty path is mapped to:
'input_files' => ["${PODS_ROOT}/.."]
i.e. the whole ios/ directory. Xcode then sees that the Generate Specs phase of ReactCodegen depends on files produced by other targets' script phases in that directory (in an Expo project: the app target's [Expo] Configure project phase, which writes Pods/Target Support Files/…/ExpoModulesProvider.swift) and fails:
error: Cycle in dependencies between targets 'Callingx' and 'TurnoHosts'; building could produce unreliable results.
Cycle path: Callingx → ReactCodegen → TurnoHosts → Callingx
→ Target 'Callingx' has an explicit dependency on Target 'ReactCodegen'
○ That command depends on command in Target 'ReactCodegen': script phase “[CP-User] Generate Specs”
→ That command depends on command in Target 'TurnoHosts': script phase “[Expo] Configure project”
An app-level codegenConfig with no spec files is a legitimate setup: it is the documented way to declare ios.modulesConformingToProtocol (e.g. an RCTImageURLLoader) from the app when a dependency cannot.
Steps to reproduce
- In an app's package.json add
"codegenConfig": { "name": "AppSpecs", "type": "modules", "jsSrcsDir": "src/config", "ios": { "modulesConformingToProtocol": { "RCTImageURLLoader": ["SomeLoader"] } } }
where src/config exists but has no spec files.
pod install
- Inspect
ios/build/generated/ios/ReactCodegen/ReactCodegen.podspec → 'input_files' => ["${PODS_ROOT}/.."].
- Build in Xcode → dependency cycle error above (seen with Expo SDK 57 projects; any other script phase writing under
ios/ triggers it too).
Fix
Filter the empty entry:
const list = String(execSync(findCommand))
.trim()
.split('\n')
+ .filter(Boolean)
.sort()
With that, input_files is [] (same as projects without an app codegenConfig) and the build succeeds.
React Native Version
0.86.3
Affected Platforms
Build - MacOS, Runtime - iOS
Description
scripts/codegen/generate-artifacts-executor/generateReactCodegenPodspec.js→getInputFiles()builds theGenerate Specsscript phaseinput_filesfrom afindover the app'scodegenConfig.jsSrcsDir. When that directory contains noNative*.{js,ts}/*NativeComponent.{js,ts}files,execSync(find …)returns an empty string,''.trim().split('\n')is[''], and the single empty path is mapped to:i.e. the whole
ios/directory. Xcode then sees that theGenerate Specsphase ofReactCodegendepends on files produced by other targets' script phases in that directory (in an Expo project: the app target's[Expo] Configure projectphase, which writesPods/Target Support Files/…/ExpoModulesProvider.swift) and fails:An app-level
codegenConfigwith no spec files is a legitimate setup: it is the documented way to declareios.modulesConformingToProtocol(e.g. anRCTImageURLLoader) from the app when a dependency cannot.Steps to reproduce
src/configexists but has no spec files.pod installios/build/generated/ios/ReactCodegen/ReactCodegen.podspec→'input_files' => ["${PODS_ROOT}/.."].ios/triggers it too).Fix
Filter the empty entry:
const list = String(execSync(findCommand)) .trim() .split('\n') + .filter(Boolean) .sort()With that,
input_filesis[](same as projects without an app codegenConfig) and the build succeeds.React Native Version
0.86.3
Affected Platforms
Build - MacOS, Runtime - iOS