react-native: Fail to build using Xcode 12 Beta 4

Description

When I try to build a project with Xcode 12 Beta 4 to test iOS14, I got a plenty of Undefined symbols for architecture x86_64. Every time I build the app, the list of errors is changed. Native libraries fail to recognize base React classes.

React Native version:

info Fetching system and libraries information...
(node:16978) Warning: Accessing non-existent property 'padLevels' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
System:
    OS: macOS 10.15.6
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
    Memory: 558.54 MB / 16.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 14.3.0 - /usr/local/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.14.4 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.3 - /Users/laigorols/.rbenv/shims/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 14.0, DriverKit 20.0, macOS 11.0, tvOS 14.0, watchOS 7.0
    Android SDK: Not Found
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6626763
    Xcode: 12.0/12A8179i - /usr/bin/xcodebuild
  Languages:
    Java: 12.0.1 - /usr/bin/javac
    Python: 2.7.16 - /Users/laigorols/.pyenv/shims/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: 16.13.1 => 16.13.1
    react-native: 0.63.2 => 0.63.2
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

Provide a detailed list of steps that reproduce the issue.

  1. Add native dependencies to package.json;
  2. Install dependencies using yarn install;
  3. Run pod install in ios folder to auto link native dependencies;
  4. Try to run application in simulator using Xcode;

Expected Results

Application is successfully installed and executed in simulator.

Snack, code example, screenshot, or link to a repository:

Xcode error log: Build Xcode12ReactNativeSample_2020-08-12T17-06-23.txt

Github repository with sample: https://github.com/igoriols/xcode12reactnativesample

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 8
  • Comments: 52 (26 by maintainers)

Commits related to this issue

Most upvoted comments

Hi all šŸ‘‹

Unfortunately I only just became aware of this ticket, so my apologies for the delay but thanks for the workarounds and the patience! šŸ™

I tried the reproduction kindly provided by @igoriols and was able to determine the problem. The issue is that all the podspecs of these libraries that fail to link depend on the React pod, which is in fact really only an umbrella dependency for pure JS applications to depend on, whereas the native APIs that these libraries rely on actually reside in the React-Core pod.

This means that they technically were always incorrect—conceptually one should always explicitly depend on the lib that provides the APIs you rely on, rather than relying on transitive dependencies—but it seems like in previous Xcode versions the build system worked differently and having the transitive dependencies around just happened to work šŸ¤·ā€ā™‚ļø

The correct fix going forward is for all these libs to update their dependency from React to React-Core:

-  s.dependency 'React'
+  s.dependency 'React-Core'

To unblock yourself you could use something like patch-package to temporarily hot-patch the podspecs you need, but it would be really great for the longer term and the community if you could also submit that change upstream to the respective library šŸ™ (See for example this react-native-webview pull-request.)

find ./node_modules -type f -name '*.podspec' | xargs sed -i.sed -e "s%'%\"%g"
find ./node_modules -type f -name '*.podspec' | xargs sed -i.sed -e 's%s.dependency[\t ]*"React"%s.dependency "React-Core"%g'

Hi, my Xcode got updated to 12 today šŸ˜ž

How do you know what the affected targets are?

Update: issue still exists with Xcode 12 Beta 5. Also, upgrading Cocoapods to 1.10 beta doesn’t help.

The issue seems to be related with React Native’s Auto-linking. So building a React Native only project won’t be affected, but if you bring in some libraries like react-native-safe-area or react-native-webview , the compiling fails.

After comparing the affected targets with other React Native targets, I found that React.framework was missing in the Link Binary With Libraries build phase for those auto-linked pods.

So I came up with a Workaround: Add a post_install in Podfile to manually add the React.framework back. (Update: Please notice that I used :generate_multiple_pod_projects => true in my Podfile.)

post_install do |installer|
  #Workaround for Xcode 12 and Auto-Linking
  installer.pod_target_subprojects.each do |project|
    project.targets.each do |target|
      if ['react-native-netinfo', 'react-native-randombytes'].include?(target.name) #list all affected target in the array
        target.build_phases.each do |build_phases|
          if build_phases.display_name == 'Frameworks'
            file_ref = project.new(Xcodeproj::Project::Object::PBXFileReference)
            file_ref.path = 'React.framework'
            file_ref.source_tree = 'BUILT_PRODUCTS_DIR'
            build_phases.add_file_reference(file_ref)
          end
        end        
      end
    end
  end
