changelog shortlog graph tags branches files raw help

Mercurial > org > blog / changeset: bump

changeset 19: 84097475a40a
parent 18: d77884ec2b44
child 20: 889759cafcc2
author: Richard Westhaver <ellis@rwest.io>
date: Sun, 02 Jun 2024 20:06:36 -0400
files: draft/dylib-skel.org
description: bump
     1.1--- a/draft/dylib-skel.org	Sun Apr 28 19:49:20 2024 -0400
     1.2+++ b/draft/dylib-skel.org	Sun Jun 02 20:06:36 2024 -0400
     1.3@@ -1,5 +1,8 @@
     1.4 #+title: Shared Library Skeletons
     1.5 * Overview
     1.6+:PROPERTIES:
     1.7+:ID:       748ba6e4-60db-4ff7-9d78-12c3f67644d8
     1.8+:END:
     1.9 + CODE :: [[https://lab.rwest.io/packy/stash/dysk][packy/stash/dysk]]
    1.10 Our core languages are [[https://www.rust-lang.org/][Rust]] and [[https://lisp-lang.org/][Lisp]] - this is the killer combo which will allow NAS-T
    1.11 to rapidly develop high-quality software. As such, it's crucial that these two very
    1.12@@ -13,12 +16,18 @@
    1.13 most popular software stack (yet ;). This is an experiment and may not make it to our
    1.14 code-base, but it's definitely something worth adding to the toolbox in case we need it.
    1.15 ** FFI
    1.16+:PROPERTIES:
    1.17+:ID:       0e490b3b-0c15-4963-9d43-7d2a689ec371
    1.18+:END:
    1.19 The level of interop we're after in this case is [[https://en.wikipedia.org/wiki/Foreign_function_interface][FFI]].
    1.20 
    1.21 Basically, calling Rust code from Lisp and vice-versa. There's an article about calling
    1.22 Rust from Common Lisp [[https://dev.to/veer66/calling-rust-from-common-lisp-45c5][here]] which shows the basics and serves as a great starting point
    1.23 for those interested.
    1.24 *** Rust ABI
    1.25+:PROPERTIES:
    1.26+:ID:       6c24dc95-eea6-44fb-8c7f-bb49227ca7bf
    1.27+:END:
    1.28 The complication(s) with Rust I mentioned early is really just that /it is not C/. =C=
    1.29 is old, i.e. well-supported with a stable ABI, making the process of creating bindings
    1.30 for a C library a breeze in many languages.
    1.31@@ -35,17 +44,29 @@
    1.32 friction-less FFI development experience in Rust.
    1.33 
    1.34 *** Overhead
    1.35+:PROPERTIES:
    1.36+:ID:       faf8fbcb-3403-4e2f-b881-ef1404ad9780
    1.37+:END:
    1.38 Using FFI involves some overhead. Check [[https://github.com/dyu/ffi-overhead][here]] for an example benchmark across a few
    1.39 languages. While building the NAS-T core, I'm very much aware of this, and will need a
    1.40 few sanity benchmarks to make sure the cost doesn't outweigh the benefit. In particular,
    1.41 I'm concerned about crossing multiple language barriers (Rust<->C<->Lisp).
    1.42 
    1.43 * basic example
    1.44+:PROPERTIES:
    1.45+:ID:       ab04fff7-51c9-4f1c-b61b-fa4739932343
    1.46+:END:
    1.47 ** Setup
    1.48+:PROPERTIES:
    1.49+:ID:       08420b18-3856-4b62-9523-98fb3398afca
    1.50+:END:
    1.51 For starters, I'm going to assume we all have Rust (via [[https://rustup.rs/][rustup]]) and Lisp ([[https://www.sbcl.org/][sbcl]] only)
    1.52 installed on our GNU/Linux system (some tweaks needed for Darwin/Windows, not covered in
    1.53 this post).
    1.54 *** Cargo
    1.55+:PROPERTIES:
    1.56+:ID:       cfeb1299-67c5-4a64-863e-f214e195e176
    1.57+:END:
    1.58 Create a new library crate. For this example we're focusing on a 'skeleton' for
    1.59 /dynamic/ libraries only, so our experiment will be called =dylib-skel= or *dysk* for
    1.60 short.
    1.61@@ -68,7 +89,13 @@
    1.62 This tells Rust to generate a shared C-compatible object with a =.so= extension which we
    1.63 can open using [[https://man.archlinux.org/man/dlopen.3.en][dlopen]].
    1.64 *** cbindgen
    1.65+:PROPERTIES:
    1.66+:ID:       435d84d6-c959-4bf6-ad37-fb6e524b54ff
    1.67+:END:
    1.68 **** install
    1.69+:PROPERTIES:
    1.70+:ID:       15115ab8-e7b4-4050-9567-bf026cc140d1
    1.71+:END:
    1.72 Next, we want the =cbindgen= program which we'll use to generate header files for
    1.73 C/C++. This step isn't necessary at all, we just want it for further experimentation.
    1.74 
    1.75@@ -80,6 +107,9 @@
    1.76 cbindgen = "0.24"
    1.77 #+end_src
    1.78 **** cbindgen.toml
    1.79+:PROPERTIES:
    1.80+:ID:       21d776b7-9f8d-445c-83c2-8e0c28751827
    1.81+:END:
    1.82 #+begin_src conf-toml :tangle cbindgen.toml
    1.83 language = "C"
    1.84 autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
    1.85@@ -96,6 +126,9 @@
    1.86 header = "dysk.h"
    1.87 #+end_src
    1.88 **** build.rs
    1.89+:PROPERTIES:
    1.90+:ID:       469dd142-bafa-4076-8ba9-baf088e60260
    1.91+:END:
    1.92 #+begin_src rust :tangle build.rs
    1.93 fn main() -> Result<(), cbindgen::Error> {
    1.94   if let Ok(b) = cbindgen::generate(std::env::var("CARGO_MANIFEST_DIR").unwrap()) {
    1.95@@ -103,6 +136,9 @@
    1.96   else { panic!("failed to generate dysk.h from cbindgen.toml") } }
    1.97 #+end_src
    1.98 ** lib.rs
    1.99+:PROPERTIES:
   1.100+:ID:       e9d50e77-4d1e-4d38-90aa-9977d8c6c888
   1.101+:END:
   1.102 #+begin_src rust :tangle lib.rs
   1.103 //! lib.rs --- dysk library
   1.104 use std::ffi::{c_char, c_int, CString};
   1.105@@ -115,15 +151,24 @@
   1.106 pub extern "C" fn plus1(n:c_int) -> c_int {n+1}
   1.107 #+end_src
   1.108 ** test.rs
   1.109+:PROPERTIES:
   1.110+:ID:       84b5dffe-7171-4d72-9788-f288e3185070
   1.111+:END:
   1.112 #+begin_src rust :tangle test.rs
   1.113 //! test.rs --- dysk test
   1.114 fn main() { let mut i = 0u32; while i < 500000000 {i+=1; dysk::plus1(2 as core::ffi::c_int);}}
   1.115 #+end_src
   1.116 ** compile
   1.117+:PROPERTIES:
   1.118+:ID:       30f4fb3e-0757-4df6-947f-8d1e11edabf9
   1.119+:END:
   1.120 #+begin_src sh
   1.121 cargo build --release
   1.122 #+end_src
   1.123 ** load from SBCL
   1.124+:PROPERTIES:
   1.125+:ID:       69b517f2-648d-4e44-b956-7879b3dadf99
   1.126+:END:
   1.127 #+begin_src lisp :tangle dysk.lisp
   1.128 ;;; dysk.lisp
   1.129 ;; (dysk:hello) ;; => "hello from rust"
   1.130@@ -137,6 +182,9 @@
   1.131 (define-alien-routine plus1 int (n int))
   1.132 #+end_src
   1.133 ** benchmark
   1.134+:PROPERTIES:
   1.135+:ID:       86e4195d-601b-4736-b852-1209a6d38bdf
   1.136+:END:
   1.137 #+begin_src shell
   1.138 time target/release/dysk-test
   1.139 #+end_src