Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MoltenVK 1.3.231.1 binaries use Apple LLVM 14+ option -fobjc-msgsend-selector-stubs, incompatible with earlier Xcode or osxcross with LLVM < 16 #1756

Closed
akien-mga opened this issue Nov 3, 2022 · 6 comments · Fixed by #1773
Labels
Bug Completed Issue has been fixed, or enhancement implemented.

Comments

@akien-mga
Copy link

akien-mga commented Nov 3, 2022

For official builds of Godot Engine 4.0, we use osxcross to cross-compile macOS and iOS binaries from Linux (Fedora 36). osxcross uses upstream LLVM/Clang.

Recent MoltenVK binaries in the Vulkan SDK seem to be built with Xcode 14 (and thus Apple LLVM 14), which includes a new -fobjc-msgsend-selector-stubs optimization enabled by default. This flag enables the use of symbols which are unique to Apple LLVM 14+, and therefore current libMoltenVK.a cannot be used with:

  • Xcode 13 or earlier on macOS (conjecture, didn't test)
  • osxcross with any upstream LLVM version < 16 (confirmed)

It should be possible to make the libMoltenVK.a binaries portable again by disabling the optimization with -fno-objc-msgsend-selector-stubs.

That optimization made its way into upstream LLVM with https://reviews.llvm.org/D128108, but this was merged recently and will first be included in LLVM 16.

Here's an example of linking error (with osxcross built with Xcode 14.1 SDKs):

/root/osxcross/target/bin/arm64-apple-darwin22-c++ -o bin/godot.macos.editor.arm64 -arch arm64 -mmacosx-version-min=11.0 -framework Cocoa -framework Carbon -framework AudioUnit -framework CoreAudio -framework C>
Undefined symbols for architecture arm64:
  "_objc_msgSend$HDR10MetadataWithDisplayInfo:contentInfo:opticalOutputScale:", referenced from:
      MVKSwapchain::setHDRMetadataEXT(VkHdrMetadataEXT const&) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
  "_objc_msgSend$UTF8String", referenced from:
      MVKCommandResourceFactory::newMTLFunction(NSString*, NSString*) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKCommandResourceFactory::initMTLLibrary() in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKWatermark::newRenderPipelineState() in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKWatermark::initShaders(char const*) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKGPUCounterQueryPool::initMTLCounterSampleBuffer(VkQueryPoolCreateInfo const*, objc_object objcproto13MTLCounterSet*, char const*) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKInstance::debugReportMessage(MVKVulkanAPIObject*, MVKConfigLogLevel, char const*) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKBuffer::propagateDebugName() in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      ...
  "_objc_msgSend$UUIDString", referenced from:
      MVKPhysicalDevice::logGPUInfo() in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
  "_objc_msgSend$addCompletedHandler:", referenced from:
      MVKImagePlane::applyImageMemoryBarrier(unsigned int, unsigned int, MVKPipelineBarrier&, MVKCommandEncoder*, MVKCommandUse) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKImagePlane::pullFromDeviceOnCompletion(MVKCommandEncoder*, MVKImageSubresource&, MVKMappedMemoryRange const&) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKPresentableSwapchainImage::presentCAMetalDrawable(objc_object objcproto16MTLCommandBuffer*, MVKPresentTimingInfo) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKCommandBuffer::flushImmediateCmdEncoder() in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKCommandEncoder::endEncoding() in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKCommandEncoder::encode(objc_object objcproto16MTLCommandBuffer*, MVKCommandEncodingContext*) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKCommandEncoder::endCurrentMetalEncoding() in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      ...
  "_objc_msgSend$addObject:", referenced from:
      MVKDescriptorPool::getMetalArgumentBufferResourceStorageSize(unsigned long, unsigned long, unsigned long) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKInstance::getAvailableMTLDevicesArray() in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKDescriptorSetLayoutBinding::addMTLArgumentDescriptors(NSMutableArray<MTLArgumentDescriptor*>*) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
      MVKDescriptorSetLayoutBinding::addMTLArgumentDescriptor(NSMutableArray<MTLArgumentDescriptor*>*, unsigned int, MTLDataType, MTLArgumentAccess) in libMoltenVK.a(libMoltenVK.a-arm64-master.o)
  "_objc_msgSend$addObserver:forKeyPath:options:context:", referenced from:
      -[MVKBlockObserver startObservingObject:atKeyPath:] in libMoltenVK.a(libMoltenVK.a-arm64-master.o)

... (continues for hundreds of lines)

See Godot PR to update our Vulkan SDK blocked by this issue:

@akien-mga
Copy link
Author

akien-mga commented Nov 3, 2022

godotengine/godot#68080 (comment)

It should be possible to make the libMoltenVK.a binaries portable again by disabling the optimization with -fno-objc-msgsend-selector-stubs.

We confirmed that building MoltenVK 1.2.0 with Xcode 14.1 on macOS and -fno-objc-msgsend-selector-stubs as extra ObjC flag fixes the linking issue for us when building Godot with osxcross and upstream LLVM 14.0.5 (Fedora 36 distro package).

@billhollings
Copy link
Contributor

billhollings commented Nov 3, 2022

We confirmed that building MoltenVK 1.2.0 with Xcode 14.1 on macOS and -fno-objc-msgsend-selector-stubs as extra ObjC flag fixes the linking issue for us when building Godot with osxcross and upstream LLVM 14.0.5 (Fedora 36 distro package).

Thanks for your analysis and research.

So how severe is this, and how do we want to handle it?

  • Is there reason to set -fno-objc-msgsend-selector-stubs as the default in MoltenVK Xcode projects? Presumably the need for such a setting will go away in time (LLVM 16+, etc). But perhaps the linking problems for dev users using Xcode 13- would make this necessary in the short term.
  • Or should we leave it alone, but document it, and let dev users with this need apply -fno-objc-msgsend-selector-stubs and rebuild MoltenVK themselves?

@phush0
Copy link

phush0 commented Nov 7, 2022

I think that devs rebuilding their copies is the correct way, as it will match whole dev environment better.

@akien-mga
Copy link
Author

That's the option we took for Godot, though we couldn't build MoltenVK with our main dev environment as it seems only Xcode / xcodebuild is supported, so we can't use osxcross. So for now I just had a dev compile it on macOS with the mentioned flag and the build works fine for us.

So from our perspective we're all set (though we'll have to keep making custom builds manually until we finally have access to LLVM 16), but figured it would be good to let you folks know about the problem since other users may face it (and hopefully find this issue if they do).

