Fixed rust, named the libraries sdk's, better examples

This commit is contained in:
Gvidas Juknevičius 2024-06-16 00:59:04 +03:00
parent 407faab33a
commit f55279b7ef
Signed by: MCorange
GPG Key ID: 12B1346D720B7FBB
20 changed files with 229 additions and 226 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/target /target
/plugins /plugins
/.cache /.cache
compile_commands.json

11
Cargo.lock generated
View File

@ -51,6 +51,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "anyhow"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.6.0" version = "1.6.0"
@ -122,9 +128,10 @@ dependencies = [
] ]
[[package]] [[package]]
name = "dim_plugin_helper" name = "dim_sdk"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"bytes", "bytes",
"lazy_static", "lazy_static",
"libc", "libc",
@ -157,7 +164,7 @@ dependencies = [
name = "example_rust" name = "example_rust"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"dim_plugin_helper", "dim_sdk",
"lazy_static", "lazy_static",
] ]

View File

@ -1,4 +1,4 @@
workspace = { members = [ "dim_plugin_helper","dim_plugins/example_rust"] } workspace = { members = [ "sdk/rust","dim_plugins/example_rust"] }
[package] [package]
name = "dim" name = "dim"
version = "0.1.0" version = "0.1.0"

View File

@ -4,7 +4,7 @@ CWD := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
PLUGIN_DIR = ${CWD}plugins PLUGIN_DIR = ${CWD}plugins
OBJECT_DIR = $(CWD)target/objects OBJECT_DIR = $(CWD)target/objects
BUILD_DIR = $(CWD)target BUILD_DIR = $(CWD)target
DIM_CC_FLAGS = -I$(CWD)include -rdynamic -shared -fPIC DIM_CC_FLAGS = -I$(CWD)sdk/c_cxx
DIM_CC = gcc DIM_CC = gcc
BIN=$(BUILD_DIR)/dim BIN=$(BUILD_DIR)/dim
@ -21,7 +21,7 @@ target/release/dim:
cargo build --release cargo build --release
dim_plugins/%/Makefile: dim_plugins/%/Makefile:
$(MAKE) -C $(dir $@) \ @$(MAKE) -C $(dir $@) \
-E "PLUGIN_DIR=$(PLUGIN_DIR)" \ -E "PLUGIN_DIR=$(PLUGIN_DIR)" \
-E "OBJECT_DIR=$(OBJECT_DIR)" \ -E "OBJECT_DIR=$(OBJECT_DIR)" \
-E "BUILD_DIR=$(BUILD_DIR)" \ -E "BUILD_DIR=$(BUILD_DIR)" \

View File

@ -7,8 +7,9 @@
"-o", "-o",
"/home/mcorange/@Projects/xor64/dim/target/objects/example_c/main.o", "/home/mcorange/@Projects/xor64/dim/target/objects/example_c/main.o",
"src/main.c", "src/main.c",
"-fPIC", "-pie",
"-pie" "-I/home/mcorange/@Projects/xor64/dim/sdk/c_cxx",
"-fPIC"
], ],
"file": "src/main.c" "file": "src/main.c"
} }

View File

