Skip to content

macOS: UIImagePNGRepresentation and UIImageJPEGRepresentation fail to link from Objective-C++ #3137

Open

Description

Description

UIImagePNGRepresentation and UIImageJPEGRepresentation are declared in RCTUIImage.h without extern "C", but defined in RCTUIImage.m, an Objective-C file. So the library exports C symbols, and an Objective-C++ caller looks for C++-mangled ones: any .mm file that calls either function on macOS fails to link.

We hit it with react-native-svg 15.16, which calls UIImagePNGRepresentation from RNSVGSvgView.mm on macOS, so RNSVG failed to link in our app. The other two functions in the same header, UIImageGetScale and UIImageGetCGImageRef, are already wrapped in extern "C".

Steps to reproduce

With nothing but the two files from main (8941740):

// caller.mm
#import "RCTUIImage.h"

int main()
{
  NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)];
  return UIImagePNGRepresentation(image) == nil;
}
K=packages/react-native/ReactApple/Libraries/RCTUIKit
xcrun clang -c -fobjc-arc -fmodules -I$K $K/RCTUIImage.m -o RCTUIImage.o
xcrun clang++ -c -fobjc-arc -fmodules -I$K caller.mm -o caller.o
nm -u caller.o | grep PNG      # __Z24UIImagePNGRepresentationP7NSImage
xcrun clang++ caller.o RCTUIImage.o -framework AppKit

React Native Version

0.83.10, with react-native-macos 0.83.0. Also on main.

Affected Platforms

Build - MacOS

Output of npx @react-native-community/cli info

OS: macOS 26.6.2 (25G83), Apple M3
Xcode 27.1 (27A9275), macOS SDK 27.0
Node 24.19.0, CocoaPods 1.17.0
react-native 0.83.10, react-native-macos 0.83.0, new architecture

Stacktrace or Logs

Undefined symbols for architecture arm64:
  "UIImagePNGRepresentation(NSImage*)", referenced from:
      _main in caller.o
   NOTE: found '_UIImagePNGRepresentation' in RCTUIImage.o, declaration possibly missing 'extern "C"'
ld: symbol(s) not found for architecture arm64

Reproducer

The two commands above, against main. A PR with a fix follows.

One thing for the fix: RCTImageLoader.mm defines its own copy of both functions (the #1611 workaround). As C++ those copies have mangled names, so they never clashed with RCTUIKit's. Declared extern "C", they become duplicate symbols in a static build such as RNTester's, so the copy has to go too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions