{"id":13702340,"url":"https://github.com/yvan-sraka/cargo-cabal","last_synced_at":"2025-10-06T23:05:00.061Z","repository":{"id":60718764,"uuid":"531876766","full_name":"yvan-sraka/cargo-cabal","owner":"yvan-sraka","description":"A tool that helps you to turn in one command a Rust crate into a Haskell Cabal library!","archived":false,"fork":false,"pushed_at":"2025-04-06T00:20:21.000Z","size":3227,"stargazers_count":102,"open_issues_count":6,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-10T06:15:28.512Z","etag":null,"topics":["haskell","rust"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/cargo-cabal","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yvan-sraka.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-02T10:14:53.000Z","updated_at":"2025-02-16T19:35:18.000Z","dependencies_parsed_at":"2023-10-01T01:26:10.283Z","dependency_job_id":"e3371a25-5e08-4186-922b-75597b68a644","html_url":"https://github.com/yvan-sraka/cargo-cabal","commit_stats":{"total_commits":26,"total_committers":2,"mean_commits":13.0,"dds":"0.038461538461538436","last_synced_commit":"e86e41ecadb17bb6144bae060723e7fd15b63d72"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yvan-sraka%2Fcargo-cabal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yvan-sraka%2Fcargo-cabal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yvan-sraka%2Fcargo-cabal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yvan-sraka%2Fcargo-cabal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yvan-sraka","download_url":"https://codeload.github.com/yvan-sraka/cargo-cabal/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248618243,"owners_count":21134200,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["haskell","rust"],"created_at":"2024-08-02T21:00:34.025Z","updated_at":"2025-10-06T23:04:55.018Z","avatar_url":"https://github.com/yvan-sraka.png","language":"Rust","funding_links":[],"categories":["Integration"],"sub_categories":["Dependencies analysers"],"readme":"\u003c!-- cargo-sync-readme start --\u003e\n\n# `cargo-cabal`\n\nA tool that helps you to turn in one command a Rust crate into a Haskell\nCabal library!\n\nTo generate bindings, you need to annotate the Rust function you want to\nexpose with [`hs-bindgen`](https://github.com/yvan-sraka/hs-bindgen) macro.\n\n## Getting started\n\nHere a little screencast demonstrating how it works (commands walkthrough\nare just pasted below):\n\n![asciinema](extra/cargo-cabal-opt.gif)\n\n\u003e **N.B.** You need in your `$PATH` a working Rust and Haskell environment,\n\u003e if you use [Nix](https://nixos.org) you can just enter:\n\u003e `nix-shell -p cabal-install ghc cargo rustc`\n\n---\n\nWelcome in this little `cargo-cabal` / `hs-bindgen` demo 🙂\n\nLet's start by creating a dumb Rust library!\n\n```text\n$ cargo new --lib greetings\n     Created library `greetings` package\n\n$ tree greetings\ngreetings\n├── Cargo.toml\n└── src\n    └── lib.rs\n\n1 directory, 2 files\n\n$ cd greetings\n```\n\nAdd `hs-bindgen` to the dependencies list:\n\n```text\n$ cargo add hs-bindgen --features full\n    Updating crates.io index\n      Adding hs-bindgen v0.8.0 to dependencies.\n             Features:\n             + antlion\n             + full\n             + std\n```\n\nAnd use it to decorate the function we want to expose:\n\n* `src/lib.rs`:\n\n```rust\nuse hs_bindgen::*;\n\n#[hs_bindgen]\nfn hello(name: \u0026str) {\n    println!(\"Hello, {name}!\");\n}\n```\n\n```text\n$ cargo build\n   Compiling proc-macro2 v1.0.47\n   Compiling quote v1.0.21\n   Compiling unicode-ident v1.0.5\n   Compiling syn v1.0.105\n   Compiling serde_derive v1.0.149\n   Compiling semver-parser v0.7.0\n   Compiling serde v1.0.149\n   Compiling thiserror v1.0.37\n   Compiling antlion v0.3.1\n   Compiling semver v0.9.0\n   Compiling semver v1.0.14\n   Compiling lazy_static v1.4.0\n   Compiling hs-bindgen-traits v0.8.0\n   Compiling rustc_version v0.2.3\n   Compiling hs-bindgen-attribute v0.7.2\n   Compiling thiserror-impl v1.0.37\n   Compiling displaydoc v0.2.3\n   Compiling hs-bindgen-types v0.8.0\n   Compiling toml v0.5.9\n   Compiling hs-bindgen v0.8.0\n   Compiling greetings v0.1.0 (/Users/yvan/demo/greetings)\nerror: custom attribute panicked\n --\u003e src/lib.rs:3:1\n  |\n3 | #[hs_bindgen]\n  | ^^^^^^^^^^^^^\n  |\n  = help: message: fail to read content of `hsbindgen.toml` configuration file\n          n.b. you have to run the command `cargo-cabal` to generate it: Os { code: 2, kind: NotFound, message: \"No such file or directory\" }\n\nerror: could not compile `greetings` due to previous error\n```\n\nSo, we will use `cargo-cabal` to check our setup and generate Cabal files:\n\n```text\n$ cargo install cargo-cabal\n    Updating crates.io index\n     Ignored package `cargo-cabal v0.7.0` is already installed, use --force to override\n\n$ cargo cabal init\nError: Your `Cargo.toml` file should contain a [lib] section with a `crate-type` field\nthat contains either `staticlib` or `cdylib` value, e.g.:\n\n[lib]\ncrate-type = [\"staticlib\"]\n```\n\n\u003e **N.B.** if you're a Nix user, rather than rely on impure `cargo install`,\n\u003e feel free to just `nix run github:yvan-sraka/cargo-cabal -- cabal init`\n\nRight, we edit the `Cargo.toml` accordingly:\n\n* `Cargo.toml`:\n\n```toml\n[package]\nname = \"greetings\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n[dependencies]\nhs-bindgen = { version = \"0.8.0\", features = [\"full\"] }\n\n[lib]\ncrate-type = [\"staticlib\"]\n```\n\n```text\n$ cargo cabal init\nCabal files generated!\n**********************\nYou should now be able to compile your library with `cabal build` and should\nadd `hs-bindgen` to your crate dependencies list and decorate the Rust function\nyou want to expose with `#[hs_bindgen]` attribute macro.\n\n$ ls\nCargo.lock  Cargo.toml  Setup.lhs  greetings.cabal  src  target\n```\n\n```text\n$ cargo build\n   Compiling greetings v0.1.0 (/Users/yvan/demo/greetings)\n    Finished dev [unoptimized + debuginfo] target(s) in 1.06s\n\n$ cabal build\nBuild profile: -w ghc-9.0.2 -O1\nIn order, the following will be built (use -v for more details):\n - greetings-0.1.0 (lib:greetings) (first run)\n[1 of 1] Compiling Main             ( omitted ... )\nLinking /Users/yvan/demo/dist-newstyle/build/aarch64-osx/ghc-9.0.2/greetings-0.1.0/setup/setup ...\nConfiguring greetings-0.1.0...\nPreprocessing library for greetings-0.1.0..\nBuilding library for greetings-0.1.0..\n[1 of 1] Compiling Greetings        ( src/Greetings.hs, omitted ... )\n```\n\nIt works! And so `cargo build` too if you just want to use the library in a\nRust project!\n\n---\n\nNow let's try to use our freshly generated library in an Haskell app 😉\n\n```text\n$ cd ..\n$ cabal init --non-interactive test\n[Log] Guessing dependencies...\n[Log] Using cabal specification: 3.8\n[Warning] unknown license type, you must put a copy in LICENSE yourself.\n[Log] Creating fresh file CHANGELOG.md...\n[Log] Creating fresh directory ./app...\n[Log] Creating fresh file app/Main.hs...\n[Log] Creating fresh file test.cabal...\n[Warning] No synopsis given. You should edit the .cabal file and add one.\n[Info] You may want to edit the .cabal file and add a Description field.\n\n$ tree test\ntest\n├── app\n│   └── Main.hs\n├── CHANGELOG.md\n└── test.cabal\n\n1 directory, 3 files\n```\n\nWe create a `cabal.project` (equivalent to cargo workspace) to perform a\nlocal test without having to upload `greetings` on hackage:\n\n* `cabal.project`:\n\n```cabal\npackages: ./greetings ./test\n```\n\nWe edit `test.cabal` to make it depends on `greetings` library:\n\n* `test/test.cabal` (content partially omitted):\n\n```cabal\nexecutable test\n    -- Other library packages from which modules are imported.\n    build-depends:    base, greetings\n```\n\nWe write a minimalist `main` function that will make call `hello` from\n`Greetings` module\n\n* `test/app/Main.hs`:\n\n```haskell\nmodule Main where\n\nimport Foreign.C.String\nimport Greetings\n\nmain :: IO ()\nmain = withCString \"Rust 🦀\" hello\n```\n\nLet's check if everything works as expected:\n\n```text\n$ cabal run test\nBuild profile: -w ghc-9.0.2 -O1\nIn order, the following will be built (use -v for more details):\n - test-0.1.0.0 (exe:test) (first run)\nConfiguring executable 'test' for test-0.1.0.0..\nPreprocessing executable 'test' for test-0.1.0.0..\nBuilding executable 'test' for test-0.1.0.0..\n[1 of 1] Compiling Main             ( app/Main.hs, omitted ... )\nLinking /Users/yvan/demo/dist-newstyle/build/aarch64-osx/ghc-9.0.2/test-0.1.0.0/x/test/build/test/test ...\nHello, Rust 🦀!\n```\n\nNow let's see if we can use the GHCi repl to call the functions defined in Rust.\n\n```text\nλ\u003e withCString \"aaa\" hello\nghc-9.4.8: ^^ Could not load '__c_hello', dependency unresolved. See top entry above.\n\n\nGHC.ByteCode.Linker: can't find label\nDuring interactive linking, GHCi couldn't find the following symbol:\n  __c_hello\nThis may be due to you not asking GHCi to load extra object files,\narchives or DLLs needed by your current session.  Restart GHCi, specifying\nthe missing library using the -L/path/to/object/dir and -lmissinglibname\nflags, or simply by naming the relevant files on the GHCi command line.\nAlternatively, this link failure might indicate a bug in GHCi.\nIf you suspect the latter, please report this as a GHC bug:\n  https://www.haskell.org/ghc/reportabug\n```\n\nIt seems like GHCi doesn't know how to link the library containing external\nfunctions. To fix this we first need to change the type of the Rust crate to\n`cdylib` in `Cargo.toml`. The reason why we need to do this is that GHCi can\nonly load dynamic libraries, not static ones.\n\n```toml\n[lib]\ncrate-type = [\"cdylib\"]\n```\nNow we need to tell GHCi explicitly where to look for those libraries. We can\ndo that by specifying the path in a `.ghci` file at the root of the project.\n\n```ghci\n:set -Ltarget/debug -lgreetings\n```\n\nAfter rebuilding the project with the necessary changes we can try once again:\n\n```text\n$ cabal repl\nBuild profile: -w ghc-9.4.8 -O1\nIn order, the following will be built (use -v for more details):\n - greetings-0.1.0 (ephemeral targets)\nPreprocessing library for greetings-0.1.0..\nGHCi, version 9.4.8: https://www.haskell.org/ghc/  :? for help\nLoaded GHCi configuration from /path/to/project/greetings/.ghci\n[1 of 1] Compiling Greetings        ( src/Greetings.hs, interpreted )\nOk, one module loaded.\nλ\u003e withCString \"Rust\" hello\nHello, Rust!\n```\n\nThat's all folks! Happy hacking 🙂\n\n## Nix support\n\nThe `--enable-nix` CLI arg makes `cargo-cabal` generate a\n[haskell.nix](https://github.com/input-output-hk/haskell.nix) /\n[naersk](https://github.com/nix-community/naersk) based `flake.nix` rather\nthan the `Setup.lhs`.\n\n\u003e **N.B.** when first working with `hs-bindgen` and Nix flakes, checking if\n\u003e `Cargo.lock` isn't in `.gitignore` and running `cargo build` and\n\u003e `git add --all` before `nix build`, will save you a lot of pain 😉\n\n## Acknowledgments\n\n⚠️ This is still a working experiment, not yet production ready.\n\n`cargo-cabal` was heavily inspired by other interoperability initiatives, as\n[`wasm-pack`](https://github.com/rustwasm/wasm-pack) and\n[`Maturin`](https://github.com/PyO3/maturin).\n\nThis project was part of a work assignment as an\n[IOG](https://github.com/input-output-hk) contractor.\n\n## License\n\nLicensed under either of [Apache License](LICENSE-APACHE), Version 2.0 or\n[MIT license](LICENSE-MIT) at your option.\n\nUnless you explicitly state otherwise, any contribution intentionally submitted\nfor inclusion in this project by you, as defined in the Apache-2.0 license,\nshall be dual licensed as above, without any additional terms or conditions.\n\n\u003c!-- cargo-sync-readme end --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyvan-sraka%2Fcargo-cabal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyvan-sraka%2Fcargo-cabal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyvan-sraka%2Fcargo-cabal/lists"}