https://github.com/dfinity/canpack
Package multiple libraries into one ICP canister.
https://github.com/dfinity/canpack
bundler candid canister cross-language dfinity icp language-bindings mops motoko rust
Last synced: about 1 month ago
JSON representation
Package multiple libraries into one ICP canister.
- Host: GitHub
- URL: https://github.com/dfinity/canpack
- Owner: dfinity
- License: apache-2.0
- Created: 2024-02-17T22:37:42.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-12-03T12:22:34.000Z (10 months ago)
- Last Synced: 2025-03-30T07:32:33.273Z (6 months ago)
- Topics: bundler, candid, canister, cross-language, dfinity, icp, language-bindings, mops, motoko, rust
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/canpack
- Size: 1.45 MB
- Stars: 10
- Watchers: 5
- Forks: 0
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# `canpack` [](https://www.npmjs.com/package/canpack) [](https://opensource.org/licenses/Apache-2.0)
Canpack is a code generation tool which simplifies cross-language communication in [Internet Computer](https://internetcomputer.org/) canisters (such as calling a [Rust](https://www.rust-lang.org/) crate from [Motoko](https://github.com/dfinity/motoko)). This works by generating a separate canister from the host language, combining fragments defined across multiple libraries.
**Note:** This project is early in development; unannounced breaking changes may occur at any time.
## Installation
Ensure that the following software is installed on your system:
* [dfx](https://support.dfinity.org/hc/en-us/articles/10552713577364-How-do-I-install-dfx) (latest version)
* [Rust](https://www.rust-lang.org/tools/install) `>= 1.71`
* [Node.js](https://nodejs.org/en) `>= 18`Run the following command to install the Canpack CLI on your global system path:
```
npm install -g canpack
```## Quick Start (Motoko + Rust)
Canpack has built-in support for the [Mops](https://mops.one/) package manager.
In your canister's `mops.toml` file, add a `rust-dependencies` section:
```toml
[rust-dependencies]
canpack-example-hello = "^0.1"
local-crate = { path = "path/to/local-crate" }
```You can also specify `[rust-dependencies]` in a Motoko package's `mops.toml` file to include Rust crates in any downstream canisters.
Next, run the following command in the directory with the `mops.toml` and `dfx.json` files:
```bash
canpack
```This will configure and generate a `motoko_rust` canister with Candid bindings for the specified dependencies. Here is a Motoko canister which uses a function defined in the [`canpack-example-hello`](https://docs.rs/canpack-example-hello/latest/src/canpack_example_hello/lib.rs.html) crate:
```motoko
import Rust "canister:motoko_rust";actor {
public composite query func hello(name: Text) : async Text {
await Rust.canpack_example_hello(name)
}
}
```Any Rust crate with Canpack compatibility can be specified as a standard [`Cargo.toml` dependency](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html). See the [Rust Crates](#rust-crates) section for more details.
## Rust Crates
It's relatively simple to add Canpack support to any IC Wasm-compatible Rust crate.
Here is the full implementation of the [`canpack-example-hello`](https://docs.rs/canpack-example-hello/latest/src/canpack_example_hello/lib.rs.html) package:
```rust
canpack::export! {
pub fn canpack_example_hello(name: String) -> String {
format!("Hello, {name}!")
}
}
```If needed, you can configure the generated Candid method using a `#[canpack]` attribute:
```rust
canpack::export! {
#[canpack(composite_query, rename = "canpack_example_hello")]
pub fn hello(name: String) -> String {
format!("Hello, {name}!")
}
}
```Note that it is possible to reference local constants, methods, etc.
```rust
const WELCOME: &str = "Welcome";fn hello(salutation: &str, name: String) -> String {
format!("{salutation}, {name}!")
}canpack::export! {
pub fn canpack_example_hello(name: String) -> String {
hello(WELCOME, name)
}
}
```The `canpack::export!` shorthand requires adding [`canpack`](https://crates.io/crates/canpack) as a dependency in your Cargo.toml file. It's also possible to manually define Candid methods by exporting a `canpack!` macro:
```rust
pub fn hello(name: String) -> String {
format!("Hello, {name}!")
}#[macro_export]
macro_rules! canpack {
() => {
#[ic_cdk::query]
#[candid::candid_method(query)]
fn canpack_example_hello(name: String) -> String {
$crate::hello(name)
}
};
}
```## Advanced Usage
### `canpack.json`
Pass the `-v` or `--verbose` flag to view the resolved JSON configuration for a project:
```bash
canpack --verbose
```Below is a step-by-step guide for setting up a `dfx` project with a `canpack.json` config file. The goal here is to illustrate how one could use Canpack without additional tools such as Mops, which is specific to the Motoko ecosystem.
Run `dfx new my_project`, selecting "Motoko" for the backend and "No frontend canister" for the frontend. Once complete, run `cd my_project` and open in your editor of choice.
Add a new file named `canpack.json` in the same directory as `dfx.json`.
In the `canpack.json` file, define a Rust canister named `my_project_backend_rust`:
```json
{
"canisters": {
"my_project_backend_rust": {
"type": "rust",
"parts": [{
"package": "canpack-example-hello",
"version": "^0.1"
}]
}
}
}
```Next, run the following command in this directory to generate all necessary files:
```bash
canpack
```In your `dfx.json` file, configure the `"dependencies"` for the Motoko canister:
```json
{
"canisters": {
"my_project_backend": {
"dependencies": ["my_project_backend_rust"],
"main": "src/my_project_backend/main.mo",
"type": "motoko"
}
},
}
```Now you can call Rust functions from Motoko using a canister import:
```motoko
import Rust "canister:my_project_backend_rust";actor {
public func hello(name: Text) : async Text {
await Rust.canpack_example_hello(name)
}
}
```Run the following commands to build and deploy the `dfx` project on your local machine:
```
dfx start --background
dfx deploy
```### Programmatic API
Canpack may be used as a low-level building block for package managers and other development tools.
Add the `canpack` dependency to your Node.js project with the following command:
```bash
npm i --save canpack
```The following example JavaScript code runs Canpack in the current working directory:
```js
import { canpack } from 'canpack';const config = {
verbose: true,
canisters: {
my_canister: {
type: 'rust',
parts: [{
package: 'canpack-example-hello',
version: '^0.1',
}]
}
}
};await canpack(config);
```---
This project is early in development. Please feel free to report a bug, ask a question, or request a feature on the project's [GitHub issues](https://github.com/dfinity/canpack/issues) page.
Contributions are welcome! Please check out the [contributor guidelines](https://github.com/dfinity/canpack/blob/main/.github/CONTRIBUTING.md) for more information.