Skip to content

Meson Build Demo

Packages a c2py23 module as a py3-none-any wheel using the Meson build system.

Meson Demo

Interface

# Python dict format equivalent of arraysum.c2py
{
    "module": "_arraysum",
    "source": ["arraysum.c"],
    "functions": [
        {
            "py_sig": "array_sum(a: buffer, b: buffer, result: buffer) -> int",
            "checks": [
                "a.format == 'd'",
                "b.format == 'd'",
                "result.format == 'd'",
                "a.n == b.n",
                "a.n == result.n",
            ],
            "c_overloads": [
                {
                    "sig": "array_sum(const double *a, const double *b, double *result, int n) -> int",
                    "map": {
                        "a": "a.ptr",
                        "b": "b.ptr",
                        "result": "result.ptr",
                        "n": "a.n",
                    },
                },
            ],
        },
    ],
}

C Source

/* arraysum.c - element-wise addition of double arrays */
extern int array_sum(const double *a, const double *b, double *result, int n);

int array_sum(const double *a, const double *b, double *result, int n) {
    int i;
    for (i = 0; i < n; i++) {
        result[i] = a[i] + b[i];
    }
    return n;
}

Build

$ c2py23 arraysum.c2py -o _arraysum_wrapper.c

Compile:

$ cc -shared -fPIC c2py23/runtime/c2py_runtime.c _arraysum_wrapper.c arraysum.c -I c2py23/runtime -o _arraysum.so -ldl -lm

See docs/building for cmake, meson, and setuptools options.

Meson Configuration

project('arraysum', 'c')

# --- Platform detection for c2py_loader naming convention ---
r = run_command('python3', '-c',
  'import sys, platform; p=sys.platform; m=platform.machine(); print("linux_x86_64" if "linux" in p and m in ("x86_64","AMD64") else f"{p}_{m}")',
  check: true)
platform_key = r.stdout().strip()
so_name = '_arraysum.c2py23-' + platform_key + '.so'

# --- Find c2py23 runtime ---
r = run_command('python3', '-c',
  'import c2py23, os; print(os.path.join(os.path.dirname(c2py23.__file__), "runtime"))',
  check: true)
runtime_dir = r.stdout().strip()

# --- Generate wrapper from .c2py ---
c2py_wrapper = custom_target('arraysum_wrapper',
  output : '_arraysum_wrapper.c',
  input : 'arraysum.c2py',
  command : ['c2py23', 'generate', '@INPUT@', '-o', '@OUTPUT@'],
)

# --- Build the .so ---
# Using shared_module with bare name (no Python EXT_SUFFIX).
# meson-python would normally use python.extension_module() which
# adds the cpython-312- tag.  Here we want the untagged c2py_loader
# name, so we use shared_module() directly.
shared_module('_arraysum',
  c2py_wrapper,
  'arraysum.c',
  files(runtime_dir / 'c2py_runtime.c'),
  name_prefix : '',
  name_suffix : 'so',
  include_directories : include_directories(runtime_dir, '.'),
  link_args : ['-ldl', '-lm'],
  install : true,
  install_dir : meson.current_source_dir() / 'arraysum',
)

# Rename installed .so to the c2py_loader convention
meson.add_install_script(
  find_program('python3'),
  '-c',
  'import os; ' +
  'src = os.path.join(os.environ["MESON_INSTALL_DESTDIR_PREFIX"], ' +
  '  "arraysum", "_arraysum.so"); ' +
  'dst = os.path.join(os.environ["MESON_INSTALL_DESTDIR_PREFIX"], ' +
  '  "arraysum", "' + so_name + '"); ' +
  'if os.path.exists(src): os.rename(src, dst)',
)

Build Script

#!/usr/bin/env bash
# build.sh - Build arraysum wheel using meson + c2py_loader convention.
set -e

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$SCRIPT_DIR"

PY="${PYTHON:-python3}"
for c in "$PY" python3.12 python3.11 python3.10 python3.9 python3; do
    command -v "$c" >/dev/null 2>&1 && PY="$c" && break
done

echo "=== arraysum (meson) wheel build ==="

# 1. Generate wrapper + build .so via meson
echo "1. Building with meson..."
"$PY" -m pip install -q meson meson-python 2>/dev/null || true

meson setup builddir --prefix=/tmp/arraysum_install 2>&1 | tail -1
meson compile -C builddir 2>&1 | tail -1
meson install -C builddir --destdir /tmp/arraysum_destdir 2>&1 | tail -1

# Copy .so from install tree to package dir
cp /tmp/arraysum_destdir/tmp/arraysum_install/arraysum/_arraysum.c2py23-*.so \
   arraysum/ 2>/dev/null || \
cp /tmp/arraysum_destdir/tmp/arraysum_install/arraysum/_arraysum.so \
   arraysum/ 2>/dev/null || true

# 2. Assemble wheel
echo ""
echo "2. Building wheel..."
"$PY" setup.py bdist_wheel 2>&1 | tail -3

echo ""
echo "=== Done ==="
ls -la dist/*.whl 2>/dev/null || echo "(no wheel produced)"

How It Works

build.sh: 1. Generates the wrapper C file with c2py23 2. Configures and builds with Meson 3. Copies the .so into the arraysum/ package directory 4. Builds the wheel with python3 -m build

The meson.build file invokes c2py23 via run_command(), then builds the .so with shared_library() using the generated wrapper, runtime, and user source files.