Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is writing a C interface easier in Ruby than Perl?

According to the official ruby About page it's easier to extend Ruby with C than Perl. I'm not a (perl) XS guy, but I find it dirt simple to write something quick and simple with Inline::C, so why is it easier in Ruby?

Writing C extensions in Ruby is easier than in Perl or Python, with a very elegant API for calling Ruby from C. This includes calls for embedding Ruby in software, for use as a scripting language. A SWIG interface is also available.

Any further explanation from those that do more C extensions would be useful.

like image 372
NO WAR WITH RUSSIA Avatar asked Apr 09 '11 23:04

NO WAR WITH RUSSIA


2 Answers

(Full disclosure, I am a Perl programmer)

The Ruby C API certainly looks much nicer than Perl's. It looks like a regular C library with functions that correspond to Ruby code. Perl's API is a mess of macros within macros within macros and magic threading flags. Using the Perl API outside of the Perl core is certainly a secondary concern. Ruby definitely wins on not being bowel clenchingly terrifying.

While Ruby has a better C API, Perl has the better tutorials on how to do anything with it. The generated Ruby documentation lacks any sort of cohesive tutorial or often any descriptive text at all. It's possible I'm looking in the wrong place but that's all that was offered. In contrast, the Perl API documentation is hand written prose with useful information about what each function does. In addition, there's over a dozen documents in the core docs about using Perl and C. I'd say Perl wins on docs.

FFI looks quite impressive. The closest thing Perl has to FFI is Inline::C which is a wrapper around the mess of XS. It's primary use is to inline C code into your Perl program, but you can also use it to access C library functions.

Here's a trivial example similar to nash's getpid example.

use Inline
  C             => Config       =>
  ENABLE        => "AUTOWRAP";

use Inline C => q{ int getpid(); };

print getpid();

Now, I am cheating because technically getpid returns pid_t on my system, but that's just an integer. FFI seems to have an awful lot of special cased code for getpid, so I suspect it's ease of use will correspond directly to whether FFI has already taken care of it. Trivial examples are trivial. It would be interesting to see what happens when typical complications arise, such as functions that return pre-allocated memory and have odd types and throw around structs.

While FFI and Inline::C can be used to do the same thing, how they do it looks very, very different. Inline::C is actually compiling and caching C code. FFI is somehow not doing any compiling. I'm not sure if that's really for real, or if the compilation is done for you at install time for common libraries.

In addition, FFI smooths the portability problems across the various Ruby implementations and their different ways of calling native APIs. This is something Inline::C doesn't have to do, and quite frankly it's amazing if it really works. One benefit is the FFI interface is much smoother than Inline::C. With Inline::C, it's very clear that you're writing a wrapper around a C compiler.

like image 169
Schwern Avatar answered Sep 20 '22 15:09

Schwern


With FFI it's very easy to extend Ruby with C. This is an example from github

require 'rubygems'
require 'ffi'
module Foo
  extend FFI::Library
  ffi_lib FFI::Library::LIBC
  attach_function :getpid, [ ], :int
end
puts "My pid=#{Foo.getpid}"

You don’t need a compiler installed on your system to be able to run FFI extensions. On linux, you also do not need to install the development versions of libraries, just the runtime versions. Of course, the libraries you link against will need to have been compiled at some point, but odds are you won’t have had to do it.

https://github.com/ffi/ffi/wiki/why-use-ffi

like image 38
Vasiliy Ermolovich Avatar answered Sep 17 '22 15:09

Vasiliy Ermolovich