新蒲京200.c软件下载-app官网网址 > 新蒲京200.c软件下载 >

的同事有过二个关于怎么样为像PHP样的解释性语言写拓宽的商讨

更新: 初藳刚发布尚未多少个小时小编发觉到自身的 PHP 基准测验是错的。为正义起见自个儿早已更新了 PHP 和 Rust 的版本。你能够在 GitHub 仓库里观察変更(链接在尾巴部分)。

二〇一八年七月,作者和 Etsy 的同事有过二个关于如何为像PHP样的解释性语言写拓宽的座谈,Ruby或Python近年来的情形相应会比PHP容易。大家谈到了写一个打响创造增添的绊脚石是它们平时必要用C来写,不过倘使你不短于C那门语言的话很难有特别信心。

从那个时候起作者便萌生了用Rust写叁个的主见,过去的几天一向在尝试。今天深夜小编好不轻巧让它运维了。

C或PHP中的Rust

自己的主干观点正是写一些方可编写翻译的Rust代码到多个Curry面,并写为它有些C的头文件,在C中为被调用的PHP做几人展览开。就算实际不是十分轻巧,可是很风趣。

Rust FFI(foreign function interface)

自己所做的率先件事情正是摆弄Rust与C连接的Rust的表面函数接口。我曾用简短的办法(hello_from_rust)写过四个心灵手敏的库,伴有单纯的宣示(a pointer to a C char, otherwise known as a string),如下是输入后输出的“Hello from Rust”。

// hello_from_rust.rs
#![crate_type = "staticlib"]

#![feature(libc)]
extern crate libc;
use std::ffi::CStr;

#[no_mangle]
pub extern "C" fn hello_from_rust(name: *const libc::c_char) {
    let buf_name = unsafe { CStr::from_ptr(name).to_bytes() };
    let str_name = String::from_utf8(buf_name.to_vec()).unwrap();
    let c_name   = format!("Hello from Rust, {}", str_name);
    println!("{}", c_name);
}

自己从C(或其余!)中调用的Rust库拆分它。那有叁个接下去会如何的很好的批注。

编译它会获得.a的多少个文本,libhello_from_rust.a。那是一个静态的库,包罗它自身抱有的信赖关系,况兼大家在编写翻译二个C程序的时候链接它,那让大家能做持续的业务。注意:在大家编写翻译后会获得如下输出:

note: link against the following native artifacts when linking against this static library
note: the order and any duplication can be significant on some platforms, and so may need to be preserved
note: library: Systemnote: library: pthread
note: library: c
note: library: m

那正是Rust编写翻译器在大家不应用这几个借助的时候所告诉大家必要链接什么。

从C中调用Rust

既然大家有了三个库,不能不做两件事来保障它从C中可调用。首先,我们供给为它创制一个C的头文件,hello_from_rust.h。然后在大家编写翻译的时候链接到它。

上面是头文件:

// hello_from_rust.h
#ifndef __HELLO
#define __HELLO

void hello_from_rust(const char *name);

#endif

那是三个一定底子的头文件,仅仅为了七个轻便易行的函数提供签字/定义。接着大家必要写四个C程序并接受它。

// hello.c
#include <stdio.h>
#include <stdlib.h>
#include "hello_from_rust.h"

int main(int argc, char *argv[]) {
    hello_from_rust("Jared!");
}

大家通过运维一下代码来编写翻译它:

gcc -Wall -o hello_c hello.c -L /Users/jmcfarland/code/rust/php-hello-rust -lhello_from_rust -lSystem -lpthread -lc -lm

只顾在终极的-lSystem -lpthread -lc -lm告诉gcc不要链接那七个“本地的古物”,为了当编写翻译大家的Rust库时Rust编写翻译器能够提供出来。

经运维上面包车型大巴代码我们得以得到五个二进制的文本:

$ ./hello_c
Hello from Rust, Jared!

美貌!大家刚刚从C中调用了Rust库。以往大家需求知道Rust库是怎么步向叁个PHP扩展的。

从 php 中调用 c

