macOS universal plugin agony

So I took a deep breath set out to update my plugin to x86-64/arm64 universal, knowing that everytime I sit down with Xcode and mess with plugins it results in anguish.

Figuring I’d start from basics, I created a simple Xcode project with a single simple function that adds 7 to a passed integer. All was good, the plugin built, I assembled it into a .xojo_plugin, and a xojo test app recognized and called it successfully from the debugger.

Thinking it can’t be this easy I then built my standalone xojo app and upon launch, i got a long error log as below. Assuming I did something wrong, I tried Xojo’s Variant Tester example from their latest PluginSDK > Examples and got the same error on launch (even tho a test app runs fine under the debugger and calls all 3 methods in their plugin just fine).

This is the latest Xojo and on a silicon mac running ventura. So my plugin agony continues. Does anyone have an idea of what’s wrong here? If Xojo’s example plugin projects fail out of the box then we’re in trouble. Seems from the error msg it wants an ‘arm64’ only version even tho I supplied it with a universal version. And how can things run fine under the debugger but fail in the built app?

Location: Common/plugin.cpp:1048
Condition: false
Message: Could not open plugin VariantTester.dylib (dlopen(/Volumes/LabStuff/Development/my Xcode projects/xojoPlugins/Xcode14TestPlugin/Xcode14Test xojo project/Builds - Xcode14Test/macOS Universal/Xcode14Test.app/Contents/Frameworks/VariantTester.dylib, 0x0005): tried: ‘/Volumes/LabStuff/Development/my Xcode projects/xojoPlugins/Xcode14TestPlugin/Xcode14Test xojo project/Builds - Xcode14Test/macOS Universal/Xcode14Test.app/Contents/Frameworks/VariantTester.dylib’ (cpu type in slice (0x0100000C) does not match fat header (0x01000007), cpu type in slice (0x0100000C) does not match fat header (0x01000007), fat file, but missing compatible architecture (have ‘x86_64,arm64’, need ‘arm64’)), ‘/System/Volumes/Preboot/Cryptexes/OS/Volumes/LabStuff/Development/my Xcode projects/xojoPlugins/Xcode14TestPlugin/Xcode14Test xojo project/Builds - Xcode14Test/macOS Universal/Xcode14Test.app/Contents/Frameworks/VariantTester.dylib’ (no such file), ‘/Volumes/LabStuff/Development/my Xcode projects/xojoPlugins/Xcode14TestPlugin/Xcode14Test xojo project/Builds - Xcode14Test/macOS Universal/Xcode14Test.app/Contents/Frameworks/VariantTester.dylib’ (cpu type in slice (0x0100000C) does not match fat header (0x01000007), cpu type in slice (0x0100000C) does not match fat header (0x01000007), fat file, but missing compatible architecture (have ‘x86_64,arm64’, need ‘arm64’)))

Seems like you build a plugin for x86_64 only.

You need to select universal architecture and also make sure it doesn’t just build one for debugging:

No, I think it’s a universal:

plus:

  1. the err log reads: have ‘x86_64,arm64’ (so presumably universal?)

and

  1. this call to the plugin returns the correct value (2), at least when running under the debugger:
    #if defined(x86_64)
    return 1; // Intel x86_64
    #elif defined(arm64)
    return 2; // arm64
    #else
    return 0; // unknown
    #endif

The failure occurs only with the built app. Clearly this can work because your MBS plugins run flawlessly. So I’m obviously doing something wrong but if xojo’s examples don’t even work then i’m at a loss.

I still get the same error on launch of the built app. Is there some other switch in Xcode that might be set incorrectly?

My plugin’s dylib was defininitely linked into my built app’s framework:

and still:
Location: Common/plugin.cpp:1048
Condition: false
Message: Could not open plugin libXcode14TestPlugin.dylib (dlopen(/Volumes/LabStuff/Development/my Xcode projects/xojoPlugins/Xcode14TestPlugin/Xcode14Test xojo project/Builds - Xcode14Test/macOS Universal/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin.dylib, 0x0005): tried: ‘/Volumes/LabStuff/Development/my Xcode projects/xojoPlugins/Xcode14TestPlugin/Xcode14Test xojo project/Builds - Xcode14Test/macOS Universal/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin.dylib’ (cpu type in slice (0x0100000C) does not match fat header (0x01000007), cpu type in slice (0x0100000C) does not match fat header (0x01000007), fat file, but missing compatible architecture (have ‘x86_64,arm64’, need ‘arm64’)), ‘/System/Volumes/Preboot/Cryptexes/OS/Volumes/LabStuff/Development/my Xcode projects/xojoPlugins/Xcode14TestPlugin/Xcode14Test xojo project/Builds - Xcode14Test/macOS Universal/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin.dylib’ (no such file), ‘/Volumes/LabStuff/Development/my Xcode projects/xojoPlugins/Xcode14TestPlugin/Xcode14Test xojo project/Builds - Xcode14Test/macOS Universal/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin.dylib’ (cpu type in slice (0x0100000C) does not match fat header (0x01000007), cpu type in slice (0x0100000C) does not match fat header (0x01000007), fat file, but missing compatible architecture (have ‘x86_64,arm64’, need ‘arm64’)))