@ -1,111 +0,0 @@
use std::{ffi::{c_char, c_void, CStr, CString}, io::Write};
pub use libc::snprintf;
#[repr(C)]
#[derive(Debug)]
pub struct PluginInfo {
ptrs: PluginInfoPtrs,
c_name: CString,
c_version: CString,
c_license: CString
}
#[repr(C)]
#[derive(Debug)]
struct PluginInfoPtrs {
name: *const c_char,
version: *const c_char,
license: *const c_char,
}
impl PluginInfo {
// pub fn new() -> Self {
// Self {
// name: std::ptr::null(),
// version: std::ptr::null(),
// license: std::ptr::null(),
// c_name: Default::default(),
// c_version: Default::default(),
// c_license: Default::default()
// }
//}
pub fn new(name: &str, version: &str, license: &str) -> Self {
let c_name = CString::new(name).unwrap();
let c_version = CString::new(version).unwrap();
let c_license = CString::new(license).unwrap();
let name = c_name.as_ptr();
let version = if c_version.is_empty() {
std::ptr::null()
} else {c_version.as_ptr()};
let license = if c_license.is_empty() {
std::ptr::null()
} else {c_license.as_ptr()};
Self { ptrs: PluginInfoPtrs{ name, version, license }, c_name, c_version, c_license }
}
pub fn get(&self) -> *const c_void {
&self.ptrs as *const _ as *const c_void
}
}
unsafe impl Sync for PluginInfo {}
// Lord have mercy on me
#[macro_export]
macro_rules! plugin_info {
($name:literal, $version:literal, $license:literal) => {
lazy_static::lazy_static!(
static ref PLUGIN_INFO: PluginInfo = PluginInfo::new($name, $version, $license);
);
};
}
#[derive(Debug)]
pub struct CBuffer {
inner: *mut i8,
count: usize,
capacity: usize
}
impl CBuffer {
pub fn from_raw_parts_mut(buf: *mut i8, capacity: usize) -> Self {
Self {
inner: buf,
capacity,
count: 0,
}
}
}
impl Write for CBuffer {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let mut count = 0;
for c in buf {
unsafe {
if self.count + count >= self.capacity - 1 {
return Err(std::io::ErrorKind::OutOfMemory.into());
}
(*self.inner.add(self.count + count)) = *c as i8;
}
count += 1;
}
unsafe {
(*self.inner.add(self.count + count)) = 0;
}
self.count += count;
Ok(count as usize)
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}

View File