该片段花了自个儿有些时间来弄了解,在这里个世界上,该文书档案在 php 扩充中并不是最棒的。最佳的一对是根源绑定八个本子 ext_skel 的 php 源(大多数象征“扩张骨架”)即生成大多数你要求的规范代码。为了让代码运行,笔者极度开足马力地读书 php 文书档案,“扩展骨骼”。

你可以经过下载来初叶,和未配额的 php 源,把代码写进 php 目录况兼运行:

$ cd ext/
$ ./ext_skel –extname=hello_from_rust

那将转移须要创建 php 扩张的中央骨架。未来,移动你随处想一些地涵养你的强盛的文书夹。何况一抬手一动脚你的

.rust 源

.rust库

.c header

进入同贰个目录。因而,以后您应有看看像那样的三个目录:

.
├── CREDITS
├── EXPERIMENTAL
├── config.m4
├── config.w32
├── hello_from_rust.c
├── hello_from_rust.h
├── hello_from_rust.php
├── hello_from_rust.rs
├── libhello_from_rust.a
├── php_hello_from_rust.h
└── tests
└── 001.phpt

一个目录,公斤个公文

你能够在 php docs 在地点看见关于这几个文件很好的描述。创立多个扩充的文件。大家将经过编制config.m4 来早先吧。

不表明,上边正是自身的结晶:

PHP_ARG_WITH(hello_from_rust, for hello_from_rust support,
[  --with-hello_from_rust             Include hello_from_rust support])

if test "$PHP_HELLO_FROM_RUST" != "no"; then
  PHP_SUBST(HELLO_FROM_RUST_SHARED_LIBADD)

  PHP_ADD_LIBRARY_WITH_PATH(hello_from_rust, ., HELLO_FROM_RUST_SHARED_LIBADD)

  PHP_NEW_EXTENSION(hello_from_rust, hello_from_rust.c, $ext_shared)
fi

正如自个儿所通晓的那么,那几个是着力的宏命令。不过关于这一个宏命令的文书档案是一定糟糕的(举例:google”PHP_ADD_LIBRARY_WITH_PATH”并不曾现身PHP团队所写的结果)。小编有时这些PHP_ADD_LIBRARY_PATH宏命令在多少人所钻探的在二个PHP拓展里链接贰个静态库的先前的线程里。在商量中其余的推荐介绍应用的宏命令是在自己运转ext_skel后产生的。

既然如此大家进行了配备安装,我们要求从PHP脚本中实际上地调用库。为此大家得改善自动生成的文书,hello_from_rust.c。首先大家加多hello_from_rust.h头文件到含有命令中。然后我们要改良confirm_hello_from_rust_compiled的定义方法。

#include "hello_from_rust.h"

// a bunch of comments and code removed...

PHP_FUNCTION(confirm_hello_from_rust_compiled)
{
    char *arg = NULL;
    int arg_len, len;
    char *strg;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
        return;
    }

    hello_from_rust("Jared (from PHP!!)!");

    len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "hello_from_rust", arg);
    RETURN_STRINGL(strg, len, 0);
}

小心:我增多了hello_from_rust(“Jared (fromPHP!!)!”);。

现行反革命,我们能够试着创立我们的恢宏:

$ phpize
$ ./configure
$ sudo make install

正是它,生成大家的元配置,运维生成的安插命令,然后安装该扩张。安装时,小编不得不亲自使用sudo,因为笔者的顾客并不持有安装目录的 php 扩充。

今昔,大家得以运作它啦!

$ php hello_from_rust.php
Functions available in the test extension:
confirm_hello_from_rust_compiled

Hello from Rust, Jared (from PHP!!)!
Congratulations! You have successfully modified ext/hello_from_rust/config.m4. Module hello_from_rust is now compiled into PHP.
Segmentation fault: 11

还行,php 已跻身大家的 c 扩大,看见大家的施用措施列表而且调用。接着,c 扩张已步向大家的 rust 库,开首打印大家的字符串。那很有趣!可是……那段错误的结果发生了如何?

 

正如作者所提到的,这里是运用了 Rust 相关的 println! 宏,可是小编平昔不对它做更加的调理。假使大家从大家的 Rust 库中剔除并赶回四个 char* 取代,段错误就能够秋风落叶。

这里是 Rust 的代码:

#![crate_type = "staticlib"]

