Skip to content

Commit 3bf4cd8

Browse files
committed
Fix static linking on iOS (#6614)
Fixes #6607. This is more of a workaround to fix issue with missing headers when building Reanimated with static linkage for iOS. I spent several hours on trying to make it right but it would work correctly only partially. I will post my findings here or internally later on and I hope to find a better solution sometime in the future. This workaround adds paths to `Common/cpp` and `apple/` directories to `HEADER_SEARCH_PATHS` – the preprocessor looks for headers in these locations. I can't use an absolute path (calculated in Ruby) because it would make the output setup-dependent and thus affect checksums in `Podfile.lock` which is unwanted as some apps check against checksum changes on CI. Tested on fabric-example app with `USE_FRAMEWORKS=static` and without. --- When installing pods in `fabric-example` with `cd ios && bundle install && bundle exec pod install`, the headers are visible in `ios/Pods` directory: ``` $ find . -name "REAUIKit.h" ./Pods/Headers/Public/RNReanimated/reanimated/apple/REAUIKit.h ./Pods/Headers/Private/RNReanimated/reanimated/apple/REAUIKit.h ``` However, after running `USE_FRAMEWORKS=static bundle exec pod install`, the headers are no longer present: ``` $ find . -name "REAUIKit.h" <no output> ``` Because of this, `#import <reanimated/apple/REAUIKit.h>` doesn't work, but when changed back to `#import <RNReanimated/REAUIKit.h>` it works fine (jump to file also works in Xcode). This made me wonder what's the location of `REAUIKit.h`. Obviously, the file is located in `react-native-reanimated/packages/react-native-reanimated/apple/reanimated/apple/REAUIKit.h` (using symlinks as a Development Pod), but the path is not included in header search paths. Hence, I decided to add `react-native-reanimated/packages/react-native-reanimated/apple/` to header search paths. However, this can't be done using absolute paths because they are likely to be machine-specific (e.g. containing the home directory name) which also affects checksum in Podfile.lock which is inconvenient since some setups assume the checksum to be stable (unless the version of the library is changed) due to security concerns. A better idea would be to take inspiration from react-native itself. I've noticed that `ReactCommon` has a similar feature – the headers are in nested subdirectories (e.g. `react/renderer/core/ShadowNode.h`) and the imports don't assume flat structure (e.g. it's `#import <react/renderer/core/ShadowNode.h>` instead of `#import <ReactCommon/ShadowNode.h>`). I remembered that frameworks create `FrameworkName.framework` directories. I finally found `RNReanimated.framework` in Xcode build folder that you can open from menu bar: <img width="312" alt="Screenshot 2024-10-18 at 18 04 45" src="https://github.com/user-attachments/assets/1db95b44-d21c-4e9a-a1d5-19674093094b"> Taking a quick look inside and comparing `ReactCommon` and `RNReanimated`, I've noticed that `RNReanimated.framework` doesn't contain any header files (except for umbrella header) while `ReactCommon` does: <img width="1178" alt="Screenshot 2024-10-18 at 18 05 33" src="https://github.com/user-attachments/assets/2633ab64-a85e-4a04-b2b3-97a11e576d6c"> When I commented out all 3 occurrences of `header_mappings_dir` in RNReanimated.podspec and run the Xcode build (first build lasts until the first error, if you hit the play button once again then, I assume it runs the remaining tasks), the headers were finally there but the directory structure was flattened: ```diff -ss.header_mappings_dir = "Common/cpp/reanimated" +#ss.header_mappings_dir = "Common/cpp/reanimated" ``` <img width="1178" alt="Screenshot 2024-10-18 at 18 14 52" src="https://github.com/user-attachments/assets/c25c1dfe-ce45-45ff-856f-be005907ffe2"> Then I tried passing an absolute path to appropriate directories to see if this would fix the structure: ```diff -ss.header_mappings_dir = "Common/cpp/reanimated" +ss.header_mappings_dir = "/Users/tomekzaw/RNOS/react-native-reanimated/packages/react-native-reanimated/Common/cpp" -sss.header_mappings_dir = "apple/reanimated" +sss.header_mappings_dir = "/Users/tomekzaw/RNOS/react-native-reanimated/packages/react-native-reanimated/ -ss.header_mappings_dir = "Common/cpp/worklets" +ss.header_mappings_dir = "/Users/tomekzaw/RNOS/react-native-reanimated/packages/react-native-reanimated/Common/cpp" ``` Then I investigated `ReactCommon.podspec` inside react-native repository and found several interesting lines of code: ```rb s.header_dir = "ReactCommon" # Use global header_dir for all subspecs for use_frameworks! compatibility ``` It looks like `header_dir` must contain `header_mappings_dir` for the latter to work properly when `use_frameworks!` is enabled. ```rb if ENV['USE_FRAMEWORKS'] s.header_mappings_dir = './' end ``` For some reason, `s.header_mappings_dir` is set to the current directory only if `USE_FRAMEWORKS` is set. ... ``` HEADER_SEARCH_PATHS = ( "$(inherited)", "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers", "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon/ReactCommon.framework/Headers/react/nativemodule/core", "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers", "${PODS_CONFIGURATION_BUILD_DIR}/ReactCommon-Samples/ReactCommon_Samples.framework/Headers/platform/ios", "${PODS_CONFIGURATION_BUILD_DIR}/React-Fabric/React_Fabric.framework/Headers/react/renderer/components/view/platform/cxx", "${PODS_CONFIGURATION_BUILD_DIR}/React-NativeModulesApple/React_NativeModulesApple.framework/Headers", "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers", "${PODS_CONFIGURATION_BUILD_DIR}/React-graphics/React_graphics.framework/Headers/react/renderer/graphics/platform/ios", ); ```
1 parent 969bad6 commit 3bf4cd8

File tree

6 files changed

+20
-5
lines changed

6 files changed

+20
-5
lines changed

apps/fabric-example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2229,7 +2229,7 @@ SPEC CHECKSUMS:
22292229
RNCPicker: d051e0647af8b2ad01a3d39a6b5dd9b7c0ccc166
22302230
RNFlashList: 6f169ad83e52579b7754cbbcec1b004c27d82c93
22312231
RNGestureHandler: c374c750a0a9bacd95f5c740d146ab9428549d6b
2232-
RNReanimated: 3eda8373a520a38427b68054026b5a8d40d42cfe
2232+
RNReanimated: 648a88c56c6881c93255e0eab431859b346e0b42
22332233
RNScreens: de6e57426ba0e6cbc3fb5b4f496e7f08cb2773c2
22342234
RNSVG: 08750404f92a36162a92522cc77dee437be1d257
22352235
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748

apps/macos-example/macos/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1270,7 +1270,7 @@ SPEC CHECKSUMS:
12701270
RNCAsyncStorage: ec53e44dc3e75b44aa2a9f37618a49c3bc080a7a
12711271
RNCPicker: 0173dedc74776227ec6dcc61bb85cd9f07bbb2ac
12721272
RNGestureHandler: bb81850add626ddd265294323310fec6e861c96b
1273-
RNReanimated: 857daa16ccc117c0491ad6950c9579cb436295df
1273+
RNReanimated: 8e5c163219a6444172d851df401a1e86721635f0
12741274
RNSVG: 01eb8d8a0e2289ec3ecc9626ce920e00d2174992
12751275
SocketRocket: f6c6249082c011e6de2de60ed641ef8bbe0cfac9
12761276
Yoga: 329461de6a23b9e0c108d197fd0f6e87c8c8ecf2

apps/paper-example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2019,7 +2019,7 @@ SPEC CHECKSUMS:
20192019
RNCPicker: 0173dedc74776227ec6dcc61bb85cd9f07bbb2ac
20202020
RNFlashList: 115dd44377580761bff386a0caebf165424cf16f
20212021
RNGestureHandler: 6dfe7692a191ee224748964127114edf057a1475
2022-
RNReanimated: 3ffdf9d59cc891c4cbd29b5182ed845aea6ec187
2022+
RNReanimated: ac6bc4e337cfc694308e094f1d73487c21832bc8
20232023
RNScreens: 19719a9c326e925498ac3b2d35c4e50fe87afc06
20242024
RNSVG: 01eb8d8a0e2289ec3ecc9626ce920e00d2174992
20252025
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748

apps/tvos-example/ios/Podfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1267,7 +1267,7 @@ SPEC CHECKSUMS:
12671267
React-runtimescheduler: 20b2202e3396589a71069d12ae9f328949c7c7b8
12681268
React-utils: 0307d396f233e47a167b5aaf045b0e4e1dc19d74
12691269
ReactCommon: 17891ca337bfa5a7263649b09f27a8c664537bf2
1270-
RNReanimated: fe28ce0f9e7a41852e6b0e0b5ac557236ae39db9
1270+
RNReanimated: 0552e8e7058dfe736c41ce163c0cd66eaf0ca906
12711271
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
12721272
Yoga: e7f2a2256464d4ef7b3825d216bd22aac3b449c1
12731273

packages/react-native-reanimated/RNReanimated.podspec

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,17 @@ Pod::Spec.new do |s|
116116
}
117117
s.compiler_flags = "#{folly_compiler_flags} #{boost_compiler_flags}"
118118
s.xcconfig = {
119-
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\" \"$(PODS_ROOT)/boost-for-react-native\" \"$(PODS_ROOT)/glog\" \"$(PODS_ROOT)/RCT-Folly\" \"$(PODS_ROOT)/Headers/Public/React-hermes\" \"$(PODS_ROOT)/Headers/Public/hermes-engine\" \"$(PODS_ROOT)/#{$config[:react_native_common_dir]}\"",
119+
"HEADER_SEARCH_PATHS" => [
120+
'"$(PODS_ROOT)/boost"',
121+
'"$(PODS_ROOT)/boost-for-react-native"',
122+
'"$(PODS_ROOT)/glog"',
123+
'"$(PODS_ROOT)/RCT-Folly"',
124+
'"$(PODS_ROOT)/Headers/Public/React-hermes"',
125+
'"$(PODS_ROOT)/Headers/Public/hermes-engine"',
126+
"\"$(PODS_ROOT)/#{$config[:react_native_common_dir]}\"",
127+
"\"$(PODS_ROOT)/#{$config[:react_native_reanimated_dir_from_pods_root]}/apple\"",
128+
"\"$(PODS_ROOT)/#{$config[:react_native_reanimated_dir_from_pods_root]}/Common/cpp\"",
129+
].join(' '),
120130
"OTHER_CFLAGS" => "$(inherited) #{folly_flags} #{fabric_flags} #{example_flag} #{version_flag} #{debug_flag} #{compilation_metadata_generation_flag}"
121131
}
122132
s.requires_arc = true

packages/react-native-reanimated/scripts/reanimated_utils.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def find_config()
1414
:is_tvos_target => nil,
1515
:react_native_node_modules_dir => nil,
1616
:react_native_common_dir => nil,
17+
:react_native_reanimated_dir_from_pods_root => nil,
1718
}
1819

1920
react_native_node_modules_dir = File.join(File.dirname(`cd "#{Pod::Config.instance.installation_root.to_s}" && node --print "require.resolve('react-native/package.json')"`), '..')
@@ -43,6 +44,10 @@ def find_config()
4344
react_native_common_dir_relative = Pathname.new(react_native_common_dir_absolute).relative_path_from(pods_root).to_s
4445
result[:react_native_common_dir] = react_native_common_dir_relative
4546

47+
react_native_reanimated_dir_absolute = File.join(__dir__, '..')
48+
react_native_reanimated_dir_relative = Pathname.new(react_native_reanimated_dir_absolute).relative_path_from(pods_root).to_s
49+
result[:react_native_reanimated_dir_from_pods_root] = react_native_reanimated_dir_relative
50+
4651
return result
4752
end
4853

0 commit comments

Comments
 (0)