I am trying to install a gem (clipper) in OSX by using
Gem.install "clipper"
but I get the error
Error: #<Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.
"/Applications/SketchUp 2015/SketchUp.app/Contents/Frameworks/Ruby.framework/Versions/2.0/bin/ruby" extconf.rb
sh: /Applications/SketchUp 2015/SketchUp.app/Contents/Frameworks/Ruby.framework/Versions/2.0/bin/ruby: No such file or directory
The installation works file if I run it from the terminal.
I have checked and the bin folder is actually not there. Any advice?
Unfortunately, SketchUp does not come properly set up to build compiled Ruby Gems under Mac OS X. What you are seeing is just the tip of the iceberg. Iâve fiddled with it extensively, manually tweaking configuration files, etc. and never got it to work. I think that a few people have managed to compile Gems outside SketchUp and get them to install, but it is tricky to get everything right since SketchUp uses a patched Ruby interpreter. At this point it is pretty much hit-or-miss.
I recently had success installing moving_images gem âmanuallyâ into my SU Gem folderâŚ
to get it to work required a standard gem instal in âTerminal.appâ and then carefully moving all the new files into my SU Gem folderâŚ
I think I will automate it the next time, maybe use ditto to copy all new files after the instalâŚ
I had the same problem in Windows 7, but I was able to compile the gem in Ruby (system) and then just copy the clipper.so file in the Sketchup plugin folder. Maybe I could do something similar in OSX?
The fact is that clipper is quite important for my plugin. Maybe an alternative could be to launch a ruby script outside SketchUp.
Build outside and copy the dylib and other files is what John describes. Sometimes it works, sometimes it doesnât. Youâll know when the Gem either doesnât work or SketchUp blows up!
Gems are a hit and miss in SketchUp. Ruby in large part assumes to be a console app. When we wrangle the Ruby interpreter into a GUI applications all sorts of complications occur - and we have no documentation to follow.
Are you planning to distribute extensions where you bundle these gems? Or is it for personal use?
There is a challenge there - if you distribute your own version of the gems. If multiple people do that same thing there can be a conflict if they try to use/load different versions. Weâve seen this happening.
Weâve also seen people bundle Ruby 1.8 libs in the past without making version checks for the Ruby environment causing lots of problems when the extension is installed under Ruby 2.0.
If possible - edit the libs you distribute into your own namespace. Now, some gems modify core classes making this difficult. These are also the type of gems that often lead to clashes.
That looks nice and clean. Thatâs good. Iâd still recommend you tweak the version you distribute to confine it to your own extension to be sure you wonât run into any future conflicts.
I very much like the way they (the binder) wrapped the library class within a Ruby mixin module.
It is actually meant to be mixed into the programmerâs namespaces:
module AuthorToplevelNamespace
module ThisPlugin
require 'clipper' # assumes gem was pre-installed
include Clipper # includes the Clipper mixin module
# Now the local constant Clipper is a proxy lookup
# to the ::Clipper::Clipper class.(Because identifiers
# are constants and get mixed in during the include.)
def self::union_method(
a = [[0, 0], [0, 100], [100, 100], [100, 0]] ,
b = [[-5, 50], [200, 50], [100, 5]]
)
c = Clipper::new()
c.add_subject_polygon(a)
c.add_clip_polygon(b)
c.union( :non_zero, :non_zero )
end
end
end
(1) This library was gemified, but unfortunately it is uncompiled.
(2) The version you cite is actually a year out of date. This is a good example of what Thomas was talking about. There then exists the high probability that someone else will package to later version, or if you packaged the later, someone else would likely package the earlier.
So to do what Thomas says, you need to change the ârbclipper.cppâ file a bit.
Change line 353 to:
VALUE top = rb_define_module("Rojj");
⌠or whatever your toplevel namespace module name is.
And change line 354 to:
VALUE mod = rb_define_module_under(top,"Clipper");
Then the âversion.rbâ file needs to be also wrapped within your toplevel module.
Example:
module Rojj::Clipper
# Keep first two components sync'd to Clipper's major/minor.
# Last is our build number based on that. Hopefully there
# won't be too much churn re: Clipper's version vs. the bindings.
VERSION = "5.0.3"
end
OK. It was more complicated than i thought. A bit of help would be greatly appreciated.
Dan, are you saying that i should download the latest version of the gem, make the modifications you suggest and then install from the local (modified) gem file?
After that I should be able to move the compiled files to the SU plugin folder as I do in Windows 7?
Sorry if the questions are dumb, but I am a bit stuck.
The only files that really belong in the âPluginsâ folder, are the SketchupExtension class registration scripts. All plugin files and support libraries should be in sub-directories.
In the case of custom compiled gems, it is really best to convert their file & folder structure to be SketchupExtension class compatible. That means putting the compiled .so file in a plugin subdirectory (named ToplevelModule_GemName,) and write a SketchupExtension registration script for the âPluginsâ directory (named ToplevelModule_GemName.rb.)
However ⌠if you modify it as outlined above, it will become a library module wrapped within YOUR toplevel module. Noone else will be expected to use it in that way, and it will not clash with any other distribution. No one elseâs distribution will be expected to wrap the gem module within your namespace, so it is safe from other plugins.
If it will only be distroâd with your plugin (and your plugin is SketchupExtension class compatible,) then you wonât need to do the above. Just package the library file along with your pluginâs other files in itâs plugin subdirectory (named ToplevelModule_PluginName.) Some where usually at the top of your pluginâs loader script, you would make a call like: require File.dirname(__FILE__)<<"/ToplevelModule_GemName.so"
or if you know the plugin sub-dir name will not change: require "ToplevelModule_PluginName/ToplevelModule_GemName.so"
If you look at some of Thomasâ plugins, youâll see how he deals with distributing Mac compiled libs, along with two separate libs for Windows (32bit and 64bit.)
You can probably make things easier for your distribution by simply extracting the gem content (which you now have wrapped in your namespace) into the support folder of your extension directly.