CMake Build Demo
Packages a c2py23 module as a py3-none-any wheel using CMake.
Cmake 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.
CMake Configuration
cmake_minimum_required(VERSION 3.16)
project(arraysum C)
# --- Platform detection for c2py_loader naming convention ---
execute_process(
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}')"
OUTPUT_VARIABLE PLATFORM_KEY
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(SO_NAME "_arraysum.c2py23-${PLATFORM_KEY}.so")
# --- Find c2py23 runtime ---
execute_process(
COMMAND python3 -c
"import c2py23, os; print(os.path.join(os.path.dirname(c2py23.__file__), 'runtime'))"
OUTPUT_VARIABLE RUNTIME_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# --- Generate wrapper from .c2py ---
add_custom_command(
OUTPUT _arraysum_wrapper.c
COMMAND c2py23 generate arraysum.c2py -o _arraysum_wrapper.c
DEPENDS arraysum.c2py
COMMENT "c2py23 generate arraysum.c2py"
)
# --- Build the .so with bare name (no EXT_SUFFIX) ---
add_library(_arraysum SHARED
_arraysum_wrapper.c
arraysum.c
${RUNTIME_DIR}/c2py_runtime.c
)
set_target_properties(_arraysum PROPERTIES
PREFIX ""
SUFFIX ".so"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/arraysum"
OUTPUT_NAME "${SO_NAME}"
)
target_include_directories(_arraysum PRIVATE
${RUNTIME_DIR}
${CMAKE_SOURCE_DIR}
)
target_link_libraries(_arraysum PRIVATE dl m)
Build Script
#!/usr/bin/env bash
# build.sh - Build arraysum wheel using cmake + 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 (cmake) wheel build ==="
# 1. Generate wrapper + build .so via cmake
echo "1. Building with cmake..."
cmake -B builddir -S . 2>&1 | tail -1
cmake --build builddir 2>&1 | tail -1
# 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. Runs c2py23 to produce the wrapper C file
2. Uses CMake to build _arraysum.c2py23-{os}_{arch}.so
3. Copies the .so into the arraysum/ package directory
4. Builds the wheel with python3 -m build
CMakeLists.txt calls c2py23 via execute_process() and
compiles the wrapper + runtime + user C source with add_library().
The package arraysum/__init__.py uses c2py_loader.load_native() to
find and load the correct .so at import time.