Quickstart Guide¶
Get started with Polyglot FFI in 5 minutes!
Installation¶
From PyPI¶
From Source¶
Verify Installation¶
Your First Project¶
Step 1: Initialize a New Project¶
Note: You can use hyphens in project names (like my-crypto-lib). Polyglot-ffi automatically converts them to underscores in generated code for compatibility with OCaml, C, and Python naming rules.
This creates:
my-crypto-lib/
├── polyglot.toml # Configuration
├── README.md # Project documentation
├── Makefile # Convenience commands
├── .gitignore # Git ignore rules
└── src/
├── my-crypto-lib.mli # OCaml interface (edit this)
└── my-crypto-lib.ml # OCaml implementation (edit this)
Step 2: Define Your API¶
Edit src/my-crypto-lib.mli:
(* my-crypto-lib.mli *)
val encrypt : string -> string
(** Encrypt a string using Caesar cipher *)
val decrypt : string -> string
(** Decrypt a string using Caesar cipher *)
val hash : string -> int
(** Simple hash function *)
Step 3: Generate Bindings¶
Output:
✓ Bindings generated successfully!
Generated files:
✓ generated/type_description.ml
✓ generated/function_description.ml
✓ generated/my_crypto_stubs.c
✓ generated/my_crypto_stubs.h
✓ generated/dune
✓ generated/dune-project
✓ generated/my_crypto_py.py
Generated 3 function(s)
Step 4: Implement Your OCaml Functions¶
Edit src/my-crypto-lib.ml:
(* my-crypto-lib.ml *)
let encrypt s =
String.map (fun c ->
if c >= 'a' && c <= 'z' then
Char.chr ((Char.code c - Char.code 'a' + 3) mod 26 + Char.code 'a')
else c
) s
let decrypt s =
String.map (fun c ->
if c >= 'a' && c <= 'z' then
Char.chr ((Char.code c - Char.code 'a' - 3 + 26) mod 26 + Char.code 'a')
else c
) s
let hash s =
String.fold_left (fun acc c -> acc * 31 + Char.code c) 0 s
(* Register functions for C FFI *)
let () =
Callback.register "encrypt" encrypt;
Callback.register "decrypt" decrypt;
Callback.register "hash" hash
Step 5: Build (Optional - if you have OCaml/Dune)¶
First, install OCaml build dependencies:
Then build your bindings:
# Copy implementation to generated directory
# Note: If your project name has hyphens, rename files to use underscores
cp src/my-crypto-lib.ml generated/my_crypto_lib.ml
cp src/my-crypto-lib.mli generated/my_crypto_lib.mli
cd generated
dune build
Important: When copying source files with hyphens in their names, rename them to use underscores (e.g., my-crypto-lib.ml → my_crypto_lib.ml). This ensures compatibility with OCaml's module naming requirements.
Using OCaml Standard Libraries:
If your OCaml code uses libraries like Str, Unix, or Thread, specify them in your polyglot.toml:
[source]
language = "ocaml"
dir = "src"
files = ["my_crypto_lib.mli"]
libraries = ["str", "unix"] # Add libraries your code uses
See Configuration Guide for more details.
Step 6: Use from Python¶
# test_crypto.py
from generated.my_crypto_py import encrypt, decrypt, hash
# Test encryption
message = "hello"
encrypted = encrypt(message)
print(f"Original: {message}")
print(f"Encrypted: {encrypted}") # "khoor"
# Test decryption
decrypted = decrypt(encrypted)
print(f"Decrypted: {decrypted}") # "hello"
# Test hash
hash_val = hash(message)
print(f"Hash: {hash_val}")
Common Workflows¶
Generate with Custom Output¶
# Specify output directory and module name
polyglot-ffi generate src/module.mli -o bindings/ -n mymodule
# Dry run (see what would be generated)
polyglot-ffi generate src/module.mli --dry-run
# Force regeneration
polyglot-ffi generate src/module.mli --force
Using the Makefile¶
The generated Makefile provides convenient commands:
# Generate bindings
make generate
# Build OCaml library
make build
# Clean generated files
make clean
# Run tests
make test
Example: Multiple Function Types¶
(* example.mli *)
(* String operations *)
val greet : string -> string
(** Greet someone *)
(* Math operations *)
val add : int -> int -> int
(** Add two integers *)
val multiply : float -> float -> float
(** Multiply two floats *)
(* Boolean operations *)
val is_even : int -> bool
(** Check if number is even *)
(* No parameters *)
val get_version : unit -> string
(** Get library version *)
Generate and use:
from gen.example_py import greet, add, multiply, is_even, get_version
print(greet("Alice")) # "Hello, Alice!"
print(add(2, 3)) # 5
print(multiply(2.5, 4.0)) # 10.0
print(is_even(4)) # True
print(get_version()) # "1.0.0"
Supported Types¶
Primitive Types¶
| OCaml Type | C Type | Python Type | Example |
|---|---|---|---|
string |
char* |
str |
"hello" |
int |
int |
int |
42 |
float |
double |
float |
3.14 |
bool |
int |
bool |
True |
unit |
void |
None |
None |
Complex Types¶
| OCaml Type | Python Type | Example |
|---|---|---|
'a option |
Optional[T] |
Optional[int] |
'a list |
List[T] |
List[str] |
'a * 'b |
Tuple[T, U] |
Tuple[int, str] |
See Type Mapping Guide for complete reference.
Project Structure¶
After initialization:
my-project/
├── polyglot.toml # Configuration
├── README.md # Documentation
├── Makefile # Build commands
├── .gitignore # Git ignore
│
├── src/ # Your OCaml source
│ ├── my-project.mli # Interface (edit this)
│ └── my-project.ml # Implementation (edit this)
│
└── generated/ # Generated bindings (don't edit)
├── type_description.ml # OCaml types
├── function_description.ml # OCaml ctypes
├── my-project_stubs.c # C wrappers
├── my-project_stubs.h # C headers
├── dune # Build config
├── dune-project # Dune metadata
└── my-project_py.py # Python wrapper
Configuration File¶
polyglot.toml:
[project]
name = "my-project"
version = "0.1.0"
source_lang = "ocaml"
[languages.ocaml]
source_dir = "src"
build_system = "dune"
[languages.python]
target_dir = "generated"
min_version = "3.8"
[bindings]
auto_discover = true
interfaces = ["src/my-project.mli"]
[generate]
watch = false
verbose = false
Advanced Features¶
Watch Mode (Auto-regenerate)¶
# Watch files and auto-regenerate on changes
polyglot-ffi watch src/*.mli
# Watch with auto-build
polyglot-ffi watch src/*.mli --build
Validate Configuration¶
# Check project configuration
polyglot-ffi check
# Check with dependencies
polyglot-ffi check --check-deps
Clean Generated Files¶
Next Steps¶
- Complex types: Try options, lists, and tuples
- Watch mode: Use
polyglot-ffi watchfor auto-regeneration - Configuration: Customize
polyglot.tomlfor your project - Multiple modules: Generate bindings for each
.mlifile - CI/CD: Add
polyglot-ffi generateto your build pipeline - Examples: Check out
examples/directory for more patterns
Troubleshooting¶
Command not found¶
# Make sure you're in a virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install
pip install -e ".[dev]"
Import errors in Python¶
Make sure the shared library is built and in the correct location. The Python wrapper expects lib{module_name}.so in the same directory.
Parse errors¶
Check your .mli syntax:
- Use val name : type format
- Currently supports only primitive types
- Multi-line signatures need continuation
Help and Support¶
# Get help
polyglot-ffi --help
# Command-specific help
polyglot-ffi init --help
polyglot-ffi generate --help
polyglot-ffi watch --help
polyglot-ffi check --help
polyglot-ffi clean --help
Resources¶
- Documentation: https://polyglotffi.com/
- Quick Reference: quick_reference.md
- Type Mapping: type-mapping.md
- Architecture: architecture.md
- Issues: https://github.com/chizy7/polyglot-ffi/issues
- Examples: See
examples/directory in repository
Upgrading¶
# Upgrade to latest version
pip install --upgrade polyglot-ffi
# Check version
polyglot-ffi --version
See Installation Guide for more options.
Ready to eliminate FFI boilerplate? Let's build something amazing!
Version: 0.5.1 | Documentation: https://polyglotffi.com/