#! { "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 :)