Reload dynamic library with Fiddle

I am using Fiddle to load a function from a dynamic library written in C. During development I need to make changes to the library and reload it for testing. The problem is that dlload does not reload the library unless I restart SketchUp.

Sample code to show the issue:

require 'fiddle'
require 'fiddle/import'
require 'fileutils'

# test
module RG
  extend Fiddle::Importer  
  dlload 'utils.dylib'
end

FileUtils.rm 'utils.dylib'

module RG
  extend Fiddle::Importer  
  dlload 'utils.dylib'
end

If you launch the script the first time there is no error. If you launch it the second time you get the error: image not found.

So it seems that during the execution the library is imported only once. It seems that this is the reason why I cannot update it during a SketchUp session.

Any suggestion on how to force Fiddle to reload the library?

I am using SketchUp 2015 on macos

no, but as your on a mac, I do have a very useful ‘mac_restart’ ruby which can close and reopen the current SU version…

re-opening the current model is playing up in v19, but was working fine in earlier versions [v15 should be ok]…

I’ll PM a copy if you want…

john

Haven’t tried it, but dllload returns a handle, and a handle can be closed.

Open the source code here and you’ll see dlclose

… and FileUtils.rm will delete the file from disk if it exists.
Why would you do this and then just afterward try to load it again?

1 Like

This is just an example to prove that once the library is loaded the first time it is not reloaded again.

My rakefile replaces the files in the plugin directory, but clearly it is not loaded again.

Thanks. That would be very kind of you.

I could not find a dlclose method, at least for Fiddle::Importer.

dlload does not return a handle, but it does define, if I understand correctly, a @handler instance variable in the module and this is a Fiddle::CompositeHandler. So I have tried

@handler.handlers.each{|h| h.close}

but I receive the error

#<Fiddle::DLError: dlclose() called too many times>

Sorry, dlclose is in the c source for Handle#close. Maybe try rescuing the error and see if you can reload the file?

Try this instead …

@handler.handlers.each {|h| h.close unless h.close_enabled? }

… and then be sure to force garbage collection so the handles are released …

GC.start
1 Like

Also, … I do not believe that the Ruby core is setup to allow #extend to run more than once upon the same object.

Usually these type of mixin methods check the ancestry chain of the object and only are applied if the mixin module does not already appear in the chain.

Anyway you shouldn’t need to extend with the importer mixin again.
You might need to find a way to reinitialize the @handlers object however.

It works! It needed a small change to deal with the first time it is executed and @handlers is not defined.

@handler.handlers.each {|h| h.close unless h.close_enabled? } unless @handler.nil?
GC.start

Thanks a lot.

1 Like