Loading a bundle with Ruby on MacOS?


I am trying to create a Sketchup plugin on MacOS that is able to a display box.
The plugin is linked to SketchupApi, Ruby and Cocoa framework.

The goal of the plugin is to access to the Sketchup Model to perform operation and to offer different settings through a dialog box using NSPanel.

I had no problem to create and call a static library on Macos from Ruby. Everything run fine with Sketchup.
But when I add the dialog stuff and turn the project from a static library to a bundle Ruby fails to load the library.

require “path_to_bundle” Ruby command fails and a laconic message only reports that ruby fails to load the file. Is Ruby able to load bundle?

I can’t find any sample that performs a similar task (except Skp_to_xml, but this is an output plugin that is not loaded with Ruby).

What is the right way to make ruby load bundle or to create a plugin with complex dialogs?


The examples are in a GitHub repo

And FYI, in order for Ruby’s global #require method to load binaries (.so, .bundle, .dll, etc…) a C entry point function beginning with the substring Init_ and ending with the exact same name as the binary file, must be defined.

You’ll see in the example, that the project’s "SUEX_HelloWorld.cpp" file that the entry point C function "Init_SUEX_HelloWorld()" is defined …

When compiled the cpp file is output as "SUEX_HelloWorld.so" on MS Windows, and "SUEX_HelloWorld.bundle" on Mac.

Dave Thomas’ book “Extending Ruby 1.9: Writing Extensions in C ” covering writing C extensions is still good even though it was written for Ruby v1.9. Still covers the basics well.

Please see Thomas Thomassen’s (@thomthom) comment in the API issue tracker …

“I’d had time to look into this. And yes - it’s exactly the same. And I realize we’re completely missing proper docs for how to user the live C API. On the mac, …(click for more) …”

Thanks Dan.

Thanks for the link to Thomas post.

I had a look at the hello_world and made it run successfully.
But this sample is not a bundle but a dynamic library.

Even if the output extension of the file is “bundle”, the output file is a internally a dylib.

If you look in the project you have the line:

productType = "com.apple.product-type.library.dynamic";
instead of
productType = “com.apple.product-type.bundle”;

As soon as you turn the project to be a real bundle (which is require to use NSBundle resource access), it cannot be loaded with ruby anymore.

I can’t figure out why this fails.

1 Like

I’m sorry, but I’ve not dealt with bundles - only dylibs.

@bugra - any ideas?

I’m not really sure but I remember a time in the past when Ruby really wanted the library extension to be .so and anything else (.dylib, .dll, .bundle) would not work. That was a few Ruby versions ago though.

I’m confused by your choice of words.

You say you created a “static library” and wrapped it in a bundle. That won’t load at runtime because a static library must be statically linked into the application when the app is built. You should have created a dynamic library, a .dylib, which can be loaded dynamically into a running app. Is that what you really did?

Assuming you have actually created a dylib, why bother packaging it as a bundle? “bundle” is the generic term for a specially structured folder that Finder recognizes and treats as opaque. You can wrap a single dylib in a bundle, but that really gains nothing since it is already a single file. When there is a collection of related libraries and their resources, those are commonly gathered as a Framework (as specific kind of bundle).

I don’t know whether the Ruby loader is clever enough to process a bundle or limited to simple dylibs - like @thomthom I haven’t tried that either.

It seems that ruby can handle any extension now.

You’re absolutely right: the static/dynamic extension library should terminate with the appropriate extension.
Note: I have created my plugin project using licensed_ruby_extension SDK sample as a template.
This sample generates a static library with a bundle extension and so mine.
hello_world sample has exactly the same problem : bundle extension but the project generates a dynamic library.
So, at least using the appropriate extension would be more conventional and less confusing.

Anyway, when the project really generates a bundle, ruby fails to load it.this as no impact on the ability for ruby to load, unless I do something bad in the project configuration. I tried many things, without success.


When there is a collection of related libraries and their resources, those are commonly gathered as a Framework (as specific kind of bundle).

From my MacOS knowledge, accessing MacOS resource require a bundle plugin.
Objective C allows to access dialog resource using
[NSBundle loadNibNamed:@“DialogName” owner:self];

This fails in a dylib, unless I made some errors.

Note that we’re currently missing the C API symbols in the SketchUp application. All except the SUGetExtensionLicense. What we see people have done is link against SketchUpAPI.framework - but that shouldn’t be done. You end up with duplicate symbols and linking to the standalone lib instead of the app. It will appear to work in many/most cases, but eventually you’ll run into crashes and incorrect behaviour. We’ll be making sure the symbols are correctly exported in upcoming release.

We used the convention which Ruby has been using .so on Windows (even though they are .dll files) and .bundle on Mac (even though they are dylib).

If I clearly understand doing that would lead to have two instance of the framework loaded.
Is this only for C symbols?
Most of the API are C symbols because extern “C” is used for most of the include files.

May be that’s unconventional convention :wink:

Symbols might be misleading here. The real issue is that there are issue with for instance global data. If you link against the framework then there is a duplicate global variable. In some cases there are flags that needs resetting to clear caches, and if you aren’t linking against the app then things get out of sync. There are also issues with downcasts - that in some cases fail because the downcast doesn’t consider a type from the SketchUp app to be the same as a type from the framework.

Yea - that’s Ruby for you. Which puts us in a situation where we have to choose to follow the conventions used in Ruby world - or the rest of the world. Both are simultaneously right and wrong.

When next SDK for MacOS will be released?