More Ruby Extension Building Nonsense-It doesn't end
No sooner did I finish bitching about the Ruby extension experience in Windows than things got worse. You see, apparently I’m doing something so unheard of, so outside the box that the Ruby extension model has trouble coping.
It’s not enough for me to include headers and link with libraries. In order to build my extension, I need to know where the root Wireshark source tree is, I need that source tree to have been built already, and (under Windows) I need to know where the wireshark-win32-libs directory is. I need to compute a number of include and library paths based on this information. After the build, I need to copy the Wireshark libs into the directory where my extension is going, since they won’t be in the path.
Now, I know what you’re thinking. “That doesn’t sound so off-the-wall; what’s the problem?” Well, the problem is that the mkmf toolkit is extremely limited; clearly a tool designed for the 80% case, with the 20% case completely shut out in the cold. “Fine”, I thought to myself, “I’ll just use Rake. I’ve been meaning to beef up my Rake skills anyway.” Um, yeah.
Fortunately I did run across an experimental Rake task for building Ruby extensions, which at least pointed me in the right direction. But now there’s a new problem: rbconfig.
You see, given that Ruby can be built and run in all sorts of fucked-up platforms, each Ruby install has a file, rbconfig.rb, which populates the Config::CONFIG hash with name/value pairs from the Ruby build. Things like LDFLAGS, bindir, and COMPILE_C. This is what mkmf uses to generate the makefile that builds your extension in the first place. This is also what extensiontask uses to invoke the compiler.
To illustrate the problem, look at the DLDFLAGS config parameter from my rbconfig.rb:
CONFIG["DLDFLAGS"] = "-link -incremental:no -debug -opt:ref -opt:icf -dll $(LIBPATH) -def:$(DEFFILE) -implib:$(*F:.so=)-$(arch).lib -pdb:$(*F:.so=)-$(arch).pdb"
If you’ve ever worked with the command line Visual C++ compiler, you’ll recognize the -link switch and those after it. This is meant to be tacked on to a cl invocation to have it do its linking. But wait. Look at the -implib switch more closely:
-implib:$(*F:.so=)-$(arch).lib
‘PC LOAD LETTER’!? WTF does that mean!? If you don’t recognize that shit that looks like line noise, you’re not alone. I too thought it was Perl code for a second. As it turns out, things like $(arch) and $(*F:.so) are variable placeholders that make and its ilk expand at runtime. $(arch) expands to the arch environment variable, while *F is an automatic variable that expands to the file name (but not extension) of the output file of the current task.
That’s right, the flags in rbconfig are only meaningful to a make-compatible build tool. If you don’t want to use make, then fuck you. I can only assume that the rbconfig under UNIX doesn’t have this bullshit, otherwise the guy who wrote extensiontask would’ve noticed his shit failing weirdly.
It shouldn’t be too hard to write a bit of regex magic that parses this stuff out and does the expansion at runtime, but dammit why does it always seem to come to this?
Tags: Migrated from Drupal, rake, ruby, tech diary