diff options
author | Qrius <[email protected]> | 2024-12-06 14:23:32 +0100 |
---|---|---|
committer | Qrius <[email protected]> | 2024-12-06 14:23:41 +0100 |
commit | 1b59010b7da3b86aea6eb929d7efe37bdf735cd6 (patch) | |
tree | 568406b02dd280c005a54622b22a025776dcca9a | |
parent | 42ec0c6469238b60bfd5f5c0baa085ec0c6ec148 (diff) | |
download | skaldpress-1b59010b7da3b86aea6eb929d7efe37bdf735cd6.tar.gz skaldpress-1b59010b7da3b86aea6eb929d7efe37bdf735cd6.zip |
Add some basic bindings for Guile-3.0
-rw-r--r-- | Cargo.lock | 4 | ||||
-rw-r--r-- | Cargo.toml | 8 | ||||
-rw-r--r-- | build.rs | 39 | ||||
-rw-r--r-- | src/guile/guile.rs | 86 | ||||
-rw-r--r-- | src/guile/guiledefs.c | 3 | ||||
-rw-r--r-- | src/guile/main.rs | 5 | ||||
-rw-r--r-- | src/guile/mod.rs | 1 | ||||
-rw-r--r-- | src/lib.rs | 2 |
8 files changed, 145 insertions, 3 deletions
@@ -109,9 +109,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "log" @@ -5,16 +5,18 @@ edition = "2021" default-run = "skaldpress" [features] -default = ["time", "markdown", "deadlinks"] +default = ["time", "markdown", "deadlinks", "guile"] time = ["dep:chrono"] markdown = ["dep:markdown"] deadlinks = ["dep:minreq"] webring = [] +guile = [] [dependencies] markdown = { version = "1.0.0-alpha.20", optional = true } chrono = { version = "0.4.38", optional = true } minreq = { version = "2.12.0", optional = true, features = ["https", "punycode"] } +#libc = { version = "0.2.167", optional = true } [[bin]] name = "skaldpress" @@ -25,3 +27,7 @@ path = "src/skaldpress/main.rs" [[bin]] name = "smp" path = "src/macro_processor/main.rs" + +[[bin]] +name = "guiletest" +path = "src/guile/main.rs" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..83fcc3c --- /dev/null +++ b/build.rs @@ -0,0 +1,39 @@ +#[cfg(feature = "guile")] +use std::env; +#[cfg(feature = "guile")] +use std::process::Command; + +// cargo build has to be run twice for some reason. +fn build_guile() { + const LIBGUILE_INCLUDE_PATH: &str = "/usr/include/guile/3.0/"; + const GUILEDEFS_SRC: &str = "src/guile/guiledefs.c"; + const GUILEDEFS_TARGET_OBJ: &str = "guiledefs.o"; + const GUILEDEFS_TARGET_ARCHIVE: &str = "libguiledefs.a"; + + let out_dir = env::var("OUT_DIR").unwrap(); + + Command::new("gcc") + .arg("-c") + .arg("-I") + .arg(LIBGUILE_INCLUDE_PATH) + .arg("-lguile-3.0") + .arg(GUILEDEFS_SRC) + .arg("-o") + .arg(format!("{}/{}", out_dir, GUILEDEFS_TARGET_OBJ)) + .spawn() + .expect("Error compiling guiledefs.c"); + + Command::new("ar") + .arg("r") + .arg(format!("{}/{}", out_dir, GUILEDEFS_TARGET_ARCHIVE)) + .arg(format!("{}/{}", out_dir, GUILEDEFS_TARGET_OBJ)) + .spawn() + .expect("Error creating libguiledefs.a"); + + println!("cargo:rustc-link-search=native={}", out_dir); +} + +fn main() { + #[cfg(feature = "guile")] + build_guile(); +} diff --git a/src/guile/guile.rs b/src/guile/guile.rs new file mode 100644 index 0000000..4a0e25b --- /dev/null +++ b/src/guile/guile.rs @@ -0,0 +1,86 @@ +use std::ffi::{CStr, CString}; +use std::os::raw::{c_char, c_int, c_void}; + +#[link(name = "guile-3.0")] +#[allow(dead_code)] +extern "C" { + fn scm_init_guile(); + fn scm_c_define_gsubr( + name: *const c_char, + req: c_int, + opt: c_int, + rst: c_int, + func: extern "C" fn() -> *mut c_void, + ); + fn scm_c_eval_string(expr: *const c_char) -> *mut c_void; + fn scm_to_locale_string(scm_obj: *mut c_void) -> *const c_char; + fn scm_c_write(scm_obj: *mut c_void, port: *mut c_void); + fn scm_open_output_string() -> *mut c_void; + fn scm_get_output_string(port: *mut c_void) -> *mut c_void; + fn scm_is_string(scm_obj: *mut c_void) -> c_int; + fn scm_is_number(scm_obj: *mut c_void) -> c_int; + fn scm_object_to_string(scm_obj: *mut c_void, printer: *mut c_void) -> *mut c_void; +} + +#[link(name = "guiledefs")] +extern "C" { + pub static scm_undefined: *mut c_void; +} + +extern "C" fn my_rust_function() -> *mut c_void { + println!("Hello from Rust!"); + unsafe { scm_undefined } +} + +/// Convert a scm object into a string using Guile-builtins +fn string_from_scm(scm_obj: *mut c_void) -> Result<String, ()> { + unsafe { + if scm_obj.is_null() { + return Err(()); + } + if scm_is_string(scm_obj) != 0 { + let res_str = CStr::from_ptr(scm_to_locale_string(scm_obj)) + .to_string_lossy() + .into_owned(); + return Ok(res_str); + } else { + let port = scm_open_output_string(); + if port.is_null() { + return Err(()); + } + let res = scm_object_to_string(scm_obj, scm_undefined); + if res.is_null() { + return Err(()); + } + let res_str = CStr::from_ptr(scm_to_locale_string(res)) + .to_string_lossy() + .into_owned(); + return Ok(res_str); + } + } +} + +pub fn smp_guile_init() {} + +pub fn testguile() { + unsafe { + scm_init_guile(); + + let func_name = CString::new("my-rust-function").unwrap(); + scm_c_define_gsubr( + func_name.as_ptr(), + 0, // required arguments + 0, // optional arguments + 0, // rest arguments + my_rust_function, + ); + + let expr = CString::new("(+ 2 3)").unwrap(); + let result = scm_c_eval_string(expr.as_ptr()); + println!("{:?}", string_from_scm(result)); + + let expr = CString::new("(my-rust-function)").unwrap(); + let result = scm_c_eval_string(expr.as_ptr()); + println!("{:?}", string_from_scm(result)); + } +} diff --git a/src/guile/guiledefs.c b/src/guile/guiledefs.c new file mode 100644 index 0000000..9f52c43 --- /dev/null +++ b/src/guile/guiledefs.c @@ -0,0 +1,3 @@ +#include <libguile.h> + +struct scm_unused_struct * scm_undefined = SCM_UNDEFINED; diff --git a/src/guile/main.rs b/src/guile/main.rs new file mode 100644 index 0000000..6957c8c --- /dev/null +++ b/src/guile/main.rs @@ -0,0 +1,5 @@ +use skaldpress::guile::guile::testguile; + +fn main() { + testguile(); +} diff --git a/src/guile/mod.rs b/src/guile/mod.rs new file mode 100644 index 0000000..2368e61 --- /dev/null +++ b/src/guile/mod.rs @@ -0,0 +1 @@ +pub mod guile; @@ -1,2 +1,4 @@ +#[cfg(feature = "guile")] +pub mod guile; pub mod macro_processor; pub mod skaldpress; |