Skip to content

Updates for recent mruby. #33

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 30 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3fcd13e
Fixes for latest mruby.
take-cheeze May 28, 2015
28a2578
Suppress warning in assert call.
take-cheeze May 30, 2015
559f36f
Pack arguments in `cfunc_closure_call_binding`.
take-cheeze May 30, 2015
271269f
Replace deprecated macro.
take-cheeze Jun 24, 2015
82133f6
Fixes for latest mruby.
take-cheeze Mar 25, 2018
19faf9c
Remove unnecessary gems.
take-cheeze Mar 25, 2018
d6ef658
Fix pthread_cancel error.
take-cheeze Apr 3, 2018
cd491a2
Fix test build error.
take-cheeze Apr 3, 2018
e1aa465
Fix compile error in 1.3.
take-cheeze Apr 3, 2018
5669496
Remove unnecessary include.
take-cheeze Apr 3, 2018
5e25163
Fix travis build.
take-cheeze Apr 3, 2018
e6e69c0
Suppress warning.
take-cheeze Apr 5, 2018
4be424c
Fix zero division.
take-cheeze Apr 23, 2018
cda0977
Fix correct value.
take-cheeze Apr 23, 2018
a61df49
Fix dependencies.
take-cheeze Jun 21, 2018
d35eda4
Silence C++ warning in `test/main.c`.
matz Nov 20, 2018
014ed7c
Change `vector_swap()` argument type from `int` to `size_t`.
matz Nov 20, 2018
1fbc550
Avoid `namespace` C++ keyword from the source.
matz Nov 20, 2018
71e3f07
Separate `mrb_string_p` and `mrb_symbol_p`.
matz Nov 20, 2018
63dec30
Add type cast to the assignment from `void*`.
matz Nov 20, 2018
4ddf9a6
Reorder struct member initialization in declaration order of members.
matz Nov 20, 2018
e6d6ce5
`enum` should be declared outside of `struct` definition.
matz Nov 20, 2018
6835a39
Fixed bugs in the size of `mrb_malloc` allocation.
matz Nov 20, 2018
ac0384a
Move local variable declaration to the top of the function.
matz Nov 20, 2018
14f3299
2.1.2 remove mrb_run, replaced with mrb_top_run
Feb 19, 2021
d817f46
fixed building libffi
Feb 19, 2021
6864711
updated docs
Feb 19, 2021
46ecd12
Merge branch 'graf0-mgem' into mgem
matz Mar 5, 2021
ca6e9f5
cfunc_rubyvm.c: update for the recent mruby source.
matz Mar 5, 2021
840949a
.gitignore: exclude `.lock` files.
matz Mar 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ tmp
*.d
*.dSYM
*.a
*.lock

# Packages #
############
Expand Down
54 changes: 42 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@

Interface to C functions on mruby. it's based on [libffi](http://sourceware.org/libffi/).


## Build status

[![Build Status](https://secure.travis-ci.org/mobiruby/mruby-cfunc.png)](http://travis-ci.org/mobiruby/mruby-cfunc)


## Install

It's mrbgems.

When you use in your project, please add below to your ``build_config.rb``.
When you use in your project, please add below to your `build_config.rb`.

```ruby
conf.gem 'path/to/here' do |g|
# g.use_pkg_config # use pkg-config for libffi linking
# g.download_libffi # download and link latest libffi

# if your libffi is installed in a non standard path
# g.cc.include_paths << '[...]/include'
# g.linker.library_paths << '[...]/lib'
Expand All @@ -29,28 +27,60 @@ If you want to run tests, please run below command.

make test

## Windows

## Todo
To compile on windows you have to provie dlfcn-win32 libraray.

- install ruby from rubyinstaller.org - get newest with devkit, 64bit
- after installing run as admin:

`ridk install 1 2 3`

* Test!
* Improve error handling
* Support anonymous struct
* Examples
* Documents
- run msys2 console & install library:

`pacman -S mingw-w64-x86_64-dlfcn`

- active ridk ruby build system by adding at the top of you Rakefile line:

`ruby RubyInstaller::Runtime.enable_msys_apps `

- then add to your build_config.rb - to build libffi & link it staically:

```ruby
MRuby::Build.new do |conf|
toolchain :gcc
conf.gem mgem: "cfunc" do |gem|
gem.download_libffi
gem.linker.flags << "-static"
end

# ... rest of build_config.rb
end
```

- now you can build mruby with cfunc mgem! :)

## Todo

- Test!
- Improve error handling
- Support anonymous struct
- Examples
- Documents

## Contributing

Feel free to open tickets or send pull requests with improvements.
Thanks in advance for your help!


## Authors

Original Authors "MobiRuby developers" are [https://github.com/mobiruby/mobiruby-ios/tree/master/AUTHORS](https://github.com/mobiruby/mobiruby-ios/tree/master/AUTHORS)


## License

See Copyright Notice in [cfunc.h](https://github.com/mobiruby/mruby-cfunc/blob/master/include/cfunc.h).

```

```
43 changes: 43 additions & 0 deletions examples/windows_cfunc1.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module Win32
module User32
# win32 api compatibile version
# each libcall format is like this:
# - return tyupe
# - libraray
# - function to call
# - variable number of arguments to function
# - last param CFunc::Int.ew(X) - where X is number of arguments you pass above
DLL = CFunc.libcall(CFunc::Pointer, "kernel32.dll", "LoadLibraryA", "user32.dll", CFunc::Int.new(1))
MessageBeep = begin
ptr = CFunc.libcall(CFunc::Pointer, "kernel32.dll", "GetProcAddress", DLL, "MessageBeep", CFunc::Int.new(2))
CFunc::FunctionPointer.new(ptr).tap do |func|
func.arguments_type = [CFunc::UInt32]
func.result_type = CFunc::UInt32
end
end

MB_ICONASTERISK = 0x40

# shortcut version - it's a little bit slower, because it will try to open user32.dll again
MessageBox = proc do |text, caption, type|
CFunc.libcall(
CFunc::UInt32, # retrun type
"user32.dll", # dll
"MessageBoxA", # function
nil, text, caption, CFunc::Int.new(type), # args
CFunc::Int.new(4) # number of args
)
end

MB_OKCANCEL = 0x1
end
end

# then you can call MessageBeep like that
Win32::User32::MessageBeep.call(Win32::User32::MB_ICONASTERISK)

# if you want get return value:
ret = Win32::User32::MessageBeep.call(Win32::User32::MB_ICONASTERISK).value

# and calling shortcut version
Win32::User32::MessageBox.("MRuby MessageBox", "MRuby MessageBox", Win32::User32::MB_OKCANCEL)
13 changes: 7 additions & 6 deletions include/cfunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#include "mruby/value.h"

struct cfunc_state {
struct RClass *namespace;
struct RClass *ns;

struct RClass *type_class;
struct RClass *void_class;
Expand All @@ -57,19 +57,20 @@ struct cfunc_state {
static inline struct cfunc_state *
cfunc_state(mrb_state *mrb, struct RClass* obj)
{
mrb_value state;
if(obj == NULL) {
obj = (struct RClass*) mrb_object(mrb_vm_const_get(mrb, mrb_intern_cstr(mrb, "CFunc")));
obj = mrb_module_get(mrb, "CFunc");
}
mrb_value state = mrb_mod_cv_get(mrb, obj, mrb_intern_cstr(mrb, "cfunc_state"));
return (struct cfunc_state *)mrb_voidp(state);
state = mrb_mod_cv_get(mrb, obj, mrb_intern_lit(mrb, "cfunc_state"));
return (struct cfunc_state *)mrb_cptr(state);
}


static inline void
set_cfunc_state(mrb_state *mrb, struct RClass* klass, struct cfunc_state *state)
{
mrb_value mstate = mrb_voidp_value(mrb, state);
mrb_mod_cv_set(mrb, klass, mrb_intern_cstr(mrb, "cfunc_state"), mstate);
mrb_value mstate = mrb_cptr_value(mrb, state);
mrb_mod_cv_set(mrb, klass, mrb_intern_lit(mrb, "cfunc_state"), mstate);
}

#endif
2 changes: 2 additions & 0 deletions include/cfunc_closure.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ struct cfunc_closure_data {
mrb_value return_type;

void *closure_pointer;

int packed_args_size;
};

#define cfunc_closure_data_pointer(mrb, val) \
Expand Down
2 changes: 1 addition & 1 deletion include/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ void check_length(vector_p vec);
/* Destroy the vector and free all the memory associated with it. */
void destroy_vector(vector_p vec);
/* Swaps the pointers at indices i and j in the vector */
void vector_swap(vector_p vec, int i, int j);
void vector_swap(vector_p vec, size_t i, size_t j);


void vector_enqueue(vector_p vec, void* data);
Expand Down
53 changes: 33 additions & 20 deletions mrbgem.rake
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,51 @@ MRuby::Gem::Specification.new('mruby-cfunc') do |spec|
spec.license = 'MIT'
spec.authors = 'MobiRuby developers'

add_test_dependency 'mruby-print', core: 'mruby-print'
add_dependency 'mruby-enumerator', core: 'mruby-enumerator'

rubyvm1_rbx = "#{dir}/test/_rubyvm1.rbx"
rubyvm1_c = "#{build_dir}/test/_rubyvm1.c"
rubyvm1_o = rubyvm1_c.ext('o')
spec.test_objs << rubyvm1_o
spec.test_preload = "#{dir}/test/mobitest.rb"

file rubyvm1_o => rubyvm1_c
file rubyvm1_c => [rubyvm1_rbx, build.mrbcfile] do |t|
FileUtils.mkdir_p File.dirname t.name
open(rubyvm1_c, 'w') do |f|
f.puts '#include <stdint.h>'
build.mrbc.run f, rubyvm1_rbx, 'mruby_data__rubyvm1'
end
end

def spec.use_pkg_config(pkg_config='pkg-config')
self.linker.flags << `"#{pkg_config}" libffi --libs-only-L --libs-only-other`.chomp
[self.cc, self.cxx, self.objc, self.mruby.cc, self.mruby.cxx, self.mruby.objc].each do |cc|
cc.include_paths << `"#{pkg_config}" libffi --cflags`.chomp
cc.flags << `"#{pkg_config}" libffi --cflags`.chomp
end
end

def spec.download_libffi(libffi_version = '3.0.13', tar = 'tar')
def spec.download_libffi(libffi_version = '3.3', tar = 'tar')
libffi_url = "ftp://sourceware.org/pub/libffi/libffi-#{libffi_version}.tar.gz"
libffi_build_root = "build/libffi/#{build.name}"
libffi_build_root = "#{MRUBY_ROOT}/build/libffi/#{build.name}"
libffi_dir = "#{libffi_build_root}/libffi-#{libffi_version}"
libffi_a = "#{libffi_dir}/lib/libffi.a"

unless File.exists?(libffi_a)
puts "Downloading #{libffi_url}"
open(libffi_url, 'r') do |ftp|
URI.open(libffi_url, 'rb') do |ftp|
libffi_tar = ftp.read
puts "Extracting"
FileUtils.mkdir_p libffi_build_root
IO.popen("#{tar} xfz - -C #{filename libffi_build_root}", 'w') do |f|
IO.popen("#{tar} xfz - -C #{filename libffi_build_root}", 'wb') do |f|
f.write libffi_tar
end
puts "Done"
end
sh %Q{(cd #{filename libffi_dir} && CC=#{build.cc.command} CFLAGS="#{build.cc.all_flags.gsub('\\','\\\\').gsub('"', '\\"')}" ./configure --prefix=`pwd` && make clean install)}
Dir.chdir(filename libffi_dir) do
sh %Q{env CC=#{build.cc.command} CFLAGS="#{build.cc.all_flags.gsub('\\', '\\\\').gsub('"', '\\"')}" ./configure --prefix="#{Dir.pwd}" && make clean install}
end
end

self.linker.library_paths << File.dirname(libffi_a)
Expand All @@ -37,6 +57,13 @@ MRuby::Gem::Specification.new('mruby-cfunc') do |spec|
end
end

if spec.respond_to?(:search_package) && spec.search_package('libffi')
spec.linker.libraries << 'pthread' << 'dl'
spec.cc.flags << %w(-pthread)
spec.linker.flags << "-Wl,--export-dynamic,--dynamic-list=#{spec.dir}/test/func.txt"
next
end

spec.linker.libraries << %w(ffi dl pthread)

if ENV['OS'] == 'Windows_NT'
Expand All @@ -55,19 +82,5 @@ MRuby::Gem::Specification.new('mruby-cfunc') do |spec|
# spec.objs << ["#{LIBFFI_DIR}/lib/libffi.a"]
# spec.test_rbfiles = Dir.glob("#{dir}/test/*.rb")
# spec.test_objs = Dir.glob("#{dir}/test/*.{c,cpp,m,asm,S}").map { |f| f.relative_path_from(dir).pathmap("#{build_dir}/%X.o") }
spec.test_preload = "#{dir}/test/mobitest.rb"

rubyvm1_rbx = "#{dir}/test/_rubyvm1.rbx"
rubyvm1_c = "#{build_dir}/test/_rubyvm1.c"
rubyvm1_o = rubyvm1_c.ext('o')
spec.test_objs << rubyvm1_o

file rubyvm1_o => rubyvm1_c
file rubyvm1_c => rubyvm1_rbx do |t|
open(rubyvm1_c, 'w') do |f|
f.puts '#include <stdint.h>'
build.mrbc.run f, rubyvm1_rbx, 'mruby_data__rubyvm1'
end
end

end
4 changes: 2 additions & 2 deletions run_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@

MRuby::Build.new do |conf|
toolchain :gcc
conf.gembox 'default'
# conf.gembox 'default'

conf.gem "#{root}/mrbgems/mruby-eval"
# conf.gem "#{root}/mrbgems/mruby-eval"

conf.gem File.expand_path(File.dirname(__FILE__)) do |g|
# g.use_pkg_config
Expand Down
15 changes: 8 additions & 7 deletions src/cfunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,22 +45,23 @@ void
mrb_mruby_cfunc_gem_init(mrb_state* mrb)
{
struct RClass *ns = mrb_define_module(mrb, "CFunc");
struct cfunc_state *state = mrb_malloc(mrb, sizeof(struct cfunc_state));
struct cfunc_state *state = (struct cfunc_state*)mrb_malloc(mrb, sizeof(struct cfunc_state));
int ai;
set_cfunc_state(mrb, ns, state);
state->namespace = ns;
state->ns = ns;

int ai = mrb_gc_arena_save(mrb);
ai = mrb_gc_arena_save(mrb);
init_cfunc_type(mrb, ns); mrb_gc_arena_restore(mrb, ai);
init_cfunc_pointer(mrb, ns); mrb_gc_arena_restore(mrb, ai);
init_cfunc_struct(mrb, ns); mrb_gc_arena_restore(mrb, ai);
init_cfunc_closure(mrb, ns); mrb_gc_arena_restore(mrb, ai);
init_cfunc_call(mrb, ns); mrb_gc_arena_restore(mrb, ai);
init_cfunc_rubyvm(mrb, ns); mrb_gc_arena_restore(mrb, ai);
init_cfunc_platform(mrb, ns); mrb_gc_arena_restore(mrb, ai);
init_cfunc_platform(mrb, ns); mrb_gc_arena_restore(mrb, ai);

mrb_define_class_method(mrb, ns, "mrb_state", cfunc_mrb_state, ARGS_NONE());
mrb_define_class_method(mrb, ns, "errno", cfunc_errno, ARGS_NONE());
mrb_define_class_method(mrb, ns, "strerror", cfunc_strerror, ARGS_NONE());
mrb_define_class_method(mrb, ns, "mrb_state", cfunc_mrb_state, MRB_ARGS_NONE());
mrb_define_class_method(mrb, ns, "errno", cfunc_errno, MRB_ARGS_NONE());
mrb_define_class_method(mrb, ns, "strerror", cfunc_strerror, MRB_ARGS_NONE());
}

void
Expand Down
Loading