neelance / ffi_gen Goto Github PK
View Code? Open in Web Editor NEWA generator for Ruby FFI bindings, directly from header files via LLVM's Clang compiler
License: MIT License
A generator for Ruby FFI bindings, directly from header files via LLVM's Clang compiler
License: MIT License
foo.h
#define FOO 123
#define BAR 456
require "ffi/gen"
FFI::Gen.generate(
module_name: "foo",
ffi_lib: "foo",
headers: ["foo.h"],
cflags: `/usr/local/Cellar/llvm/3.4.1/bin/llvm-config --cflags`.split(" "),
prefixes: [],
output: "foo.rb"
Result:
# Generated by ffi-gen. Please do not change this file by hand.
require 'ffi'
module foo
extend FFI::Library
ffi_lib 'foo'
def self.attach_function(name, *_)
begin; super; rescue FFI::NotFoundError => e
(class << self; self; end).class_eval { define_method(name) { |*_| raise e } }
end
end
FOO = 123
end
BAR
is nowhere to be found.
Maybe related:
http://lists.cs.uiuc.edu/pipermail/cfe-dev/2011-January/012983.html
#pragma GCC visibility push(default)
enum fun {
FOO,
BAR
};
#pragma GCC visibility pop
/Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:379:in `block in read_declaration': undefined method `raw' for nil:NilClass (NoMethodError)
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:372:in `each'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:372:in `read_declaration'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:346:in `block in declarations'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:338:in `each'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:338:in `each_with_index'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:338:in `declarations'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen/ruby_output.rb:10:in `block in generate_rb'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:150:in `indent'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen/ruby_output.rb:5:in `generate_rb'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:280:in `generate'
from /Library/Ruby/Gems/2.0.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:749:in `generate'
from foo.rb:3:in `<main>'
Is it possible to support /* */ comments?
For example you can see libssh2.h :)
getFieldOrder is required: http://twall.github.io/jna/3.5.1/javadoc/com/sun/jna/Structure.html
child[:kind]
in this case is :unexposed_attr
Can be fixed by regenerating bindings and changing ruby_output.rb:79
:
+ when :incomplete_array
+ element_type_data = to_ruby_type Clang.get_array_element_type(canonical_type)
+ [":pointer", "Array<#{element_type_data[:description]}>"]
I'm having trouble getting started using this tool on OSX:
LoadError: Could not open library 'libclang-3.5.so.1': dlopen(libclang-3.5.so.1, 5): image not found.
Could not open library 'libclang-3.5.so.1.dylib': dlopen(libclang-3.5.so.1.dylib, 5): image not found.
Could not open library 'libclang.so.1': dlopen(libclang.so.1, 5): image not found.
Could not open library 'libclang.so.1.dylib': dlopen(libclang.so.1.dylib, 5): image not found.
Could not open library 'clang': dlopen(clang, 5): image not found.
Could not open library 'libclang.dylib': dlopen(libclang.dylib, 5): image not found
I have installed llvm
via: brew install llvm --with-clang
on El Capitan, what am I missing?
Could you fix gemfile and readme to ffi_gen ?
This is necessary, as tests require a nontrivial set of external libraries, which aren't necessarily available on systems such as OS X.
See the discussion in #20 (comment).
It would be handy to generate separate files for each FFI::Struct
/ FFI::Union
. This would reduce the size of the primary generated file.
I had to edit some code for the generator to work and not sure what the effect of my code changes are, hence why this isn't a pull request
On OSX, I cloned libcouchbase and built it as per the instructions on that repo
Then I run the following in irb
:
require "ffi_gen"
FFIGen.generate(
module_name: "Libcouchbase::Ext",
ffi_lib: "libcouchbase",
headers: ["./include/libcouchbase/couchbase.h"],
# Needed the header stdarg.h which I found on my system here
cflags: ["-I/System/Library/Frameworks/Kernel.framework/Versions/A/Headers"],
prefixes: ["LCB_", "lcb_"],
output: "libcouchbase.rb"
)
The following code had errors:
# NoMethodError: undefined method `parts' for nil:NilClass
# from /Users/steve/.rvm/gems/ruby-2.1.5/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:447:in `read_declaration'
# -- I fixed ffi_gen.rb:447 by adding the && name
last_nested_declaration.name ||= Name.new(name.parts + field_name.parts) if last_nested_declaration && name
then
# NoMethodError: undefined method `to_ruby_classname' for nil:NilClass
# from /Users/steve/.rvm/gems/ruby-2.1.5/gems/ffi_gen-1.2.0/lib/ffi_gen/ruby_output.rb:134:in `ruby_name'
# -- I fixed ruby_output.rb:134 by adding the check for nil
@ruby_name ||= @name ? @name.to_ruby_classname : nil
Hopefully you find this useful and thanks for creating this awesome gem!
Trying to generate libuv, but with no luck
require 'ffi_gen'
FFIGen.generate(
module_name: "LibUV",
ffi_lib: "libuv",
headers: %w[
uv.h
],
cflags: `llvm-config --cflags`.split(" "),
prefixes: [],
output: "libuv.rb"
)
with llvm-3.5.0_2 installed on Yosemite
here is backtrace
/Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:328:in `block (2 levels) in read_named_declaration': undefined method `+' for nil:NilClass (NoMethodError)
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:319:in `catch'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:319:in `block in read_named_declaration'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:311:in `each'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:311:in `read_named_declaration'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:295:in `block in declarations'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:282:in `each'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:282:in `declarations'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen/ruby_output.rb:10:in `block in generate_rb'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:146:in `indent'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen/ruby_output.rb:5:in `generate_rb'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:238:in `generate'
from /Users/fazibear/.rubies/2.2.0/lib/ruby/gems/2.2.0/gems/ffi_gen-1.1.0/lib/ffi_gen.rb:479:in `generate'
I tried to generate .rb from libssh2.h (http://libssh2.org/download/libssh2-1.4.2.tar.gz)
But some definitions and macros are ignored.
Configuration for generation:
FFI::Gen.generate(
module_name: "LibSSH2",
ffi_lib: "libssh2",
headers: ["libssh2/include/libssh2.h"],
cflags: `llvm-config --cflags`.split(" "),
prefixes: ["libssh2_", "LIBSSH2"],
output: "libssh2/libssh2.rb"
)
For example the following definitions were ignored:
#define LIBSSH2_CHANNEL_WINDOW_DEFAULT (256*1024)
#define libssh2_channel_open_session(session) \
libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \
LIBSSH2_CHANNEL_WINDOW_DEFAULT, \
LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0)
It doesn't look like FFI-Gen currently generates bindings for functions defined inside extern "C" {}
blocks.
I'm not sure what I'm doing wrong, but I get an error while ffi-gen is trying to traverse declarations (I think). Here's my gen file:
require 'ffi/gen'
FFI::Gen.generate(
module_name: "Ncurses",
ffi_lib: "ncurses",
headers: ["/usr/include/ncurses.h"],
cflags: `/usr/local/Cellar/llvm/3.4.2/bin/llvm-config --cflags`.split(" "),
prefixes: ["_nc_", "NCURSES_", "WA_", "COLOR_", "ACS_"],
output: "ffi-ncurses.rb")
And here's the error I get running it:
~/projects/ffi-gen $ jruby -Ilib ncurses.rb
TypeError: wrong argument type NilClass (expected instance of FFI::Struct)
declarations at /Users/headius/projects/ffi-gen/lib/ffi/gen.rb:327
generate_rb at /Users/headius/projects/ffi-gen/lib/ffi/gen/ruby_output.rb:10
indent at /Users/headius/projects/ffi-gen/lib/ffi/gen.rb:150
generate_rb at /Users/headius/projects/ffi-gen/lib/ffi/gen/ruby_output.rb:5
generate at /Users/headius/projects/ffi-gen/lib/ffi/gen.rb:280
generate at /Users/headius/projects/ffi-gen/lib/ffi/gen.rb:742
(root) at ncurses.rb:3
JNA struct members appear without names:
public static class Blob extends Structure {
public NativeLong ;
public Pointer ;
}
The code says:
@fields.each do |field|
writer.puts "public #{field[:type].java_jna_type} #{field[:symbol]};"
end
I believe it should be something like:
@fields.each do |field|
writer.puts "public #{field[:type].java_jna_type} #{field[:name].raw};"
end
I like to put all typedef
, callback
and enum
definitions in a types.rb
file. I can then require the types.rb
in other files containing FFI::Struct
classes.
struct foo {
int length;
char data[];
}
Translates as:
class Foo < FFI::Struct
layout :length, :int,
:data, :pointer
end
However, this is incorrect. Data is not a pointer in the sense that memcpy(&f->data, bad, sizeof(void*))
would populate bad
with the pointer value. It would instead copy the first sizeof(void*)
bytes of the array. Thus, ffi gets a pointer with the first few bytes of the array as the value, which is invalid to dereference.
It appears that FFI lacks the support for [typ, length]
syntax in some contexts.
See ffi/ffi#385.
Example:
#define CONST_X 0L
is converted to
CONST_X = 0L
I'm using version ffi_gen (1.2.0)
This project is probably dead but I believe it is still worth reporting that that it fails for LLVM 3.9, 4.0, and 5.0. LLVM-3.8 works. It fails with the following stack trace when processing Core.h:
SyntaxError: (eval):1: syntax error, unexpected tCONSTANT, expecting end-of-input
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:401:in `eval'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:401:in `block in read_declaration'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:372:in `each'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:372:in `read_declaration'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:346:in `block in declarations'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:338:in `each'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:338:in `each_with_index'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:338:in `declarations'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen/ruby_output.rb:10:in `block in generate_rb'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:150:in `indent'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen/ruby_output.rb:5:in `generate_rb'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:280:in `generate'
/var/lib/gems/2.3.0/gems/ffi_gen-1.2.0/lib/ffi_gen.rb:745:in `generate'
The usual convention for FFI helper libs is to be called ffi-foo
and FFI::Foo
. Would it be possible to rename ffi_gen
to ffi-gen
?
Newest clang is 3.5.0. Could you fix the readme if you meant "At least 3.0"?
As seen here https://github.com/ffi/ffi/wiki/Structs#pointers-to-functions if a function returns a pointer to a struct, it should use SomeStruct.by_ref
as the return type. Otherwise, ffi returns an FFI::Pointer
.
Not sure if this is an issue with ffi-gen or not but when I try and run ffi-gen I get the following error:
`block in ffi_lib': Could not open library 'clang': /usr/lib/clang: cannot read file data: Is a directory. (LoadError)
Could not open library 'libclang.so': libclang.so: cannot open shared object file: No such file or directory
Mind helping me out? I'm on Ubuntu and installed clang with apt-get
but not sure what else i need to do to get it working.
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.