#![feature(libc)]
extern crate libc;
use std::ffi::{CStr, CString};

#[no_mangle]
pub extern "C" fn hello_from_rust(name: *const libc::c_char) -> *const libc::c_char {
    let buf_name = unsafe { CStr::from_ptr(name).to_bytes() };
    let str_name = String::from_utf8(buf_name.to_vec()).unwrap();
    let c_name   = format!("Hello from Rust, {}", str_name);

    CString::new(c_name).unwrap().as_ptr()
}

并变更 C 头文件:

#ifndef __HELLO
#define __HELLO

const char * hello_from_rust(const char *name);

#endif

还要改造 C 扩展文件:

PHP_FUNCTION(confirm_hello_from_rust_compiled)
{
    char *arg = NULL;
    int arg_len, len;
    char *strg;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
        return;
    }

    char *str;
    str = hello_from_rust("Jared (from PHP!!)!");
    printf("%s/n", str);

    len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "hello_from_rust", arg);
    RETURN_STRINGL(strg, len, 0);
}

不算的微基准

那就是说为什么您还要如此做?笔者还确实未有在切实世界里使用过那一个。不过本身实在以为斐波那契连串算法就是三个好的例证来讲圣元(Synutra卡塔尔(قطر‎(Aptamil卡塔尔个PHP扩充怎样很基本。经常是斩钢截铁(在Ruby中):

def fib(at) do
    if (at == 1 || at == 0)
        return at
    else
        return fib(at - 1) + fib(at - 2)
    end
end

与此相同的时间能够通过不行使递回来更正那倒霉的属性:

def fib(at) do
    if (at == 1 || at == 0)
        return at
    elsif (val = @cache[at]).present?
        return val  
    end

    total  = 1
    parent = 1
    gp     = 1

    (1..at).each do |i|
        total  = parent + gp
        gp     = parent
        parent = total
    end

    return total
end

那么大家围绕它来写多个例证,一个在PHP中,三个在Rust中。看看哪位更加快。下边是PHP版:

def fib(at) do
    if (at == 1 || at == 0)
        return at
    elsif (val = @cache[at]).present?
        return val  
    end

    total  = 1
    parent = 1
    gp     = 1

    (1..at).each do |i|
        total  = parent + gp
        gp     = parent
        parent = total
    end

    return total
end

那是它的运营结果:

$ time php php_fib.php

real    0m2.046s
user    0m1.823s
sys 0m0.207s

明日我们来做Rust版。上边是库能源:

#![crate_type = "staticlib"]

fn fib(at: usize) -> usize {
    if at == 0 {
        return 0;
    } else if at == 1 {
        return 1;
    }

    let mut total  = 1;
    let mut parent = 1;
    let mut gp     = 0;
    for _ in 1 .. at {
        total  = parent + gp;
        gp     = parent;
        parent = total;
    }

    return total;
}

#[no_mangle]
pub extern "C" fn rust_fib(at: usize) -> usize {
    fib(at)
}

在乎,笔者编写翻译的库rustc – O rust_lib.rs使编写翻译器优化(因为大家是这里的正经八百)。这里是C扩张源(相关摘录):

PHP_FUNCTION(confirm_rust_fib_compiled)
{
    long number;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &number) == FAILURE) {
        return;
    }

    RETURN_LONG(rust_fib(number));
}

运行PHP脚本:

<?php
$br = (php_sapi_name() == "cli")? "":"<br>";

if(!extension_loaded('rust_fib')) {
    dl('rust_fib.' . PHP_SHLIB_SUFFIX);
}

for ($i = 0; $i < 100000; $i ++) {
    confirm_rust_fib_compiled(92);
}
?>

那便是它的运作结果:

$ time php rust_fib.php

real    0m0.586s
user    0m0.342s
sys 0m0.221s

你能够望见它比前面叁个快了三倍!完美的Rust微基准!

总结

那边大概从未得出什么结论。小编不分明在Rust上写多个PHP的恢宏是三个好的主见,然而开销一些时间去商量Rust,PHP和C,那是二个很好的办法。

假诺您期待查看全部代码也许查看纠正记录,能够访谈GitHub Repo。

上一篇:付费投稿计划
下一篇:没有了