@billhollings
Copy link
Contributor

Although -fno-objc-msgsend-selector-stubs allows a library built with Xcode 14 to be linked to an app using Xcode 13 or earler, it cannot be used when building the library with any Xcode version prior to 14. I haven't been able to find a way to suppress the compile error that occurs as a result of this, nor have I found a way to only apply that build setting for Xcode 14 builds and above.

As a result, I've removed -fno-objc-msgsend-selector-stubs and just documented the change in linkage with Xcode 14, and recommended devs who need to link MoltenVK to their apps with Xcode 13 or earlier also need to build with Xcode 13 or earlier, or build with Xcode 14 after adding the -fno-objc-msgsend-selector-stubs to their MoltenVK build.

@akien-mga
Copy link
Author

As an update, for users who may stumble upon this issue while doing the same thing we do for Godot (linking MoltenVK with osxcross instead of the native Xcode toolchain):

This issue is still reproducible as of latest osxcross, despite using Apple LLVM based on LLVM 16, which should have https://reviews.llvm.org/D128108 included. I suspect Apple's open source codebase for the ld64 linker (used in osxcross via https://github.com/tpoechtrager/cctools-port/ ) might still be lagging behind and not offering this feature yet.

So for Godot we've consistently made our custom MoltenVK builds with -fno-objc-msgsend-selector-stubs as a workaround. I finally bit the bullet and made a GitHub repo that builds MoltenVK releases with that option enabled, so these builds should be compatible with osxcross:

https://github.com/godotengine/moltenvk-osxcross/releases

I might not tag all upstream releases there, but at least the ones we decide to use in Godot whenever we update our Vulkan SDK components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Completed Issue has been fixed, or enhancement implemented.
Projects
None yet
3 participants