【问题标题】:Run C Code Block in Erlang在 Erlang 中运行 C 代码块
【发布时间】:2011-04-01 07:50:39
【问题描述】:

如何从 Erlang 运行 C 代码块? (或者从erlang调用一个C函数?)

【问题讨论】:

    标签: c erlang


    【解决方案1】:

    这是用于创建驱动程序

    首先,您需要创建 C/C++ 文件来执行此操作。

    他们需要包括

    #include "erl_driver.h"
    #include "ei.h"
    

    然后你需要设置驱动映射

    /* mapping of the drivers functions */
    static ErlDrvEntry driver_entry = {
      NULL,                             /* init */
      startup_function_name,            /* startup  */
      shutdown_function_name,           /* shutdown */
      NULL,                             /* output */
      NULL,                             /* ready_input */
      NULL,                             /* ready_output */
      driver_name,                      /* the name of the driver */
      NULL,                             /* finish */
      NULL,                             /* handle */
      NULL,                             /* control */
      NULL,                             /* timeout */
      outputv_function_name,            /* outputv  */
      NULL,                             /* ready_async */
      NULL,                             /* flush */
      NULL,                             /* call */
      NULL,                             /* event */
      ERL_DRV_EXTENDED_MARKER,          /* ERL_DRV_EXTENDED_MARKER */
      ERL_DRV_EXTENDED_MAJOR_VERSION,   /* ERL_DRV_EXTENDED_MAJOR_VERSION */
      ERL_DRV_EXTENDED_MAJOR_VERSION,   /* ERL_DRV_EXTENDED_MINOR_VERSION */
      ERL_DRV_FLAG_USE_PORT_LOCKING     /* ERL_DRV_FLAGs */
    };
    
    DRIVER_INIT(driver_name){
       return &driver_entry;
    }
    

    注意:如果您尝试运行 C++ 代码而不是 C,则需要

    extern "C" {
      DRIVER_INIT(driver_name){
        return &driver_entry;
      }
    }
    

    您需要使用 (char *) 转换任何文字字符串

    那么最好定义一个包含端口信息的结构

    typedef struct
    {
      ErlDrvPort port;
    } port_data;
    

    最后,您需要设置所有功能

    static ErlDrvData startup_function_name(ErlDrvPort port, char *doc)
    {
      /* Plus any other start up methods you need */
      port_data* d = (port_data*)driver_alloc(sizeof(port_data));
      d->port = port;
      return (ErlDrvData)d;
    }
    
    /* Plus any other shutdown methods you need */
    static void shutdown_function_name(ErlDrvData handle)
    {
      driver_free((char*)handle);
    }
    
    static void outputv_function_name(ErlDrvData handle, ErlIOVec *ev)
    {
      port_data* d = (port_data*)handle;
      char* inputstring = ev->binv[1]->orig_bytes;
        ErlDrvTermData spec[] = {
          ERL_DRV_ATOM, driver_mk_atom("ok"),
          ERL_DRV_BUF2BINARY, inputstring, strlen(inputstring)
          ERL_DRV_TUPLE, 2
        };
        driver_send_term(d->port,driver_caller(d->port),spec,sizeof(spec)/sizeof(spec[0]));
    }
    

    您需要将此 C/C++ 代码编译为共享对象并将其与 erl 接口链接

    g++ -fpic -rdynamic -shared file_name -lerl_interface -lei
    

    现在,您需要在 erlang 中做几件事: 您需要加载驱动程序

    erl_ddll:load_driver("./location/of/driver", driver_name).
    

    然后你将为驱动程序打开一个端口

    Port = open_port({spawn, driver_name}, [binary]).
    

    最后你可以向端口发送数据

    port_command(Port, <<"String to Echo Back"),
    receive
      {ok, String} -> io:format("Received ~p back from the driver")
    end.
    

    【讨论】:

      【解决方案2】:

      最新的方法会考虑 NIF http://www.erlang.org/doc/man/erl_nif.html(小心,它可能会导致 VM 崩溃)。执行此操作的常规方法涉及链接驱动程序(谷歌链接,因为反垃圾邮件拥有它)

      【讨论】:

      • NIF 是您可能想要避免的事情,除非您真的知道自己在做什么。如果你调用了一些阻塞的东西,你就炸毁了 Erlang 的调度程序。如果你调用了一些崩溃的东西,你以前健壮的 Erlang 就会崩溃。
      猜你喜欢
      • 2015-03-29
      • 2023-04-09
      • 2017-06-06
      • 2016-05-02
      • 1970-01-01
      • 2018-08-28
      • 2021-02-25
      • 1970-01-01
      • 2019-01-08
      相关资源
      最近更新 更多