Files
llgo/doc/Rust-to-LLGO-Migration-Guide.md
2024-07-25 09:04:55 +08:00

3.0 KiB

Rust to LLGO Migration Document

Add Dependencies & Build Configuration

Edit Cargo.toml to include necessary dependencies and configuration:

[dependencies]
libc = "0.2"
csv = "1.1"

[lib]
crate-type = ["cdylib"] # The generated dynamic library will conform to the C standard

Import C Language Types

Use types from the libc package for interoperability with C:

use libc::{c_int, c_char, strlen};

Function Decoration and Attributes

To ensure that Rust functions can be correctly called by C and LLGO, use the following decorators:

  • #[no_mangle] prevents the compiler from mangling the function name.

  • unsafe is used to mark operations that are unsafe, especially when dealing with raw pointers.

  • extern "C" specifies the use of C calling conventions.

Memory Management

Use Box to manage dynamic memory to ensure correct memory release between Rust and C:

pub unsafe extern "C" fn sled_create_config() -> \*mut Config {
Box::into_raw(Box::new(Config::new()))
}

#[no_mangle]
pub unsafe extern "C" fn sled_free_config(config: \*mut Config) {
drop(Box::from_raw(config));
}

Handling Generic Pointers

Address the interfacing issues between generic pointers in C and Rust:

#[no_mangle]
pub extern "C" fn csv_reader_new(file_path: *const c_char) -> *mut c_void { /* ... */ }

#[no_mangle]
pub extern "C" fn csv_reader_free(ptr: *mut c_void) { /* ... */ }

String Handling

Convert strings between C and Rust:

#[no_mangle]
pub extern "C" fn csv_reader_read_record(ptr: *mut c_void) -> *const c_char { /* ... */ }

#[no_mangle]
pub extern "C" fn free_string(s: *mut c_char) {
    unsafe {
        let c_string = CString::from_raw(s);
        drop(c_string);
    }
}

Compilation and Installation

Build the dynamic library and use dylib-installer to install it to the system path:

cargo build --release
cargo install --git https://github.com/hackerchai/dylib-installer
sudo dylib_installer ./target/release/

Generate Header File

Use cbindgen to generate a C header file, automating this process through a build.rs script:

fn main() {
    let config = cbindgen::Config::from_file("cbindgen.toml").expect("Config file not found.");
    cbindgen::generate_with_config(&crate_dir, config).unwrap().write_to_file("target/include/csv_wrapper.h");
}

LLGO Package Mapping

Map functions from the Rust library to an LLGO package, ensuring type consistency:

const (
	LLGoPackage = "link: $(pkg-config --libs csv_wrapper); -lcsv_wrapper"
)

type Reader struct {
	Unused [8]byte
}

//go:linkname NewReader C.csv_reader_new
func NewReader(file_path *c.Char) *Reader

//llgo:link (*Reader).Free C.csv_reader_free
func (reader *Reader) Free() {}

//llgo:link (*Reader).ReadRecord C.csv_reader_read_record
func (reader *Reader) ReadRecord() *c.Char { return nil }

Writing Examples and README

Provide example code and a detailed README file to help users understand how to use the generated library.