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
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.