So what does the file command say about the dylib?
Does it have the right platform? The error says it doesn’t.
And the plug-in sdk includes a text file explaining the plug-in structure.

this is what ‘file’ reports on the dylib in the built app:

…/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin.dylib: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit dynamically linked shared library arm64] [arm64:Mach-O 64-bit dynamically linked shared library arm64]
…/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library arm64
…/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin.dylib (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64

and on the .debug app:

…/Xcode14Test.debug.app/Contents/Frameworks/libXcode14TestPlugin.dylib: Mach-O 64-bit dynamically linked shared library arm64

partial victory: I reset the scheme settings in Xcode (Edit scheme>Run>Info) from ‘Debug’ to ‘Release’ (now it builds a release version that is not restricted to the current architecture only, arm64 in my case since i’m running on a silicon mac).

My app now runs under the debugger and built. However, despite having the 2 required components in my universal plugin:

file …/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin_universal.dylib: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit dynamically linked shared library x86_64] [arm64:Mach-O 64-bit dynamically linked shared library arm64]
…/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin_universal.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
…/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin_universal.dylib (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64

Now the built app throws an error on launch on my Intel mac:

Location: Common/plugin.cpp:1048
Condition: false
Message: Could not open plugin libXcode14TestPlugin_universal.dylib (dlopen(/Volumes/SharedVolume/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin_universal.dylib, 5): no suitable image found. Did find:
…/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin_universal.dylib: cannot load ‘libXcode14TestPlugin_universal.dylib’ (load command 0x80000034 is unknown)
…/Xcode14Test.app/Contents/Frameworks/libXcode14TestPlugin_universal.dylib: cannot load ‘libXcode14TestPlugin_universal.dylib’ (load command 0x80000034 is unknown))

Christian: I noticed MBS has 2 separate folders for each arch: Mac arm64 and Mac x86_64 vs Xojos are just Mac Universal. So tried building a non-universal plugin with separate arm and x86 dylibs and that did not work on my Intel Mac either.

I’m totally stuck. This really should not be so hard and I wish Xojo’s example projects actually worked so we can emulate what they did.

Well, I build plugin dylibs with make files (no Xcode project), so I have full control on what runs.

You may ask Xojo Inc. for help, e.g. @William_Yu.

Our Open source plugins have XCode projects…if that helps.

https://einhugur.com/Html/opensource.html

I don’t make “Universal” per see though, I make macOS Intel and macOS Apple Silicon. (Separate segments). Xojo glues them together if Xojo user chooses “Universal build”.

Thank you Christian and Bjorn for your help. I tried the fpPlugin project, and while the Xcode project failed to build, reporting a number of obscure errors (this is my recurrent experience with Xcode, even coming back to the same project on the same machine 6 months later and just building, often fails, it’s almost like magic…), I followed the myriad different settings in your project and this one caught my eye:

Turns out mine was set to the default of 13.2, so that explains why my plugin ran under Rosetta on my silicon Mac, but failed to load on my older Intel Mac running 10.14. In my partial defense, I knew enough that this had to be set for compatibility with older OS versions, and I had this under Architectures:

but no, that was not the right place for this setting.

Bottom line, I now have a universal plugin that runs on both architectures, new and old OSs.

Thanks again
P.

1 Like

BTW, because making plugins is such a convoluted process (for me anyway), requiring me to start almost from scratch every time (since I only come back to this infrequently), I wrote a step-by-step A to Z instruction sheet that summarizes what needs to be done in Xcode 14.
Happy to share, just email me pkstys@gmail.com
Xojo Inc, if you read this thread and have somewhere to post the pdf I created (and think it would be useful for your users) then I’m happy to send along as well.

Peter, what about writing a guest blog post?, it will appear in https://blog.xojo.com and the PDF could be linked and downloaded from there.

Unfortunately I won’t have time to do this, but happy to send the pdf for posting somewhere

https://xojo.com/issues

Open an Issue about this problem you experienced there, post your PDF, findings and remarks. And close it as solved by yourself. Return here and post a link to such case. People may find it in the future searching here or there.

It may be used by Xojo to enhance their docs about plugins.

Good idea Rick:

https://tracker.xojo.com/xojoinc/xojo/-/issues/73896

1 Like

static long add7( long n )

needs to be

static RBInteger add7(RBInteger n)

Else you will get memory clobbering issues on some systems.

3 Likes

Thx Bjorn, quite correct. However when I look at the definitions, on 64 bit builds (32 bit no longer exists really) RBInteger, long and int64_t seem to be the same

32 bit exists on Windows and on Linux Arm32…

And long is not guarantied to be 64 bit (and usually is not 64 bit)

For example on Visual Studio 64 bit app then its like this:

std::cout << sizeof(long) << “\n”; // 4 bytes
std::cout << sizeof(int64_t) << “\n”; // 8 bytes

3 Likes

OK got it, i only do macOS so didn’t look far enough