Skip to content

Commit 2dbd56b

Browse files
committed
[ios][precompile] add support for clang virtual file system
To solve our problem with header files from the React.XCFramework not being consumable due to the legacy Cocoapods headers, we used to point all header search / resolving into the Pods/Headers folder when building even with the framework installed. This is a problem since an xcframework expects a modular header structure that can be consumed from within the headers folder of the framework. The headers are used for both Objective-c compiling and for creating clang modules that can be consumed by Swift in our setup. This commit fixes the above issues and makes a modular clang virtual file system from the header files we distribute. This vfs-overlay file will then be used by the `rncore.rb` script when installing the 'React-Core-prebuilt' pod and map the header files requested in the source code to the actual location on disk where the React.xcframework headers are installed. Here are the changes: - Added vfs.js with types for creating clang virtual file system overlays - Added resolving the paths in the vfs file to the actual install path - Added installing the vfs overlay with the switch `-ivfsoverlay <path>` to compiler settings for both obj-c and swift on pod installation - Add vfs targets to the app target on post install
1 parent a902614 commit 2dbd56b

5 files changed

Lines changed: 420 additions & 14 deletions

File tree

packages/react-native/scripts/cocoapods/rncore.rb

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,26 @@
1313
### building ReactNativeCore from source (then this function does nothing).
1414
def add_rncore_dependency(s)
1515
if !ReactNativeCoreUtils.build_rncore_from_source()
16+
# Add the dependency
17+
s.dependency "React-Core-prebuilt"
18+
1619
current_pod_target_xcconfig = s.to_hash["pod_target_xcconfig"] || {}
1720
current_pod_target_xcconfig = current_pod_target_xcconfig.to_h unless current_pod_target_xcconfig.is_a?(Hash)
18-
s.dependency "React-Core-prebuilt"
19-
current_pod_target_xcconfig["HEADER_SEARCH_PATHS"] ||= [] << "$(PODS_ROOT)/React-Core-prebuilt/React.xcframework/Headers"
21+
22+
# Add VFS overlay flags for both Objective-C and Swift
23+
# The VFS overlay file is pre-resolved at pod install time for each platform slice.
24+
# We reference it directly in the xcframework using the React-VFS.yaml file that
25+
# is written to the React-Core-prebuilt folder during setup_vfs_overlay.
26+
vfs_overlay_flag = "-ivfsoverlay $(PODS_ROOT)/React-Core-prebuilt/React-VFS.yaml"
27+
current_pod_target_xcconfig["OTHER_CFLAGS"] ||= "$(inherited)"
28+
current_pod_target_xcconfig["OTHER_CFLAGS"] += " #{vfs_overlay_flag}"
29+
current_pod_target_xcconfig["OTHER_CPLUSPLUSFLAGS"] ||= "$(inherited)"
30+
current_pod_target_xcconfig["OTHER_CPLUSPLUSFLAGS"] += " #{vfs_overlay_flag}"
31+
# For Swift, we need to use -Xcc to pass flags to the underlying Clang compiler
32+
# Both the flag and its argument need separate -Xcc prefixes
33+
current_pod_target_xcconfig["OTHER_SWIFT_FLAGS"] ||= "$(inherited)"
34+
current_pod_target_xcconfig["OTHER_SWIFT_FLAGS"] += " -Xcc -ivfsoverlay -Xcc $(PODS_ROOT)/React-Core-prebuilt/React-VFS.yaml"
35+
2036
s.pod_target_xcconfig = current_pod_target_xcconfig
2137
end
2238
end
@@ -450,4 +466,79 @@ def self.get_nightly_npm_version()
450466
return latest_nightly
451467
end
452468

