Reputation: 22174
I would like to create a module that uses a non python aware C library and ctypes
.
According to this documentation about creating a C extension to python, I’m required to provide a module initialization function with the signature PyObject* PyInit_modulename(void)
. This looks like a significant complication compared to using the wrapper using ctypes
that I already have.
So far I tested building an Extension with setpuptools on unix and it worked. It was simply and handy. But it doesn’t work on windows. I use cibuildwheel
and github actions to build wheels for all OS including windows. The compilation on Windows fails because the function PyInit_ext
is not found.
I thus need to compile my code as a pure DLL (windows shared library). I then can load the library with ctypes
. Can this be done with setuptools
which is used by cibuildwheel
?
How can I do that ?
Here is my setup.cfg
file:
[metadata]
name = hello_chmike
version = 0.0.0
url = https://github.com/chmike/hello
maintainer = Christophe Meessen
maintainer_email = [email protected]
description = Simple python module with external C library
long_description = file: README.md
long_description_content_type = text/markdown
keywords = Example
license = BSD 3-Clause License
license_file = LICENSE.txt
classifiers =
License :: OSI Approved :: BSD License
Programming Language :: Python :: 3
Operating System :: OS Independent
Topic :: Utilities
[options]
packages = hello
python_requires = >=3.6
and here is the setup.py
file I currently have and which is not good because it uses Extension:
from setuptools import setup, Extension
setup(
ext_modules=[Extension('hello.ext',
['src/hello.c'],
depends=['src/hello.h'],
include_dirs=['src'],
)],
)
The content of the file hello.c
is the following:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// hello return a heap allocated string containing the name appended
// to "hello " and followed by "!".
char *hello(char *name) {
char *buf = malloc(7+strlen(name));
sprintf(buf, "hello %s!", name);
return buf;
}
Upvotes: 1
Views: 133
Reputation: 22174
The only viable solution to get portable code across different OS and using the python building tools and cibuildwheel
to get precompiled modules is to create a real python extension.
This means creating a python extension C code that wraps the python agnostic C library. Wrapping means that we create C functions as required by the Python C extension standard that call the python agnostic C functions from my library.
Using ctypes
to wrap the python agnostic C library will work when used for a specific OS like linux. But the execution context is so different between OS that trying to make a ctypes
wrapper that works on the every OS requires complex hacking and platform switch in the python wrapper.
By using real python extension C code, we avoid this complexity. I wish I knew this when I started.
Upvotes: 1