استدعاء وظائف الصدأ من Go

في وقت من الأوقات ، كان هناك مقال عن هبر حول كيفية استدعاء رمز Rust من Go . المقالة ليست سيئة ، ولكن من الصعب فهمها وصد المبتدئين في الواقع من الرغبة في النظر إلى اللغتين. ليس الغرض من هذا المنشور الدخول في شجاعة المكالمات عبر اللغات ، ولكن إظهار مدى سهولة القيام بذلك.

صورة

لن نذهب بعيداً ونأخذ مثالاً من كتاب عن تعلم لغة الصدأ.

كل ما يفعله هذا المثال هو بدء 10 سلاسل ، حيث يزيد المتغير 'x' إلى 5 ملايين ويعرض رسالة حول نهاية الدفق.

use std::thread;

#[no_mangle]
pub extern "C" fn process() {
    let handles:Vec<_> = (0..10).map(|_|{
        thread::spawn(||{
            let mut x = 0;
            for _ in 0..5_000_000 {
                x += 1
            }
            x
        })
    }).collect();

    for h in handles {
        println!("Thread finished with count={}",
                 h.join().map_err(|_| "Could not join thread!").unwrap());
    }
    println!("Done!");
}


تحتاج أيضًا إلى تعديل ملف البضائع عن طريق إضافة خط إليه
نوع الصندوق = ["cdylib"]
ونتيجة لذلك ، سيتم إنشاء مكتبة قادرة على استدعاء الوظائف عبر واجهة الوظائف الأجنبية (FFI) .

من الجدير بالذكر أن libembed.dylib هي مكتبة على نظام التشغيل Mac OS ، وعلى Linux ستكون libembed.so ، وعلى Windows ستكون libembed.dll

شكرا: bingo347


Cargo.toml
[package]
name = "embed"
version = "0.1.0"

[lib]
crate-type = ["cdylib"]


بشكل عام ، هذا كل ما عليك فعله في مكتبة Rust. يصف مثال من الكتاب هذا بمزيد من التفصيل ولن نتطرق إلى هذا الأمر.

نقوم بتجميع المكتبة باستخدام الأمر:
بناء البضائع - إطلاق
الآن هدفنا هو استدعاء هذا الرمز من تطبيق Go. ننشئ تطبيقًا بسيطًا وداخل مشروعنا ، نضيف مجلد lib الذي ننسخ فيه ملف /target/release/libembed.dylib . في الداخل ، نقوم بإنشاء ملف باسم الوظيفة ووصف توقيع المكالمة.

ليب / عملية. ح
void process();


داخل ملف Go ، نضيف مثل هذه التوجيهات وسوف تبدو main.go على هذا النحو

package main

/*
#cgo LDFLAGS: -L./lib -lembed
#include "./lib/process.h"
*/
import "C"

func main() {
	C.process()
}


تجميع المشروع معًا
اذهب build -ldflags = "- r / lib" main.go
انتبه إلى معلمة ldflags ، في هذه الحالة كل ما نقوم به هو تعيين المسار إلى رابط ديناميكي ELF.

الكل. قم بتشغيل البرنامج والحصول على الإخراج.



ومن الجدير بالذكر بشكل منفصل أنه يمكنك نقل التعاليم من برنامج Go إلى مكتبة Rust. للقيام بذلك ، نقوم بتحويل الوظيفة في مكتبة Rust بحيث تأخذ قيمة سلسلة.

extern crate libc;
use std::thread;
use std::ffi::CStr;

#[no_mangle]
pub extern "C" fn process(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 handles:Vec<_> = (0..10).map(|_|{
        thread::spawn(||{
            let mut x = 0;
            for _ in 0..5_000_000 {
                x += 1
            }
            x
        })
    }).collect();

    for h in handles {
        println!("{}:Thread finished with count={}\n",
                 str_name,
                 h.join().map_err(|_| "Could not join thread!\n").unwrap());
    }
    println!("Done!");
}


نقوم بتجميع مشروعنا ، ونسخ المكتبة إلى المجلد lib مرة أخرى ، وتعديل ملف process.h بهذه الطريقة
عملية باطلة (char * name) ؛

نقوم بتمرير الخط من تطبيق Go-application (في حالتنا: "Hello from Golang") .

package main

/*
#cgo LDFLAGS: -L./lib -lembed
#include "./lib/process.h"
*/
import "C"

func main() {
	C.process(C.CString("Hello from Golang !!"))
}


الكل. قم بتشغيل البرنامج والحصول على الإخراج.


All Articles