Skip to content

Commit

Permalink
Better support for wrapping C++ code inside C code using extern "C" l…
Browse files Browse the repository at this point in the history
…inkage.

Rename #compiler in #use_compiler.
Now #compiler returns the current compiler.
  • Loading branch information
Andrea Fazzi committed Dec 2, 2009
1 parent 0bb147b commit 5758675
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 27 deletions.
16 changes: 9 additions & 7 deletions lib/ffi-inliner/inliner.rb
Expand Up @@ -97,7 +97,7 @@ def cmd
end
end

class CPlusPlus < GCC
class GPlusPlus < GCC
def ldshared
if Config::CONFIG['target_os'] =~ /darwin/
'g++ -dynamic -bundle -fPIC'
Expand All @@ -122,14 +122,14 @@ def cmd
end

class Builder
attr_reader :code
attr_reader :code, :compiler
def initialize(mod, code = "", options = {})
make_pointer_types
@mod = mod
@code = code
@sig = [parse_signature(@code)] unless @code.empty?
options = { :compiler => Compilers::GCC }.merge(options)
@compiler = options[:compiler]
options = { :use_compiler => Compilers::GCC }.merge(options)
@compiler = options[:use_compiler]
end

def map(type_map)
Expand All @@ -146,14 +146,14 @@ def library(*libraries)

def c(code)
(@sig ||= []) << parse_signature(code)
@code << code
@code << (@compiler == Compilers::GPlusPlus ? "extern \"C\" {\n#{code}\n}" : code )
end

def c_raw(code)
@code << code
end

def compiler(compiler)
def use_compiler(compiler)
@compiler = compiler
end

Expand Down Expand Up @@ -208,14 +208,16 @@ def strip_comments(code)
# Based on RubyInline code by Ryan Davis
# Copyright (c) 2001-2007 Ryan Davis, Zen Spider Software
def parse_signature(code)

sig = strip_comments(code)

# strip preprocessor directives
sig.gsub!(/^\s*\#.*(\\\n.*)*/, '')
# strip {}s
sig.gsub!(/\{[^\}]*\}/, '{ }')
# clean and collapse whitespace
sig.gsub!(/\s+/, ' ')

# types = 'void|int|char|char\s\*|void\s\*'
types = @types.keys.map{|x| Regexp.escape(x)}.join('|')
sig = sig.gsub(/\s*\*\s*/, ' * ').strip
Expand Down
83 changes: 63 additions & 20 deletions spec/ffi-inliner/inliner_spec.rb
@@ -1,6 +1,6 @@
require File.expand_path(File.join(File.dirname(__FILE__), "../spec_helper"))

describe Inliner do
describe 'Inliner' do

before do
module Foo
Expand Down Expand Up @@ -75,7 +75,7 @@ module Foo

end

it 'should be configured using the block form' do
it 'should be configured using the block form' do
module Foo
inline do |builder|
builder.c %q{
Expand Down Expand Up @@ -159,23 +159,32 @@ module Foo
end
end
end

it 'should use different compiler as specified in the configuration block' do
module Foo
inline do |builder|
builder.compiler Inliner::Compilers::TCC
builder.use_compiler Inliner::Compilers::TCC
builder.c "int func_1() { return 1 + 1; }"
end
end
Foo.func_1.should == 2
end

# it 'should be configured using the hash form' do
# tcc = mock('tcc', :exists? => true, :compile => nil)
# Inliner::Compilers::TCC.should_receive(:new).and_return(tcc)
# module Foo
# inline "int func_1() { return 1; }", :compiler => Inliner::Compilers::TCC
# end
# end
it 'should return the current compiler' do
module Foo
inline do |builder|
builder.compiler.should == Inliner::Compilers::GCC
end
end
end

# it 'should be configured using the hash form' do
# tcc = mock('tcc', :exists? => true, :compile => nil)
# Inliner::Compilers::TCC.should_receive(:new).and_return(tcc)
# module Foo
# inline "int func_1() { return 1; }", :compiler => Inliner::Compilers::TCC
# end
# end

it 'should raise errors' do
lambda {
Expand All @@ -189,18 +198,52 @@ module Foo
end
}.should raise_error(/Compile error/)
end

end

describe Inliner::Compilers::Compiler do
before do
class DummyCC < Inliner::Compilers::Compiler
def cmd
"dummycc -shared"
describe 'Compiler' do
before do
class DummyCC < Inliner::Compilers::Compiler
def cmd
"dummycc -shared"
end
end
end
it 'should return the progname' do
DummyCC.new.progname.should == 'dummycc'
end
end
it 'should return the progname' do
DummyCC.new.progname.should == 'dummycc'
end

describe 'GPlusPlus compiler' do

it 'should compile and link a C shim library that encapsulates C++ code' do
module Foo
inline do |builder|
builder.use_compiler Inliner::Compilers::GPlusPlus
builder.c_raw <<-code
#include <iostream>
#include <string>
using namespace std;
class Greeter {
public:
Greeter();
string say_hello();
};
Greeter::Greeter() { };
string Greeter::say_hello() {
return "Hello foos!";
};
code
builder.c <<-code
const char* say_hello()
{
Greeter greeter;
return greeter.say_hello().c_str();
}
code
end
end
end

end

end

0 comments on commit 5758675

Please sign in to comment.