Il programma principale è codice Python, quindi ci serve un ambiente virtuale adatto. Immaginiamo di lavorare ad un progetto nuovo e creiamo una cartella. Questa sarà la nostra root.

All'interno della root lanciamo:

python3 -m venv env

Per entrare nell'ambiente appena creato:

source env/bin/activate

Ci serve un file in cui scrivere l'entry point del programma python. Come è convenzione fare, lo chiamiamo main.py. Per crearlo facilmente, possiamo agire direttamente dal terminale e lanciare

touch main.py

Per il momento lasciamolo vuoto ed occupiamoci del vero codice, quello in rust. Lanciamo:

cargo new progetto

Cargo si occupa della parte più noiosa e crea i file utili per noi.

TODO: scrivere schema ASCII con gerarchia dei file

cd progetto
nano Cargo.toml

A questo punto modifichiamo così il file:

# Cargo.toml

[package]
name = "progetto"
version = "0.1.0"
authors = ["mr-chrome <giovanni.crisalfi@gmail.com>"]
edition = "2018"

[lib]
name = "progetto"
crate-type = ["cdylib"]

[dependencies.pyo3]
version = "0.12.4"
features = ["extension-module"]

Cosa abbiamo scritto? Sotto [package] le solite informazioni, quelle che servono per ogni progetto in rust:

  • il nome del progetto
  • la versione che sarà aggiornata da noi in base allo stato di completamento del codice
  • Gli autori con nick ed email
  • L'edizione di Rust in uso

Sotto [lib] è fondamentale scrivere lo stesso nome che utilizzeremo all'interno del file src/lib.rs che stiamo per scrivere. Infine le dipendenze.

Salviamo e passiamo al prossimo file.

nano src/lib.rs

Scrivere questo codice:

// src/lib.rs

use pyo3::prelude::*;
use pyo3::wrap_pyfunction;

/// Formats the sum of two numbers as string.
#[pyfunction]
fn say_hi_to(name: &str) -> PyResult<String> {
    Ok(format!("Hi, {}!", name))
}

/// A Python module implemented in Rust.
#[pymodule]
fn progetto(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_function(wrap_pyfunction!(say_hi_to, m)?)?;
    Ok(())
}

Nelle prime due righe abbiamo importato pyo3, dopodiché abbiamo sfruttato una macro per dichiarare la nostra funzione. La macro portante è quella finale, giacché lì è specificato il modulo sotto cui verranno raccolte tutte le funzioni di cui abbiamo bisogn. Come si può notare, ha lo stesso nome del progetto specificato in Cargo.toml.

La funzione che abbiamo scritto non fa altro che prendere il nome che riceve come input e wrapparlo in una semplice frase che saluta l'interlocutore.

A questo punto salviamo il file e compiliamo:

cargo build --release

Per il prossimo comando è importante che il virtual env sia attivo. Se non lo è, attivarlo adesso tornando nella root e digitando: source env/bin/activate, quindi tornare in progetto e lanciare:

pip3 install maturin && maturin develop

A questo punto il nostro modulo dovrebbe essere disponibile per tutto l'ambiente python. Torniamo nella root:

nano main.py

Copiare questo codice:

# main.py

from progetto import say_hi_to
name = input("Digit your name:\n")
print(say_hi_to(name) + "\n")
input("Press any button to exit.")

Salvare il file e testare il programma:

python3 main.py

Il programma chiederà il tuo nome, facciamo Cromo, quindi mosterà:

Digit your name:
Cromo
Hi, Cromo!

Press any button to exit.

Bene, il nostro modulo è stato importato con successo e la funzione ha svolto il proprio sacrosanto lavoro.