469+
# Processes the VFS overlay file from the React.xcframework to resolve the ${ROOT_PATH} placeholder.
470+
# This method should be called from react_native_post_install after pod install completes.
471+
#
472+
# The VFS overlay file maps header import paths to their actual locations within the xcframework.
473+
# Since the xcframework contains platform-specific slices, we generate a resolved VFS file for each
474+
# slice and also create a default VFS file that can be used immediately (before script phases run).
475+
def self.process_vfs_overlay()
476+
return if @@build_from_source
477+
478+
prebuilt_path = File.join(Pod::Config.instance.project_pods_root, "React-Core-prebuilt")
479+
xcframework_path = File.join(prebuilt_path, "React.xcframework")
480+
vfs_template_path = File.join(xcframework_path, "React-VFS-template.yaml")
481+
482+
unless File.exist?(vfs_template_path)
483+
rncore_log("VFS overlay template not found at #{vfs_template_path}", :error)
484+
exit 1
485+
end
486+
487+
rncore_log("Processing VFS overlay file...")
488+
489+
# Read the template content
490+
vfs_template_content = File.read(vfs_template_path)
491+
492+
# Write the VFS file - use the top-level xcframework path
493+
# so that ${ROOT_PATH}/Headers points to the xcframework's Headers folder
494+
resolved_vfs_content = vfs_template_content.gsub('${ROOT_PATH}', xcframework_path)
495+
resolved_vfs_path = File.join(prebuilt_path, "React-VFS.yaml")
496+
File.write(resolved_vfs_path, resolved_vfs_content)
497+
rncore_log(" Created VFS overlay at #{resolved_vfs_path}")
498+
499+
rncore_log("VFS overlay setup complete")
500+
end
501+
502+
# Configures the xcconfig files for aggregate (main app) targets to enable VFS overlay for React Native Core.
503+
# This is needed because the main app target does not go through podspec processing,
504+
# so it won't get the VFS overlay flags from add_rncore_dependency.
505+
#
506+
# Parameters:
507+
# - installer: The CocoaPods installer object
508+
def self.configure_aggregate_xcconfig(installer)
509+
return if @@build_from_source
510+
511+
prebuilt_path = File.join(Pod::Config.instance.project_pods_root, "React-Core-prebuilt")
512+
vfs_overlay_path = File.join(prebuilt_path, "React-VFS.yaml")
513+
514+
unless File.exist?(vfs_overlay_path)
515+
rncore_log("VFS overlay not found at #{vfs_overlay_path}, skipping prebuilt xcconfig configuration", :error)
516+
exit 1
517+
end
518+
519+
rncore_log("Configuring xcconfig for prebuilt React Native Core...")
520+
521+
vfs_overlay_flag = " -ivfsoverlay \"#{vfs_overlay_path}\""
522+
swift_vfs_overlay_flag = " -Xcc -ivfsoverlay -Xcc \"#{vfs_overlay_path}\""
523+
524+
# Add flags to aggregate target xcconfigs (these are used by the main app target)
525+
installer.aggregate_targets.each do |aggregate_target|
526+
aggregate_target.xcconfigs.each do |config_name, config_file|
527+
# Add VFS overlay to compiler flags (C/C++ and Swift)
528+
ReactNativePodsUtils.add_flag_to_map_with_inheritance(config_file.attributes, "OTHER_CFLAGS", vfs_overlay_flag)
529+
ReactNativePodsUtils.add_flag_to_map_with_inheritance(config_file.attributes, "OTHER_CPLUSPLUSFLAGS", vfs_overlay_flag)
530+
531+
# For Swift, we need to use -Xcc to pass the flag to the underlying Clang compiler
532+
ReactNativePodsUtils.add_flag_to_map_with_inheritance(config_file.attributes, "OTHER_SWIFT_FLAGS", swift_vfs_overlay_flag)
533+
534+
# Suppress incomplete umbrella warnings for the prebuilt frameworks (it is expected, as our umbrella headers do not include all headers)
535+
ReactNativePodsUtils.add_flag_to_map_with_inheritance(config_file.attributes, "OTHER_SWIFT_FLAGS", " -Xcc -Wno-incomplete-umbrella")
536+
537+
xcconfig_path = aggregate_target.xcconfig_path(config_name)
538+
config_file.save_as(xcconfig_path)
539+
end
540+
end
541+
542+
rncore_log("Prebuilt xcconfig configuration complete")
543+
end
453544
end

packages/react-native/scripts/ios-prebuild/types.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@ export type Destination =
2222
export type BuildFlavor = 'Debug' | 'Release';
2323
2424
export type MavenSubGroup = 'hermes' | 'react';
25+
26+
export type VFSEntry = {
27+
name: string,
28+
type: 'file' | 'directory',
29+
'external-contents'?: string,
30+
contents?: Array<VFSEntry>,
31+
};
32+
33+
export type VFSOverlay = {
34+
version: number,
35+
'case-sensitive': boolean,
36+
roots: Array<VFSEntry>,
37+
};
38+
39+
export type HeaderMapping = {
40+
key: string,
41+
path: string,
42+
};
2543
*/
2644

2745
module.exports = {};

0 commit comments

Comments
 (0)