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 relaunch the script. I am developing a plugin in Ruby for SketchUp so "relaunching" the script would actually mean to restart the application.
Sample code to show the issue:
require 'fiddle'
require 'fiddle/import'
require 'fileutils'
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, as expected.
So it seems that during the execution the library is imported only once.
Any suggestion on how to force Fiddle to reload the library?
I am using macos and Ruby 2.0
Just in case someone needs this in the future. You can use
#handler.handlers.each {|h| h.close unless h.close_enabled? } unless #handler.nil?
GC.start
So you first close all the handlers and then force the garbage collection.
Related
I'm incrementally adding RBS type signatures to my Ruby (not Rails) project. The project contains a Rakefile for running tests manually, but also a Guardfile for running tests when files change.
For that reason I've added the RBS setup to spec_helper.rb, to avoid having to duplicate it in both Rakefile and Guardfile.
# spec_helper.rb
ENV['RBS_TEST_TARGET'] ||= 'MyModule::*'
require 'rbs/test/setup'
This works as expected - the type signatures are verified regardless of what winds up running the specs. It feels like a bit of a hack, though; is there a better or even a more idiomatic way of doing this?
I've been trying to debug ruby gem made with Ruby C Extension to figure out how it works, so I can modify it to my own use. It's quite an advanced gem and printing values isn't enough. So I started debugging it with gdb and gdb-ruby gem. I created instance of class in ruby and ran a method that later connects to functions written in C. There was no way I could stop at certain line in C function even after placing breakpoint. To debug ruby I use 'pry' gem if that means anything. Is there a straightforward way to place a breakpoint inside C function, so it stops at it when reaching given function/line in C file after running Ruby program?
require 'digest/md5' # => true
Digest::Md5.hexdigest('') # => "d41d8cd98f00b204e9800998ecf8427e"
Which file does this require use? Is an actual file being required? Or is it required programmatically?
This is (sorta) explained in the documentation for Kernel#require:
require(name) → true or false
Loads the given name, returning true if successful and false if
the feature is already loaded.
If the filename does not resolve to an absolute path, it will be
searched for in the directories listed in $LOAD_PATH ($:).
If the filename has the extension “.rb”, it is loaded as a source file; if
the extension is “.so”, “.o”, or “.dll”, or the default shared library
extension on the current platform, Ruby loads the shared library as a Ruby
extension. Otherwise, Ruby tries adding “.rb”, “.so”, and so on to the
name until found. If the file named cannot be found, a LoadError will be raised.
By default $LOAD_PATH will include the directories where Ruby's standard library lives. Directories, plural, because native (compiled binary) modules in the standard library live in a different directory than pure-Ruby modules.
Digest is actually a great example because some of its files are native and others are Ruby.
On my Mac $LOAD_PATH includes (among others) these two directories (truncated for readability):
.../usr/lib/ruby/2.0.0
.../usr/lib/ruby/2.0.0/universal-darwin15
The former is where pure-Ruby modules live and the latter is where native modules live.
So when I do require 'digest/md5' Ruby first looks in .../usr/lib/ruby/2.0.0/ for a directory named digest/, and upon finding it, for a file in it named md5.rb. It doesn't find it, so it looks for md5.bundle. Why .bundle and not .so or .o? Because that's the "default shared library extension" that Ruby was configured with when it was compiled for OS X. Go figure.
Ruby doesn't find it there, so next it looks in .../usr/lib/ruby/2.0.0/universal-darwin15/digest/. There's no md5.rb there, but there is an md5.bundle, so Ruby loads it.
It loads a C-extension that can be found in Ruby's source dir - ruby/ext/digest/md5/
It's one of Ruby's standard libraries (stdlib), which means that it's available in pretty much every implementation of Ruby. It does, in fact, load a file. But it's a file that was copied to your computer when you installed Ruby and is pretty much always going to be available to you. Another good example of a standard library is DateTime.
One thing that confused me a lot when I started learning Ruby and Rails was that Rails requires a fair number of Ruby's standard libraries for you. So it's good to be aware of what's actually going on under the hood.
I am trying to load a dll using the following fiddle code: ( If there is a easier way to load a dll and call a function on it that would solve my problem I am happy to hear it )
require 'fiddle' unless defined?(Fiddle)
require 'fiddle/import' unless defined?(Fiddle::Importer)
extend Fiddle::Importer
dlload "Foo.dll"
dlload "C:/Folder/Foo.dll" works like I want. But the problem is that Foo.dll is a c++ dll that requires several other dlls in various locations.
How do I go about just calling dlload "Foo.dll" without a full path. In short how do I add a list of directories to the Ruby dll search path?
I have tried the following:
$LOAD_PATH.unshift("C:/Folder")
ENV['RUBYLIB'] = "C:/Folder"
ENV['LD_LIBRARY_PATH'] = "C:/Folder"
The ruby interpreter is running inside another program (Sketchup), so my environment is restricted.
The only solution I got to work was writing a small kernel32.dll library and calling AddDllDirectory from within it.
This page on the IronRuby help website talks about being able to 'require' some well-known assemblies such as System.Windows.Forms without needing to crank out the entire 'ah-come-on-gimme-a-break-here-you-cannot-be-serious' strong name of the assembly.
In the docs it says this:
>>> require "System.Windows.Forms"
=> true
But when I try the same 'require', I get this:
>>> require "System.Windows.Forms"
IronRuby.Libraries:0:in 'require': no such file to load -- System.Windows.Forms (LoadError)
from :0:in 'Initialize##1'
What might I be doing wrong? Could it be a setup problem? I can't see this "libs directory on the load path" that gets mentioned in the documentation. Is the documentation wrong?
Thanks.
The way that this works is because the IronRuby guys have written a bunch of wrapper scripts.
Look in <your ironruby install path>\lib\ironruby and you'll see System.Windows.Forms.rb, System.Drawing.rb etc.
What happens when you do require 'System.Windows.Forms' is that IronRuby finds that rb file and runs it. The code inside that file just does the full strong-named require for you.
If you want to load other dll's that they haven't written wrappers for, you have 3 options:
require the full path to the dll (eg c:\program files\whatever\whatever\blah.dll)
require the strong name (this only works if it's in the GAC or somewhere else IronRuby can find dll's in)
use load_assembly - This is the most convenient, but IIRC it loads the dll into the LoadFrom context, not the Load context.
If you don't understand what that means, then basically it's fine in testing, but don't do it in production :-)
Well, it was a setup problem - there were two copies of ir.exe in the IronRuby download, and I was using the wrong one.