原生我的意思是用C ++或C
编写我正在编写一种基于Java的编程语言,因为它有一个VM和一个字节码编译器的语言。
实现语言的功能,例如for
循环,变量,算术等,对我来说不是问题;但是,执行像Java这样的本机函数是。
我需要原生函数,以便用我的语言编写的程序可以创建窗口,与硬件和操作系统接口,并做任何非简单数学的事情。
我听说过JNI,这看起来肯定是我想要的东西,但是,我不知道如何实现这样的东西。
由于我的VM是用C ++实现的,我知道在编译时我可以拥有本地函数的h #include
hpp文件,然后它可以动态加载dll
或{{然而,这并不是一个好的解决方案,因为每次你希望它能够执行另一个本机函数时你必须重新编译VM。
问题归结为:C ++程序(VM)如何动态地(在运行时,如字节码所指示的那样更加精确)使用C ++函数加载库,然后在不预先声明它们的情况下执行这些函数在一些头文件?
答案 0 :(得分:1)
看看libffi。它提供了在给定函数地址和调用签名的情况下调用任何函数的方法。
如何确定签名应该取决于您的上下文。您可以根据参数类型推断出各种调用。 JNA从显式Java接口,方法声明或动态调用参数中推断出本机调用签名。
超越简单的函数调用来处理构造函数,内存管理和对象方法调度更复杂,但仍然基于相同的基本原则。
答案 1 :(得分:0)
我未讨论的一个主题是如何将新语言VM函数调用中的参数传递给C ++堆栈,以及如何将返回值从C ++函数传递回VM。
假设您希望以新语言提供pow(3)功能。 提醒一下,pow()签名是
double pow ( double base, double power )
最简单的方法是这样的
void
language::pow( VM * pVM )
{
double arg2 = pVM->PopDouble();
double arg1 = pVM->PopDouble();
double result = pow( arg1, arg2 );
pVM->PushDouble( result );
}
但这听起来并不像你追求的那样。合并dlopen()& dlsym()得到你喜欢的东西
void
language::pow( VM * pVM )
{
double arg2 = pVM->PopDouble();
double arg1 = pVM->PopDouble();
void *handle = dlopen("libm", RTLD_LAZY);
if (!handle) { /*...return; ...*/ }
typedef double (* pfPow ) ( double, double );
pfPow pPow = (pfPow) dlsym(handle, "pow");
if (!pPow) { /*...return; ...*/ }
double result = (* pPow )( arg1, arg2 );
pVM->PushDouble( result );
}
但情况更糟。您仍希望语言能够访问每个C ++函数的存根函数。
听起来你希望你的语言有类似
的东西double result = eval_double( "libm", "pow", arg1, arg2 );
我不知道如何在C ++中实现它。 Varags支持获取任何类型的C ++参数。但是没有用于推送任意类型的C ++参数的API。