mitchellh / go-mruby Goto Github PK
View Code? Open in Web Editor NEWGo (golang) bindings to mruby.
Home Page: https://gist.github.com/mitchellh/90029601268e59a29e64e55bab1c5bdc
License: MIT License
Go (golang) bindings to mruby.
Home Page: https://gist.github.com/mitchellh/90029601268e59a29e64e55bab1c5bdc
License: MIT License
Any thoughts or hints to solve this.
dweb@dweb-linux go-mruby (master) $ go build ~/source/go/src/github.com/mitchellh/go-mruby
# github.com/mitchellh/go-mruby
libmruby.a(numeric.o): In function `flo_floor':
./vendor/mruby/src/numeric.c:486: undefined reference to `floor'
libmruby.a(numeric.o): In function `flo_truncate':
./vendor/mruby/src/numeric.c:606: undefined reference to `floor'
./vendor/mruby/src/numeric.c:607: undefined reference to `ceil'
libmruby.a(numeric.o): In function `flo_round':
./vendor/mruby/src/numeric.c:575: undefined reference to `floor'
./vendor/mruby/src/numeric.c:579: undefined reference to `ceil'
libmruby.a(numeric.o): In function `flo_ceil':
./vendor/mruby/src/numeric.c:511: undefined reference to `ceil'
libmruby.a(numeric.o): In function `flodivmod':
./vendor/mruby/src/numeric.c:273: undefined reference to `fmod'
libmruby.a(numeric.o): In function `num_pow':
./vendor/mruby/src/numeric.c:56: undefined reference to `pow'
libmruby.a(numeric.o): In function `flodivmod':
./vendor/mruby/src/numeric.c:273: undefined reference to `fmod'
./vendor/mruby/src/numeric.c:273: undefined reference to `fmod'
./vendor/mruby/src/numeric.c:273: undefined reference to `fmod'
libmruby.a(numeric.o): In function `mrb_flo_to_str':
./vendor/mruby/src/numeric.c:144: undefined reference to `log10'
./vendor/mruby/src/numeric.c:153: undefined reference to `pow'
./vendor/mruby/src/numeric.c:166: undefined reference to `pow'
./vendor/mruby/src/numeric.c:167: undefined reference to `floor'
libmruby.a(math.o): In function `math_erfc':
./vendor/mruby/mrbgems/mruby-math/src/math.c:623: undefined reference to `erfc'
libmruby.a(math.o): In function `math_erf':
./vendor/mruby/mrbgems/mruby-math/src/math.c:605: undefined reference to `erf'
libmruby.a(math.o): In function `math_hypot':
./vendor/mruby/mrbgems/mruby-math/src/math.c:588: undefined reference to `hypot'
libmruby.a(math.o): In function `math_cbrt':
./vendor/mruby/mrbgems/mruby-math/src/math.c:523: undefined reference to `cbrt'
libmruby.a(math.o): In function `math_sqrt':
./vendor/mruby/mrbgems/mruby-math/src/math.c:480: undefined reference to `sqrt'
libmruby.a(math.o): In function `math_log10':
./vendor/mruby/mrbgems/mruby-math/src/math.c:462: undefined reference to `log10'
libmruby.a(math.o): In function `math_log2':
./vendor/mruby/mrbgems/mruby-math/src/math.c:440: undefined reference to `log2'
libmruby.a(math.o): In function `math_log':
./vendor/mruby/mrbgems/mruby-math/src/math.c:415: undefined reference to `log'
./vendor/mruby/mrbgems/mruby-math/src/math.c:417: undefined reference to `log'
libmruby.a(math.o): In function `math_exp':
./vendor/mruby/mrbgems/mruby-math/src/math.c:388: undefined reference to `exp'
libmruby.a(math.o): In function `math_atanh':
./vendor/mruby/mrbgems/mruby-math/src/math.c:354: undefined reference to `atanh'
libmruby.a(math.o): In function `math_acosh':
./vendor/mruby/mrbgems/mruby-math/src/math.c:337: undefined reference to `acosh'
libmruby.a(math.o): In function `math_asinh':
./vendor/mruby/mrbgems/mruby-math/src/math.c:320: undefined reference to `asinh'
libmruby.a(math.o): In function `math_tanh':
./vendor/mruby/mrbgems/mruby-math/src/math.c:297: undefined reference to `tanh'
libmruby.a(math.o): In function `math_cosh':
./vendor/mruby/mrbgems/mruby-math/src/math.c:279: undefined reference to `cosh'
libmruby.a(math.o): In function `math_sinh':
./vendor/mruby/mrbgems/mruby-math/src/math.c:262: undefined reference to `sinh'
libmruby.a(math.o): In function `math_atan2':
./vendor/mruby/mrbgems/mruby-math/src/math.c:239: undefined reference to `atan2'
libmruby.a(math.o): In function `math_atan':
./vendor/mruby/mrbgems/mruby-math/src/math.c:209: undefined reference to `atan'
libmruby.a(math.o): In function `math_acos':
./vendor/mruby/mrbgems/mruby-math/src/math.c:192: undefined reference to `acos'
libmruby.a(math.o): In function `math_asin':
./vendor/mruby/mrbgems/mruby-math/src/math.c:175: undefined reference to `asin'
libmruby.a(math.o): In function `math_tan':
./vendor/mruby/mrbgems/mruby-math/src/math.c:154: undefined reference to `tan'
libmruby.a(math.o): In function `math_cos':
./vendor/mruby/mrbgems/mruby-math/src/math.c:137: undefined reference to `cos'
libmruby.a(math.o): In function `math_sin':
./vendor/mruby/mrbgems/mruby-math/src/math.c:119: undefined reference to `sin'
collect2: error: ld returned 1 exit status
dweb@dweb-linux go-mruby (master) $ ~/source/go/src/github.com/mitchellh/go-mruby 2 โต
dweb@dweb-linux go-mruby (master) $ go test ~/source/go/src/github.com/mitchellh/go-mruby 2
Hi there, i'm just trying a kinda simple code that involves go routines:
// main.go
package main
import (
"github.com/mitchellh/go-mruby"
"sync"
)
func main() {
mrb := mruby.NewMrb()
defer mrb.Close()
var wg sync.WaitGroup
for i := 1; i < 50000; i++ {
wg.Add(1)
go func() {
mrb.LoadString("puts 'hola mundo'")
wg.Done()
}()
}
wg.Wait()
after doing go run main.go
it starts to print the messages as expected but after a while it raise a fatal error:
fatal error: unexpected signal during runtime execution
fatal error: schedule: holding locks
panic during panic
[signal SIGSEGV: segmentation violation code=0x1 addr=0x1357b900160 pc=0x55e9799579c9]
it seems like at some point something really bad is happening inside the Mrb struct, and it just starts crashing over and over again.
my go version is go1.7.4 linux/amd64
running in a Debian 9.1 (stretch)
I'm not sure if this is mruby or us, but here's a trace:
fatal error: exitsyscall: syscall frame is no longer valid
runtime stack:
runtime.throw(0x84679e, 0x2d)
/usr/local/go/src/runtime/panic.go:566 +0x95
runtime.exitsyscall.func1()
/usr/local/go/src/runtime/proc.go:2470 +0x36
runtime.systemstack(0x7ffe3ea0c490)
/usr/local/go/src/runtime/asm_amd64.s:298 +0x79
runtime.mstart()
/usr/local/go/src/runtime/proc.go:1079
goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x7108e0, 0xc4201e0fd0, 0xc400000000)
/usr/local/go/src/runtime/cgocall.go:131 +0x110 fp=0xc4201e0f88 sp=0xc4201e0f48
github.com/erikh/box/vendor/github.com/mitchellh/go-mruby._C2func_mrb_load_file(0x14ae400, 0x14cbc90, 0x0, 0x0, 0x0, 0x0)
??:0 +0x72 fp=0xc4201e0fd0 sp=0xc4201e0f88
github.com/erikh/box/vendor/github.com/mitchellh/go-mruby.(*Mrb).LoadFile(0xc420084370, 0xc4200107d0, 0x9, 0x0, 0x0, 0x0)
/home/erikh/src/github.com/erikh/box/vendor/github.com/mitchellh/go-mruby/mruby.go:196 +0x219 fp=0xc4201e10b0 sp=0xc4201e0fd0
github.com/erikh/box/builder.(*Builder).Load(0xc420245000, 0xc4200107d0, 0x9, 0x1, 0x1, 0x0)
/home/erikh/src/github.com/erikh/box/builder/builder.go:115 +0x43 fp=0xc4201e10f0 sp=0xc4201e10b0
box is my project, and it just calls LoadFile there.
Hello, and thanks for the awesome work on this project!
I'm interested in using go-mruby to create a go application in which third parties can extend the functionality by writing little ruby extensions.
To get a basic idea of how this all works, I tried to re-create irb with the following code:
import (
"bufio"
"fmt"
"github.com/mitchellh/go-mruby"
"os"
)
func main() {
mrb := mruby.NewMrb()
for {
reader := bufio.NewReader(os.Stdin)
fmt.Print("irb> ")
text, _ := reader.ReadString('\n')
result, err := mrb.LoadString(text)
if err != nil {
panic(err)
}
fmt.Printf("%s\n", result.String())
}
}
Trying out some basic stuff:
$ go run main.go
irb> self
main
irb> self.class
Object
irb> a = 3
3
irb> puts a
panic: undefined method 'a' for main
goroutine 1 [running]:
main.main()
/home/p0tash/Development/Go/src/github.com/hkparker/mrubytest/main.go:19 +0x289
exit status 2
hmm. Didn't seem to hold on to the reference to "a" between iterations of LoadString. For comparison, here's regular irb, which behaves as we'd all expect of course.
$ irb
irb(main):001:0> self
=> main
irb(main):002:0> self.class
=> Object
irb(main):003:0> a = 3
=> 3
irb(main):004:0> a
=> 3
Next I thought to try passing this reference in one call to LoadString.
$ go run main.go
irb> a = 3; puts a
3
irb>
So no panic, but we see the call to puts emitted a new line without printing the expected 3
.
My guess is that I'm using this library wrong, and that to access (or create) "a" (or anything else), I should be interacting with the ruby VM via go calls and not loading ruby strings. But I don't get why this also doesn't work.
Can anyone explain what's going on here, and why the above code isn't working as I'd expect it to?
I've cloned this project into $GOPATH/src/go-mruby
and run make
, which went swimmingly. Then I ran go install
so that it got copied into $GOPATH/pkg/linux_amd64
.
Next, I created another dir an pasted the example code (from README
) into the main
pkg, located at $GOPATH/src/gorbtest/main.go
.
When I attempt to go build
the test pkg, it complains like so:
/home/akshay/.gimme/versions/go1.5.1.linux.amd64/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
gcc: error: libmruby.a: No such file or directory
I use gimme
to manage the go version (and hence the nonstandard $GOROOT
), but that shouldn't make a difference, correct?
My $GOPATH
seems to have a go-mruby.a
after I go install
in go-mruby, so that should be used by whatever I'm trying to build, right? What am I missing?
Is there any trick to getting mrbgem defined classes to be available?
Adding (for instance) conf.gem :git => 'https://github.com/iij/mruby-regexp-pcre.git'
to the build_config.rb , the make
output reports that it should be available:
Config Name: host
Output Directory: build/host
Binaries: mrbc
Included Gems:
mruby-erb - Direct ERB port from CRuby
mruby-regexp-pcre
...
And it's available in mirb
:
$ echo "Regexp.methods" | vendor/mruby/build/host/bin/mirb
mirb - Embeddable Interactive Ruby Shell
> => [:instance_of?, :instance_eval, :_inspect, :instance_variable_get, :instance_variable_defined?, :instance_variable_set, :instance_variables, :Hash, :to_enum, :is_a?, :kind_of?, :method_missing, :protected_methods, :last_match, :`, :new, :private_methods, :initialize, :object_id, :quote, :methods, :!, :class_variable_get, :respond_to?, :attr_accessor, :send, :class_variable_defined?, :attr, :loop, :inherited, :public_methods, :remove_instance_variable, :superclass, :!=, :prepended, :prepend_features, :==, :escape, :instance_exec, :include, :__send__, :include?, :tap, :__id__, :extend_object, :proc, :iterator?, :class_variable_set, :local_variables, :raise, :prepend, :p, :extended, :singleton_class, :printf, :module_eval, :initialize_copy, :module_function, :hash, :format, :sprintf, :extend, :instance_methods, :__printstr__, :method_defined?, :equal?, :dup, :included_modules, :included, :eql?, :Integer, :srand, :rand, :class_eval, :class, :append_features, :puts, :clone, :to_s, :inspect, :alias_method, :ancestors, :const_defined?, :undef_method, :const_set, :const_get, :public, :__method__, :remove_class_variable, :private, :protected, :attr_writer, :lambda, :String, :attr_reader, :method_removed, :fail, :remove_method, :print, :block_given?, :global_variables, :enum_for, :compile, :nil?, :Array, :"!~", :class_variables, :===, :__case_eqq, :define_method, :Float, :const_missing, :singleton_methods, :remove_const, :constants, :define_singleton_method]
But it is not available in the mrb context created by go-mruby with the following snippet:
mrb := mruby.NewMrb()
defer mrb.Close()
result, _ := mrb.LoadString(`Regexp.methods`)
fmt.Printf("Result: %s\n", result.String())
The output is:
panic: uninitialized constant Regexp
goroutine 1 [running]:
main.main()
/home/mike/go/src/github.com/mikesimons/templateer/main.go:61 +0x100
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1696 +0x1
I appreciate this may be me being thick headed but I've successfully managed to work with mruby in C (here https://github.com/mikesimons/templateer) and go-mruby is not behaving as the C counterpart does even though initialization steps seem to be (more or less) the same.
In the C version above, mrbgem defined classes are simply available as if they were part of stdlib.
Need to fix the build script.
Hello,
where would be the best place to find an example or indication of how go-mruby can be used to call Go code from Ruby?
Whats the current situation with this project?
It seems like there has not been much activity in the recent year.
Is everyone just happy how it is or is there no interest in updating this project?
Are there any plans to upgrade to mruby 3.0.0?
I would appreciate a short statement about the future plans for this project ๐
I read the doc, use Hash.Get
to access values, but I can't find a way to convert to Symbol
.
The readme fails to mention the following dependencies which need to be installed:
Hi guys, looks like tests doesn't pass after go1.10 update:
Checking code with gofmt..
gofmt -s *.go >/dev/null
sh golint.sh
Installing golint into your GOPATH...
Checking with golint...
go test -v
# github.com/DamnWidget/aim/vendor/github.com/mitchellh/go-mruby
./array_test.go:38: Fatalf format %s has arg valType of wrong type mruby.ValueType
./hash_test.go:33: Fatalf format %s has arg valType of wrong type mruby.ValueType
./hash_test.go:58: Fatalf format %s has arg value.Type() of wrong type mruby.ValueType
./parser_test.go:19: Fatalf format %s has arg warns of wrong type []*mruby.ParserMessage
./parser_test.go:44: Fatalf format %s has arg warns of wrong type []*mruby.ParserMessage
./value_test.go:245: Fatalf format %s has arg cType of wrong type mruby.ValueType
FAIL github.com/DamnWidget/aim/vendor/github.com/mitchellh/go-mruby [build failed]
make: *** [Makefile:27: test] Error 2```
If not it'd be nice to have this as well.
Simple reproducer added to mruby_test.go
.
func TestMrbYieldException(t *testing.T) {
mrb := NewMrb()
defer mrb.Close()
cb := func(m *Mrb, self *MrbValue) (Value, Value) {
result, err := m.Yield(m.GetArgs()[0])
if err != nil {
exc := err.(*mruby.Exception)
return nil, exc
}
return result, nil
}
class := mrb.DefineClass("Hello", mrb.ObjectClass())
class.DefineClassMethod("foo", cb, ArgsBlock())
_, err := mrb.LoadString(`Hello.foo { raise "exception" }`)
if err == nil {
t.Fatalf("expected err")
}
}
This will consistently crash the go runtime with something like this:
runtime: newstack sp=0xc82003ada0 stack=[0xc82003a000, 0xc82003afd0]
morebuf={pc:0x4092559 sp:0xc82003ada8 lr:0x0}
sched={pc:0x409372d sp:0xc82003ada0 lr:0x0 ctxt:0x0}
It appears an exception might get thrown and the go -> ruby -> go -> ruby seems to cause a problem. You can also reproduce it by calling m.LoadString("raise 'exception'")
from inside of the function call.
So technically this isn't open source :( could you plz add a license?
As per the initial comment on #21 I noticed that Decode
will not handle quite a few common cases where there may need to be some basic coercions.
Of particular note in reference to #21 is the fact that a nil
in any value coming from mruby will fail at one of the unknown type
checks.
For nil
specifically I think that using zero types would be most appropriate.
But there are additional cases that it would be nice to handle for completeness.
Some examples:
I propose a table of coercions is produced on this issue and an implementation can stem from that.
As per the discussion on #24, these types wrap the low level mruby types which bypass the []
, []=
etc methods that ruby users may expect to work.
Raised here so it is not forgotten.
while delving into a few bugs I realized that this was a huge issue moving forward, basically the whole notion of a target_class is hidden behind opaque interfaces, which destroys how we couple go and mruby code.
It looks like the solution is just to start using the new proc constructors, but I haven't dug in yet; am not entirely sure when I will have the time to, so recording here.
I'm trying to pass long strings using m.LoadString("...")
, and hit error like:
line 1:552695: string too long (truncated)
I've looked at the code, and found a seemingly non-configurable constant:
include/mruby/compile.h:#define MRB_PARSER_BUF_SIZE 1024
I guess changing MRB_PARSER_BUF_SIZE
to a very big number would work, but it's still gonna be a fixed number and I can imagine this is a statically allocated buffer and it's really dull.
The question is: what's the better way to return a long string as a value without resizing parser buffer? Is there a chunked parser mode of sorts?
I want to execute compiled mruby code.
For that, I think that support of the LoadIrepFile() function is necessary.
Hi,
Building the library fails as follows:
go-mruby git:(master) go build
# github.com/mitchellh/go-mruby
./array.go:15:13: could not determine kind of name for C.mrb_ary_len
A commit to MRuby from 2017 (67e2dddb8254fbf4a4eb81c1241ec1963bc77627
) seems to have introduced the following change:
Remove `mrb_ary_len` function. Use `RARRAY_LEN` instead.
Wondering why it hasn't caused problems for anyone else. Am I doing something stupid?
Go: 1.11.5
Mruby: 2.0.0
I've not yet been able to find what's the simplest way to reproduce this, but I am able to hit this with my project, which you can compile like this:
go get github.com/Masterminds/glide
go get -d github.com/errordeveloper/kubeplay
cd $GOPATH/src/github.com/errordeveloper/kubeplay
$GOPATH/bin/glide up
make -C vendor/github.com/mitchellh/go-mruby libmruby.a
go install ./rubykube
go build .
Create empty kubeconfig
:
kind: Config
apiVersion: v1
preferences: {}
clusters:
- cluster:
server: https://localhost:8443
name: test
contexts:
- context:
cluster: test
user: test
name: test
current-context: test
users:
- name: test
user: {}
Start kubeplay
and call pods []
:
> ./kubeplay -kubeconfig ./kubeconfig
kubeplay (namespace="*")> pods []
+++ Execute: pods
args=[]
fatal error: exitsyscall: syscall frame is no longer valid
I don't know if this is a bug or just a general misunderstanding of how the bindings work, but consider the following:
// run is a simple go function that returns a syntax error
func run() error {
mrb := mruby.NewMrb()
defer mrb.Close()
_, err := mrb.LoadString(`clearly a syntax error`)
if err != nil {
return err
}
return nil
}
// Test just executes run and tries to print the result
func TestFuck(t *testing.T) {
err := run()
if err != nil {
println(fmt.Sprintf("err: %s", err))
}
}
This will, 100% of the time, panic. The resulting panic text does vary slightly, but they all seem to indicate that, upon closing mrb
, any errors or return values are GCed, meaning it is not possible to blindly return an error as above in standard go-like behavior.
My current workaround is to basically copy the error:
if err != nil {
err = errors.New(err.Error())
return err
}
Which seems pretty non-optimized.
Even using the example in the README, introducing a syntax error and invoking from another function will cause a C-level panic.
Is this intended? Any workarounds?
The tests do things like LoadString("{}")
... is there a direct way for hashes and arrays?
cc @erikh
Consider the code example from the README:
addFunc := func(m *mruby.Mrb, self *mruby.MrbValue) (mruby.Value, mruby.Value) {
args := m.GetArgs()
return mruby.Int(args[0].Fixnum() + args[1].Fixnum()), nil
}
class := mrb.DefineClass("Example", nil)
class.DefineClassMethod("add", addFunc, mruby.ArgsReq(2))
result, err := mrb.LoadString(`Example.add(12, 30)`)
if err != nil {
panic(err.Error())
}
Even though the spec says that two arguments are required, if you call the function with less than two arguments:
result, err := mrb.LoadString(`Example.add(12)`)
it will panic (since the function is trying to access an index out of the range of the slice):
panic: runtime error: index out of range [recovered]
panic: runtime error: index out of range
and if you give it more than 2 args:
result, err := mrb.LoadString(`Example.add(12, 12, 12)`)
It happily adds the first two and completely ignores any other arguments.
Is it possible to have fixed location for external static linked file?
I tried to integrate go-mruby within my irc bot framework here https://github.com/fudanchii/sifr/compare/mruby-support?expand=1
but when I run go build
it looks like Go looking for the .a files at my project's root directory instead of go-mruby's
adie@millefeuille:sifr $ go build
# github.com/fudanchii/sifr
gcc: error: libmruby.a: No such file or directory
gcc: error: libcrypto.a: No such file or directory
/usr/lib/go/pkg/tool/linux_386/8l: running gcc failed: unsuccessful exit status 0x100
adie@millefeuille:sifr $
It works okay after I copied both libcrypto.a and libmruby.a manually. (using iij/mruby here since it's already embedded with some useful gems by default). But it will surely cumbersome to always manually copy both of the files in case I work with multiple projects
Maybe we can set a fixed path somewhere and let Go tools or Make
copy those files there?
Is there a way to use gems?
mrb := NewMrb()
defer mrb.Close()
proc, _ := mrb.LoadString(`
Proc.new do
puts 1
end
`)
val, err := mrb.Run(proc, nil)
fmt.Printf("%#v, %#v", val, err)
Expected: Prints "1", returns nil, nil
Actual: (_mruby.MrbValue)(nil), &mruby.Exception{MrbValue:(_mruby.MrbValue)(0xc8200920e0), cachedString:"unexpected return"}
For some reason mruby.Run
does not work with a Proc
returned from mruby.LoadString
. There may be good technical reasons (though I can't think of what they might be) but this surprised me. The error unexpected return
is also non-obvious as there is no return
injected anywhere AFAICT.
It is necessary to use something like the following to create a Proc
that works with mruby.Run
:
mrb := NewMrb()
defer mrb.Close()
parser := NewParser(mrb)
defer parser.Close()
context := NewCompileContext(mrb)
defer context.Close()
parser.Parse(`puts 1`, context)
proc := parser.GenerateCode()
val, err := mrb.Run(proc, nil)
fmt.Printf("%#v, %#v", val, err)
This works as expected. Drilling down in to the differences between the MrbValues generated with these two approaches should be sufficient to determine a cause (and potential solution).
At the very least I need Add(item *mruby.MrbValue)
. Is this is problematic or simply unimplemented as it was not needed?
cc @erikh
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.