简体   繁体   English

在 C++ 应用程序中嵌入 Ruby 解释器

[英]Embedding a Ruby interpreter in a C++ app

I'm hoping to use Ruby as a scripting language for my game engine.我希望使用 Ruby 作为我的游戏引擎的脚本语言。 I've found the usual articles describing how to call Ruby classes from C++ code and vice versa (eg here ) but I can't quite see how to do what I want with that way of working...我找到了描述如何从 C++ 代码调用 Ruby 类的常用文章,反之亦然(例如这里),但我不太明白如何用这种工作方式做我想做的事......

My engine currently uses a little language I wrote myself with Flex and Bison, and a little stack based virtual machine.我的引擎目前使用一种我自己用 Flex 和 Bison 编写的小语言,以及一个基于堆栈的小虚拟机。 Scripts don't always run right through from start to finish, for instance they sometimes includes commands like "sleep for 2 seconds" or "wait until character has finished walking", so the scheduler keeps tabs on the status of each script and an instruction pointer, and knows when to resume them, and so on.脚本并不总是从头到尾运行,例如它们有时包含诸如“睡眠 2 秒”或“等待角色完成行走”之类的命令,因此调度程序会密切关注每个脚本的状态和指令指针,并知道何时恢复它们,等等。

So it seems that I really need some kind of embedded Ruby interpreter that I can exercise a certain degree of control over, rather than simply calling Ruby methods.所以看来我真的需要某种嵌入式 Ruby 解释器,我可以对其进行一定程度的控制,而不是简单地调用 Ruby 方法。 Or am I just being obtuse and missing something?还是我只是迟钝而遗漏了什么?

I'm working in Microsoft Visual C++, so ideally any solution would compile nice and easily in that.我在 Microsoft Visual C++ 工作,因此理想情况下,任何解决方案都可以很好地轻松编译。

Here's an example including error handling.这是一个包含错误处理的示例。

#include <iostream>
#include <ruby.h>

using namespace std;

int main(void)
{
  ruby_init();
  ruby_init_loadpath();
  int status;
  rb_load_protect(rb_str_new2("./test.rb"), 0, &status);
  if (status) {
    VALUE rbError = rb_funcall(rb_gv_get("$!"), rb_intern("message"), 0);
    cerr << StringValuePtr(rbError) << endl;
  };
  ruby_finalize();
  return status;
}

You're on the right track.你在正确的轨道上。 The key is to do something similar to the section on Embedding Concepts in the link you posted.关键是在您发布的链接中执行类似于嵌入概念部分的操作。 In simple terms it's little more than:简单来说,它只不过是:

ruby_init();
ruby_script("some_script");

You may need to copy over all the #ifdef stuff from main.c to get everything working.您可能需要从main.c复制所有#ifdef内容以使一切正常。 From then it's a matter of building an API to your C++ functions you want to expose, and depending on your design, multi-threading the thing.从那时起,只需将 API 构建到您想要公开的 C++ 函数,并根据您的设计,多线程处理。

You could always re-design the way the scripts work to suit the script engine rather than trying to get the engine to work with the original scripting paradigms.您总是可以重新设计脚本的工作方式以适应脚本引擎,而不是试图让引擎与原始脚本范例一起工作。

So, if you had this:所以,如果你有这个:

proc:
  action 1
  action 2
  sleep a bit
  action 3
end

which would require the script to be suspended on the sleep line, do this:这将需要将脚本挂起在睡眠线上,请执行以下操作:

proc
  action1
  action2
  set timer (time, callback_proc)
end

callback_proc
  action3
end

which lets the scripting engine finish each method neatly.这让脚本引擎可以巧妙地完成每个方法。 It wouldn't need many changes to the hosting side - each version requires some form of event system which can restart the script engine.它不需要对托管方进行太多更改 - 每个版本都需要某种形式的事件系统,可以重新启动脚本引擎。

There is a guide about how to embed ruby into a C++ application.有一个关于如何将 ruby 嵌入到 C++ 应用程序中的指南 That may be helpful.这可能会有所帮助。 Otherwise go to the Ruby documentation .否则 go 到Ruby 文档 The Embed Ruby in C article may be helpful, too.在 C 文章中嵌入 Ruby也可能会有所帮助。

I think what your going to want to do is use Ruby's threads.我认为您想要做的是使用 Ruby 的线程。 I've done a fair bit of digging through the Ruby threading code and I know that (where pthreads is available) sleep is implemented in a non-blocking fashion using pthread_cond_timedwait.我已经对 Ruby 线程代码进行了相当多的挖掘,并且我知道(在 pthreads 可用的地方)睡眠是使用 pthread_cond_timedwait 以非阻塞方式实现的。 This unblocks the interpreter so that other threads can continue execution.这会解除对解释器的阻塞,以便其他线程可以继续执行。

Your own code is going to have to respect Ruby's threads when it comes to interacting with the Ruby interpreter.在与 Ruby 解释器交互时,您自己的代码必须尊重 Ruby 的线程。 They've still got a Global VM Lock in Ruby which means you should be careful about modifying anything in the interpreter without having the lock yourself.他们在 Ruby 中仍然有一个全局 VM 锁,这意味着你应该小心修改解释器中的任何内容而不自己拥有锁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM