我有一些现有的 C++ 代码可以在独立的 C++ 应用程序中进行数值处理。我现在想在新的 node.js 应用程序中使用该代码。
研究如何从node.js访问C++代码,有两个选择:
node-ffi 似乎是访问现有 libraries 的好选择,但我是否正确地认为如果我使用 node-ffi 我必须编写一个 C 包装器以使我的 C++ 可访问? (这是我在 Windows 上使用 Visual Studio 获得简单测试用例的唯一方法)。
对于我的源代码已经是 C++ 而不是 C 的情况,在上述两个选项之间进行选择时有哪些注意事项?
最佳答案
FFI 与动态 C 库一起使用。这意味着您必须在外部公开您的动态库。在 C++ 中,您可以使用 extern "C"执行此操作,如下所示:
#ifdef __cplusplus
extern "C" {
#endif
int foo (int param){
int ret = 0;
// do C++ things
return ret;
}
int bar(){
int ret = 0;
// do C++ things
return ret;
}
#ifdef __cplusplus
}
#endif
这将使您的 C++ 函数可用于 C 事物,作为动态库方法。
在将 C++ 库编译为 libmylibrary.dll/.so 后,以下是在 javascript 中包装它的方法:
var ffi = require('ffi');
var mylibrary = ffi.Library('libmylibrary', {
"foo": [ "int", ["int"] ],
"bar": [ "int", [] ]
});
您可以做很多更酷的事情。看看吧,here
如果这是一个 Node 库,只需将您的方法放在 module.exports 中。以下是上述 C++ 代码包装的完整示例,带有同步和异步方法:
var ffi = require('ffi');
var mylibrary = ffi.Library('libmylibrary', {
"foo": [ "int", ["int"] ],
"bar": [ "int", [] ]
});
module.exports = {
fooSync : mylibrary.foo,
foo: mylibrary.foo.async,
barSync : mylibrary.bar,
bar: mylibrary.bar.async
};
我没用过node-ffi-generate ,但是为您生成这些包装器看起来很酷。
如果我将此文件保存为 mylibrary.js,我可以这样使用它:
var mylib = require('./mylibrary.js');
var num = mylib.fooSync(1);
// or
mylib.foo(1, function(er, num){
});
至于“更好吗?”的问题。我想是的,对于大多数事情。如果你让你的方法外部 C,它们几乎可以在所有其他语言中工作,其中一些也有 FFI,所以你可以用任何你的目标语言编写上面的简单等价物。这意味着需要维护的代码很少,除了基本的“加载 C++ 库”和“弄乱它的签名以感觉适合语言 X”。它不是特定于 Node 的。另一个好处是常见的共享库(如教程示例中给出的 sqlite)。您可能并不关心他们拥有的确切版本,或者想用更多的 C++ 代码包装它,需要编译才能使用它。使用 FFI,您可以仅使用 javascript 包装预编译/安装的库。
关于c++ - 用于访问现有 C++ 功能的 node-ffi 与 node 扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16783023/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
当我使用has_one时,它工作得很好,但在has_many上却不行。在这里您可以看到object_id不同,因为它运行了另一个SQL来再次获取它。ruby-1.9.2-p290:001>e=Employee.create(name:'rafael',active:false)ruby-1.9.2-p290:002>b=Badge.create(number:1,employee:e)ruby-1.9.2-p290:003>a=Address.create(street:"123MarketSt",city:"SanDiego",employee:e)ruby-1.9.2-p290
我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。