@ -1,7 +1,7 @@
PLUGIN_NAME=example_c PLUGIN_NAME=example_c
CC_FLAGS = $(DIM_CC_FLAGS) CC_FLAGS = $(DIM_CC_FLAGS) -fPIC
SOURCES=$(wildcard src/*.c) SOURCES=$(wildcard src/*.c)
OBJECTS=$(patsubst src/%.c,$(OBJECT_DIR)/$(PLUGIN_NAME)/%.o,$(SOURCES)) OBJECTS=$(patsubst src/%.c,$(OBJECT_DIR)/$(PLUGIN_NAME)/%.o,$(SOURCES))
@ -12,8 +12,8 @@ build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECTS) $(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECTS)
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
$(DIM_CC) -o $@ $^ $(CC_FLAGS) $(DIM_CC) -o $@ $^ -rdynamic -shared $(CC_FLAGS)
$(OBJECT_DIR)/$(PLUGIN_NAME)/%.o: src/%.c $(OBJECT_DIR)/$(PLUGIN_NAME)/%.o: src/%.c
@mkdir -p $(dir $@) @mkdir -p $(dir $@)
$(DIM_CC) -c -o $@ $< -fPIC -pie $(DIM_CC) -c -o $@ $< -pie $(CC_FLAGS)

View File

@ -2,9 +2,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include "../../../include/plug.h" #include "dim_sdk.h"
PLUG_INFO("Example plugin", "0.0.0", "GPLv3") PLUG_INFO("Example plugin", "0.0.1", "GPLv3")
typedef struct plug_t { typedef struct plug_t {
char* some_data; char* some_data;
@ -16,7 +16,6 @@ plug_t* p = {0};
void plug_init() { void plug_init() {
p = malloc(sizeof(plug_t)); p = malloc(sizeof(plug_t));
assert(p != NULL && "Buy more ram KEKW"); assert(p != NULL && "Buy more ram KEKW");
p->some_data = "hi :3";
p->count = 0; p->count = 0;
printf("Hello from plugin"); printf("Hello from plugin");
@ -31,7 +30,7 @@ void plug_post_reload(void *state) {
} }
void plug_poll(char *buf, size_t len) { void plug_poll(char *buf, size_t len) {
snprintf(buf, len, "%s (%d)", p->some_data, p->count++); snprintf(buf, len, "Hello from C! (%d)", p->count++);
} }
void plug_free() { void plug_free() {

View File

@ -8,5 +8,5 @@ crate-type=["cdylib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
dim_plugin_helper = {path="../../dim_plugin_helper"} dim_sdk = {path="../../sdk/rust/"}
lazy_static = "1.4.0" lazy_static = "1.4.0"

View File

@ -4,12 +4,12 @@ PLUGIN_NAME=example_rust
build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim build: $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
$(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/release/lib$(PLUGIN_NAME).so $(PLUGIN_DIR)/$(PLUGIN_NAME).dim: $(OBJECT_DIR)/$(PLUGIN_NAME)/debug/lib$(PLUGIN_NAME).so
cp $(OBJECT_DIR)/$(PLUGIN_NAME)/release/lib$(PLUGIN_NAME).so $(PLUGIN_DIR)/$(PLUGIN_NAME).dim cp $(OBJECT_DIR)/$(PLUGIN_NAME)/debug/lib$(PLUGIN_NAME).so $(PLUGIN_DIR)/$(PLUGIN_NAME).dim
$(OBJECT_DIR)/$(PLUGIN_NAME)/release/lib$(PLUGIN_NAME).so: $(OBJECT_DIR)/$(PLUGIN_NAME)/debug/lib$(PLUGIN_NAME).so:
mkdir -p $(OBJECT_DIR)/$(PLUGIN_NAME) mkdir -p $(OBJECT_DIR)/$(PLUGIN_NAME)
cargo build --release --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME) cargo build --target-dir $(OBJECT_DIR)/$(PLUGIN_NAME)

View File

@ -1,67 +1,48 @@
use std::ffi::c_void; use std::fmt::Write;
use std::ffi::CStr; use dim_sdk::{plugin_info, DimPlugin};
use std::ffi::CString;
use std::io::BufWriter;
use std::io::Write;
use dim_plugin_helper::{plugin_info, PluginInfo};
plugin_info!("Example rust project", "owo", "nyaaa"); plugin_info!(
Plug, // Your main global structs name that implements `DimPlugin`
"Example rust project", // Plugin name
"0.0.0", // Plugin Version (leave empty for none)
"GPLv3" // Plugin license (leave empty for none)
);
struct Plug { struct Plug {
pub some_data: String, counter: usize,
} }
impl Plug { impl Plug {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
some_data: String::from("OwO") counter: 0
} }
} }
} }
impl DimPlugin for Plug {
static mut PLUG: *mut Plug = std::ptr::null_mut(); fn init(&mut self) {
// Initialise data, this will run once, it will not run again after reload
#[no_mangle]
extern "C" fn plug_get_info() -> *const c_void {
PLUGIN_INFO.get()
} }
fn poll(&mut self, f: &mut dim_sdk::CBuffer) -> dim_sdk::Result<()> {
#[no_mangle] // Write to buffer the text you want to display, keep this short
extern "C" fn plug_init() { write!(f, "Hello from rust! ({})", self.counter)?;
unsafe { self.counter += 1;
PLUG = (&mut Plug::new()) as *mut Plug; Ok(())
}
fn pre_reload(&mut self) {
// Do stuff before reload, probably save important things because theres a good chance
// (especially on rust) that if you change the data layout it will die
}
fn post_reload(&mut self) {
// Do stuff after reloading plugin, state a.k.a this struct has the same data, will crash
// if the data layout changed
}
fn free(&mut self) {
// Yout probably dont need this but its for freeing things before the plugin gets unloaded
} }
} }
#[no_mangle]
extern "C" fn plug_pre_reload() -> *const () {
unsafe {
return PLUG as *const ();
}
}
#[no_mangle]
extern "C" fn plug_post_reload(state: *mut ()) {
unsafe {
PLUG = state as *mut Plug;
}
}
#[no_mangle]
extern "C" fn plug_poll(buf: *mut i8, len: usize) {
let mut buf = dim_plugin_helper::CBuffer::from_raw_parts_mut(buf, len);
// let mut buf = StringBuffer::from_raw_parts_mut(buf, len);
let data = unsafe {(*PLUG).some_data.clone()};
let _ = write!(buf, "{}", data);
}
#[no_mangle]
extern "C" fn plug_free() {
}

View File

@ -1,37 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "../include/plug.h"
PLUG_NAME("Example plugin")
PLUG_VERSION("0.0.0")
PLUG_LICENSE("GPLv3")
typedef struct plug_t {
char* some_data;
} plug_t;
static plug_t* p = {0};
void plug_init() {
p = malloc(sizeof(plug_t));
assert(p != NULL && "Buy more ram KEKW");
p->some_data = "hi :3";
}
void* plug_pre_reload() {
return p;
}
void plug_post_reload(void *state) {
p = state;
}
void plug_poll(char *buf, size_t len) {
snprintf(buf, len, "%s", p->some_data);
}
void plug_free() {
free(p);
}

View File

@ -1,12 +1,13 @@
[package] [package]
name = "dim_plugin_helper" name = "dim_sdk"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
[lib] [lib]
name="dim_plugin_helper" name="dim_sdk"
[dependencies] [dependencies]
anyhow = "1.0.86"
bytes = "1.6.0" bytes = "1.6.0"
lazy_static = { version = "1.4.0", features = ["spin"] } lazy_static = { version = "1.4.0", features = ["spin"] }
libc = "0.2.155" libc = "0.2.155"

36
sdk/rust/src/c_buffer.rs Normal file
View File

@ -0,0 +1,36 @@
#[derive(Debug)]
pub struct CBuffer<'a> {
inner: &'a mut [i8],
count: usize,
capacity: usize
}
#[allow(dead_code)] // rust_analyzer too dumb to see my macro magic
// i hate that macro as much as you do
impl CBuffer<'_> {
pub fn from_raw_parts_mut(buf: *mut i8, capacity: usize) -> Self {
Self {
inner: unsafe {
std::slice::from_raw_parts_mut(buf, capacity)
},
capacity,
count: 0,
}
}
}
impl std::fmt::Write for CBuffer<'_> {
fn write_str(&mut self, buf: &str) -> Result<(), std::fmt::Error> {
for c in buf.as_bytes() {
if self.count >= self.capacity - 1 {
return Ok(());
}
self.inner[self.count] = *c as i8;
self.count += 1;
}
self.inner[self.count] = 0;
Ok(())
}
}

25
sdk/rust/src/lib.rs Normal file
View File

@ -0,0 +1,25 @@
#[macro_use]
mod magic;
mod c_buffer;
mod plugin_info;
pub use c_buffer::*;
pub use plugin_info::*;
pub use anyhow::Result;
pub trait DimPlugin {
fn init(&mut self);
fn pre_reload(&mut self);
fn post_reload(&mut self);
fn poll(&mut self, f: &mut CBuffer) -> Result<()>;
fn free(&mut self) {}
}

53
sdk/rust/src/magic.rs Normal file
View File

@ -0,0 +1,53 @@
// Lord have mercy on me
#[macro_export]
macro_rules! plugin_info {
($typ:ty, $name:literal, $version:literal, $license:literal) => {
lazy_static::lazy_static!(
static ref PLUGIN_INFO: $crate::PluginInfo = $crate::PluginInfo::new($name, $version, $license);
);
static mut PLUG: *mut $typ = std::ptr::null_mut() as *mut $typ;
#[no_mangle]
unsafe extern "C" fn plug_get_info() -> *const std::ffi::c_void {
PLUGIN_INFO.get_raw_ptr()
}
#[no_mangle]
unsafe extern "C" fn plug_init() {
PLUG = std::alloc::alloc(std::alloc::Layout::new::<$typ>()) as *mut $typ;
*PLUG = Plug::new();
(&mut *PLUG).init();
}
#[no_mangle]
unsafe extern "C" fn plug_pre_reload() -> *mut $typ {
//TODO: Untested
(&mut *PLUG).pre_reload();
return PLUG;
}
#[no_mangle]
unsafe extern "C" fn plug_post_reload(state: *mut $typ) {
//TODO: Untested
PLUG = state;
(&mut *PLUG).post_reload();
}
#[no_mangle]
unsafe extern "C" fn plug_poll(buf: *mut i8, len: std::ffi::c_uint) {
let mut buf = $crate::CBuffer::from_raw_parts_mut(buf, len as usize);
if let Err(_e) = (&mut *PLUG).poll(&mut buf) {
// TODO: Handle error maybe?
}
}
#[no_mangle]
unsafe extern "C" fn plug_free() {
std::alloc::dealloc(PLUG as *mut u8, std::alloc::Layout::new::<$typ>());
(&mut *PLUG).free();
}
};
}

View File

@ -0,0 +1,41 @@
use std::ffi::{c_char, c_void, CString};
#[derive(Debug)]
pub struct PluginInfo {
ptrs: PluginInfoPtrs,
_name: CString,
_version: CString,
_license: CString
}
#[repr(C)]
#[derive(Debug)]
struct PluginInfoPtrs {
name: *const c_char,
version: *const c_char,
license: *const c_char,
}
impl PluginInfo {
pub fn new(name: &str, version: &str, license: &str) -> Self {
let _name = CString::new(name).unwrap();
let _version = CString::new(version).unwrap();
let _license = CString::new(license).unwrap();
let name = _name.as_ptr();
let version = if _version.is_empty() {
std::ptr::null()
} else {_version.as_ptr()};
let license = if _license.is_empty() {
std::ptr::null()
} else {_license.as_ptr()};
Self { ptrs: PluginInfoPtrs{ name, version, license }, _name, _version, _license }
}
pub fn get_raw_ptr(&self) -> *const c_void {
&self.ptrs as *const _ as *const c_void
}
}
unsafe impl Sync for PluginInfo {}

View File

@ -37,6 +37,8 @@ impl PlugMan {
self.load(entry.path().to_path_buf())?; self.load(entry.path().to_path_buf())?;
} }
} }
println!("INFO: Loaded {} plugins", self.plugins.len());
Ok(()) Ok(())
} }
@ -81,18 +83,18 @@ impl PlugMan {
#[derive(Debug)] #[derive(Debug)]
pub enum PluginError { pub enum PluginError {
DlOpenError(dlopen::Error), DlOpenError,
IoError(std::io::Error) IoError
} }
impl From<dlopen::Error> for PluginError { impl From<dlopen::Error> for PluginError {
fn from(value: dlopen::Error) -> Self { fn from(_: dlopen::Error) -> Self {
Self::DlOpenError(value) Self::DlOpenError
} }
} }
impl From<std::io::Error> for PluginError { impl From<std::io::Error> for PluginError {
fn from(value: std::io::Error) -> Self { fn from(_: std::io::Error) -> Self {
Self::IoError(value) Self::IoError
} }
} }

View File

@ -1,4 +1,4 @@
use std::{alloc::Layout, ffi::{c_char, CStr, CString}, path::PathBuf}; use std::{alloc::Layout, ffi::{c_char, c_uint, CStr, CString}, path::PathBuf};
use dlopen::raw::Library; use dlopen::raw::Library;
@ -90,6 +90,10 @@ impl Plugin {
let s = unsafe { let s = unsafe {
(self.syms().poll)(buf as *mut i8, cap); (self.syms().poll)(buf as *mut i8, cap);
let len = libc::strlen(buf as *const i8); let len = libc::strlen(buf as *const i8);
if len > cap {
panic!("String len is bigger than allocatd");
}
String::from_raw_parts(buf, len, cap) String::from_raw_parts(buf, len, cap)
}; };