end

Still, hope this could be fixed on React Native side.

@mrousavy Ok, created the PR to update React-Core https://github.com/facebook/react-native/pull/29995

I fixed the issue by updating all the libs and by creating an empty swift file within the project.

Thanks @radko93 for jumping on all of these! šŸ™Œ

@xiao99xiao thanks for the workaround, it’s compiling for me now.

@igoriols you might need to update the script a bit as per your use case.

Pasting the script that worked for me:

  #Workaround for Xcode 12 and Auto-Linking
  installer.pods_project.targets.each do |target|
    if ['react-native-netinfo', 'react-native-shimmer', 'react-native-webview'].include?(target.name) #list all affected target in the array
      target.build_phases.each do |build_phases|
        if build_phases.display_name == 'Frameworks'
          file_ref = installer.pods_project.new(Xcodeproj::Project::Object::PBXFileReference)
          file_ref.path = 'React.framework'
          file_ref.source_tree = 'BUILT_PRODUCTS_DIR'
          build_phases.add_file_reference(file_ref)
        end
      end
    end
  end

You can use this script to fix the issue for all of your node modules: https://gist.github.com/HosseinRashno/4786b289356ad9840b6c087ce8191fe4

Link to StackOverflow: https://stackoverflow.com/a/65218722/4497248

Edit: And of course, you have to delete the pod folder and pod install, and then in xCode clean the project and build it again.

We ran into the same, having to manage multiple repo’s which different sets of dependencies with mixed versions, we had to manually patch many dependencies. So we ended up writing a little script that does the work for us, it’s a bit of a hack, but it works for us šŸ¤·ā€ā™‚ļø . Will share it here, but no guarantees it will work in your case as well. Place in the the root dir of your project, and run it on postinstall.

const fs = require('fs')
const path = require('path')

/**
 * Temporary patch to fix all xCode 12 libs
 */

const nodeModulesDir = path.join(__dirname, 'node_modules');

const fetchRNPackageDirs = (dir) => {
    const dirList = fs.readdirSync(dir);
    const packageDirs = [];
    dirList.forEach(packageName => {
        const packageDir = path.join(dir, packageName);
        if (packageName.startsWith('@')) {
            packageDirs.push(...fetchRNPackageDirs(packageDir))
        } else {
            const files = fs.readdirSync(packageDir);
            const podSpecs = files.filter(file => file.toLowerCase().endsWith('.podspec'));
            if (podSpecs.length > 0) {
                packageDirs.push({
                    dir: packageDir,
                    files: podSpecs,
                    package: packageName
                });
            }
        }

    });
    return packageDirs;
}

