Skip to main content

Milksnake

Milksnake is an extension for setuptools that allows you to distribute dynamic linked libraries in Python wheels in the most portable way imaginable.

It gives you a hook to invoke your own build process and to then take the resulting dynamic linked library.

Why?

There are already other projects that make Python and native libraries play along but this one is different. Unlike other projects that build Python extension modules the goal of this project is to build regular native libraries that are then loaded with CFFI at runtime. Why not just use CFFI? Because CFFI's setuptools support alone does not properly work with such wheels (it does not provide a way to build and properly tag wheels for shared libraries) and it does not provide a good way to invoke an external build process (like a makefile, cargo to build rust binaries etc.)

In particular you will most likely only need two wheels for Linux, one for macs and soon one for Windows independently of how many Python interpreters you want to target.

What is supported?

  • Platforms: Linux, Mac, Windows
  • setuptools commands: bdist_wheel, build, build_ext, develop
  • pip install --editable .
  • Universal wheels (PACKAGE-py2.py3-none-PLATFORM.whl); this can be disabled with milksnake_universal=False in setup() in case the package also contains stuff that does link against libpython.

How?

This example shows how to build a rust project with it:

This is what a setup.py file looks like:

from setuptools import setup

def build_native(spec):
    # build an example rust library
    build = spec.add_external_build(
        cmd=['cargo', 'build', '--release'],
        path='./rust'
    )

    spec.add_cffi_module(
        module_path='example._native',
        dylib=lambda: build.find_dylib('example', in_path='target/release'),
        header_filename=lambda: build.find_header('example.h', in_path='target'),
        rtld_flags=['NOW', 'NODELETE']
    )

setup(
    name='example',
    version='0.0.1',
    packages=['example'],
    zip_safe=False,
    platforms='any',
    setup_requires=['milksnake'],
    install_requires=['milksnake'],
    milksnake_tasks=[
        build_native
    ]
)

You then need a rust/ folder that has a Rust library (with a crate type of cdylib) and a example/ python package.

Example example/__init__.py file:

from example._native import ffi, lib


def test():
    return lib.a_function_from_rust()

And a rust/src/lib.rs:

#[no_mangle]
pub unsafe extern "C" fn a_function_from_rust() -> i32 {
    42
}

And the rust/Cargo.toml:

[package]
name = "example"
version = "0.1.0"
build = "build.rs"

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

[build-dependencies]
cbindgen = "0.4"

And finally the build.rs file:

extern crate cbindgen;

use std::env;

fn main() {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let mut config: cbindgen::Config = Default::default();
    config.language = cbindgen::Language::C;
    cbindgen::generate_with_config(&crate_dir, config)
      .unwrap()
      .write_to_file("target/example.h");
}

Metadata

Release files for milksnake 0.1.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for milksnake 0.1.6
File Size Uploaded
milksnake-0.1.6.tar.gz 10.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for milksnake 0.1.6
File Interpreter ABI Platform
milksnake-0.1.6-py2.py3-none-any.whl Python 2, Python 3 none any Details

Total release size: 21.6 kB

Release files / milksnake-0.1.6.tar.gz

Download URL milksnake-0.1.6.tar.gz
Size 10.5 kB
Tags Source
SHA-256 checksum
How to use checksums
0198f8932b4e136c29c0d0d490ff1bac03f82c3a7b2ee6f666e3683b64314fd9
BLAKE2b-256 checksum
How to use checksums
379c100deced3999e748500dda3027e2a19b0074199ba27cdc5a6988d22919b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.12.0

Release files / milksnake-0.1.6-py2.py3-none-any.whl

Download URL milksnake-0.1.6-py2.py3-none-any.whl
Size 11.1 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
31e3eafaf2a48e177bb4b2dacef2c7ae8c5b2147a19c6d626209b819490e6f1d
BLAKE2b-256 checksum
How to use checksums
6d5b1688cbd7244f039a2c1a762e246f04f7fc3eff07932776ac9944da3ea208
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.12.0

Release history Release notifications | RSS feed

This release

0.1.6 This release

2 release files

0.1.5

2 release files

0.1.4

1 release file

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page