#! { "step": 0.10, "width": 80, "height": 20 } $ # Welcome in this little `cargo-cabal` / `hs-bindgen` demo :) $ # Let's start by creating a dumb Rust library! $ cargo new --lib greetings Created library `greetings` package $ tree greetings greetings ├── Cargo.toml └── src └── lib.rs 1 directory, 2 files $ cd greetings $ # Add `hs-bindgen` to the dependencies list: $ cargo add hs-bindgen --features full Updating crates.io index Adding hs-bindgen v0.7.1 to dependencies. Features: + antlion + full + std $ # And use it to decorate the function we want to expose: $ cat -n src/lib.rs 1 use hs_bindgen::*; 2 3 #[hs_bindgen] 4 fn hello(name: &str) { 5 println!("Hello, {name}!"); 6 } #timeout: 1.5 $ cargo build Compiling proc-macro2 v1.0.47 Compiling quote v1.0.21 Compiling unicode-ident v1.0.5 Compiling syn v1.0.105 Compiling serde_derive v1.0.149 Compiling semver-parser v0.7.0 Compiling serde v1.0.149 Compiling thiserror v1.0.37 Compiling antlion v0.3.1 Compiling semver v0.9.0 Compiling semver v1.0.14 Compiling lazy_static v1.4.0 Compiling hs-bindgen-traits v0.7.1 Compiling rustc_version v0.2.3 Compiling hs-bindgen-attribute v0.7.2 Compiling thiserror-impl v1.0.37 Compiling displaydoc v0.2.3 Compiling hs-bindgen-types v0.7.1 Compiling toml v0.5.9 Compiling hs-bindgen v0.7.1 Compiling greetings v0.1.0 (/Users/yvan/demo/greetings) error: custom attribute panicked --> src/lib.rs:3:1 | 3 | #[hs_bindgen] | ^^^^^^^^^^^^^ | = help: message: fail to read content of `hsbindgen.toml` configuration file n.b. you have to run the command `cargo-cabal` to generate it: Os { code: 2, kind: NotFound, message: "No such file or directory" } error: could not compile `greetings` due to previous error $ # So, we will use `cargo-cabal` to check our setup and generate Cabal files: $ cargo install cargo-cabal Updating crates.io index Ignored package `cargo-cabal v0.7.0` is already installed, use --force to override $ cargo cabal init Error: Your `Cargo.toml` file should contain a [lib] section with a `crate-type` field that contains either `staticlib` or `cdylib` value, e.g.: [lib] crate-type = ["staticlib"] $ # Right, we edit the `Cargo.toml` accordingly: $ cat -n Cargo.toml 1 [package] 2 name = "greetings" 3 version = "0.1.0" 4 edition = "2021" 5 6 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 8 [dependencies] 9 hs-bindgen = { version = "0.7.1", features = ["full"] } 10 11 [lib] 12 crate-type = ["staticlib"] $ cargo cabal init Cabal files generated! ********************** You should now be able to compile your library with `cabal build` and should add `hs-bindgen` to your crate dependencies list and decorate the Rust function you want to expose with `#[hs_bindgen]` attribute macro. $ ls Cargo.lock Cargo.toml Setup.lhs greetings.cabal src target #timeout: 1.5 $ cargo build Compiling greetings v0.1.0 (/Users/yvan/demo/greetings) Finished dev [unoptimized + debuginfo] target(s) in 1.06s $ cabal build Build profile: -w ghc-9.0.2 -O1 In order, the following will be built (use -v for more details): - greetings-0.1.0 (lib:greetings) (first run) [1 of 1] Compiling Main ( omitted ... ) Linking /Users/yvan/demo/dist-newstyle/build/aarch64-osx/ghc-9.0.2/greetings-0.1.0/setup/setup ... Configuring greetings-0.1.0... Preprocessing library for greetings-0.1.0.. Building library for greetings-0.1.0.. [1 of 1] Compiling Greetings ( src/Greetings.hs, omitted ... ) $ # It works! -- $ # Now let's try to use our freshly generated library in an Haskell app ;) $ cd .. $ cabal init --non-interactive test [Log] Guessing dependencies... [Log] Using cabal specification: 3.8 [Warning] unknown license type, you must put a copy in LICENSE yourself. [Log] Creating fresh file CHANGELOG.md... [Log] Creating fresh directory ./app... [Log] Creating fresh file app/Main.hs... [Log] Creating fresh file test.cabal... [Warning] No synopsis given. You should edit the .cabal file and add one. [Info] You may want to edit the .cabal file and add a Description field. $ tree test test ├── app │   └── Main.hs ├── CHANGELOG.md └── test.cabal 1 directory, 3 files $ # We create a `cabal.project` (equivalent to cargo workspace) to perform a $ # local test without having to upload `greetings` on hackage: $ cat -n cabal.project 1 packages: ./greetings ./test $ # We edit `test.cabal` to make it depends on `greetings` library: $ cat -n test/test.cabal .. 53 executable test .. 66 -- Other library packages from which modules are imported. 67 build-depends: base, greetings .. .. (output partially omitted) #timeout: 1.5 $ # We write a minimalist `main` function that will make call `hello` from $ # `Greetings` module $ cat -n test/app/Main.hs 1 module Main where 2 3 import Foreign.C.String 4 import Greetings 5 6 main :: IO () 7 main = withCString "Rust 🦀" hello #timeout: 1.5 $ # Let's check if everything works as expected: $ cabal run test Build profile: -w ghc-9.0.2 -O1 In order, the following will be built (use -v for more details): - test-0.1.0.0 (exe:test) (first run) Configuring executable 'test' for test-0.1.0.0.. Preprocessing executable 'test' for test-0.1.0.0.. Building executable 'test' for test-0.1.0.0.. [1 of 1] Compiling Main ( app/Main.hs, omitted ... ) Linking /Users/yvan/demo/dist-newstyle/build/aarch64-osx/ghc-9.0.2/test-0.1.0.0/x/test/build/test/test ... Hello, Rust 🦀! #timeout: 1.5 $ # That's all folks! Happy hacking :)