const packagesWithPodSpec = fetchRNPackageDirs(nodeModulesDir);
const dependencyRegex = /(s\.dependency +(?:'|"))React('|")/;
packagesWithPodSpec.forEach(package => {
    package.files.forEach(file => {
        const filePath = path.join(package.dir, file);
        const fileContents = fs.readFileSync(filePath);
        if (fileContents.match(dependencyRegex)) {
            fs.writeFileSync(filePath, fileContents.replace(dependencyRegex, '$1React-Core$2'))
            console.log('[xCode12Fix] Patching: ' + filePath);
        }
    })
});

Still seems like the correct change though in your estimation?

Without a doubt šŸ‘

Note that even though a GM exists, the beta is still needed for macOS 11/arm64.

@mikehardy I couldn’t reproduce the issue all the time, after a lot of cleaning and rebuilding I once had the error that a firebase package couldn’t be built (that’s why I’ve created the PR over there)

Hi all šŸ‘‹

Unfortunately I only just became aware of this ticket, so my apologies for the delay but thanks for the workarounds and the patience! šŸ™

I tried the reproduction kindly provided by @igoriols and was able to determine the problem. The issue is that all the podspecs of these libraries that fail to link depend on the React pod, which is in fact really only an umbrella dependency for pure JS applications to depend on, whereas the native APIs that these libraries rely on actually reside in the React-Core pod.

This means that they technically were always incorrect—conceptually one should always explicitly depend on the lib that provides the APIs you rely on, rather than relying on transitive dependencies—but it seems like in previous Xcode versions the build system worked differently and having the transitive dependencies around just happened to work šŸ¤·ā€ā™‚ļø

The correct fix going forward is for all these libs to update their dependency from React to React-Core:

-  s.dependency 'React'
+  s.dependency 'React-Core'

To unblock yourself you could use something like patch-package to temporarily hot-patch the podspecs you need, but it would be really great for the longer term and the community if you could also submit that change upstream to the respective library šŸ™ (See for example this react-native-webview pull-request.)

help me a lot, thanks

Let’s try to keep this issue on topic, as it’s lengthy enough as it is and otherwise people might miss the important bits when they come looking for solutions.

Also, @mikehardy I think the firebase app package version hasn’t been updated:

[!] NPM package '@react-native-firebase/messaging' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/ml-vision' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/perf' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/storage' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/messaging' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/ml-vision' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/perf' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/storage' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/ml-vision' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/messaging' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/perf' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

[!] NPM package '@react-native-firebase/storage' depends on '@react-native-firebase/app' v8.4.2 but found v8.4.3, this might cause build issues or runtime crashes.

@mikehardy, not all modules are affected, I pointed out that I didn’t test react-native-device-info yet. If you’re sure it (you’ve cleaned the project etc) works you can dismiss this PR.

Hi there! I have a bunch of modules like that should be affected (like react-native-device-info which @radko93 just PRd, thanks!).

I just updated to Xcode12. I’m trying the examples to demonstrate the problem.

My build is working fine? How do I demonstrate this failure? The example apps appear to work so which makes me uncomfortable, normally I like to have the first step of a PR verification be ā€œdemonstrate the problemā€ šŸ¤”

Thanks to @xiao99xiao and @naveen-c , I was able to use the following script to solve my problem with the workaround:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    #Workaround for Xcode 12 and Auto-Linking
    if ['RNCAsyncStorage', 'RNGestureHandler', 'RNReanimated', 'RNScreens', 'RNShare', 'react-native-webview', 'react-native-safe-area-context', 'react-native-netinfo'].include?(target.name) #list all affected target in the array
      target.build_phases.each do |build_phases|
        if build_phases.display_name == 'Frameworks'
          file_ref = installer.pods_project.new(Xcodeproj::Project::Object::PBXFileReference)
          file_ref.path = 'React.framework'
          file_ref.source_tree = 'BUILT_PRODUCTS_DIR'
          build_phases.add_file_reference(file_ref)
        end
      end
    end
    if ['react-native-safe-area-context'].include?(target.name)
      target.build_phases.each do |build_phases|
        if build_phases.display_name == 'Frameworks'
          file_ref = installer.pods_project.new(Xcodeproj::Project::Object::PBXFileReference)
          file_ref.path = 'yoga.framework'
          file_ref.source_tree = 'BUILT_PRODUCTS_DIR'
          build_phases.add_file_reference(file_ref)
        end
      end
    end
  end
end

I had to add yoga.framework to react-native-safe-area-context, also. šŸ˜•

Hi @xiao99xiao , thanks for your help. Just let me see if I understand it right: this script adds React.framework to Link Binary With Libraries build phase for each native library pods (the ones Auto-linked) that uses react-native. Is that right?

I used the following script:

post_install do |installer|
  #Workaround for Xcode 12 and Auto-Linking
  installer.pod_target_subprojects.each do |project|
    project.targets.each do |target|
      if ['RNCAsyncStorage', 'RNGestureHandler', 'RNPermissions', 'RNReanimated', 'RNScreens', 'RNShare', 'react-native-netinfo', 'react-native-safe-area-context', 'react-native-webview', 'rn-fetch-blob'].include?(target.name) #list all affected target in the array
        target.build_phases.each do |build_phases|
          if build_phases.display_name == 'Frameworks'
            file_ref = project.new(Xcodeproj::Project::Object::PBXFileReference)
            file_ref.path = 'React.framework'
            file_ref.source_tree = 'BUILT_PRODUCTS_DIR'
            build_phases.add_file_reference(file_ref)
          end
        end        
      end
    end
  end
end

The Undefined symbols for architecture x86_64 errors persists and the script didn’t add React.framework in Link Binary With Libraries. Did I do something wrong when I used your script? Screen Shot 2020-08-19 at 12 00 17

I don’t know if it means something for the issue, but there was a React (pods) in Dependencies section already. I thought the libs were importing react’s dependencies this way: Screen Shot 2020-08-19 at 12 04 26