(solved) -> How to get CFFI and setuptools to find C files and headers

237 views Asked by At

I have written a c extension package using CFFI and I am trying to work out how to build it with setuptools. My package looks like this:

pkgName/
    pyproject.toml
    setup.py
    src/
       pkgName/
              build_cffi.py # Compiles C extension with CFFI
              mainCfile.C
              mainCfile.h
              other.h
              wrapper.py
              __init__.py

My build_cffi.py looks like this:

ffibuilder.set_source(
    "c_binding",
    """
     #include "mainCfile.h"   // the C header of the library
""",
    sources=['mainCfile.c'], include_dirs = [os.path.dirname(os.path.realpath(__file__))]
)
ffibuilder.cdef(
    """
    void test_print(int to_print);
"""
)
if __name__ == "__main__":
    ffibuilder.compile(verbose=True)

and my setup.py looks like this

from setuptools import setup
setup(
    setup_requires=["cffi>=1.0.0"],
    cffi_modules=["src/pkgName/build_cffi.py:ffibuilder"],
    install_requires=["cffi>=1.0.0"],
)

Now, when I run build_cffi.py on its own from the src/pkgName folder, it builds fine. However when I run python3 -m build from the package root directory, the compilation fails with this error: fatal error: mainCfile.h: No such file or directory

How can I get CFFI and setuptools to find my directory with the c headers from setuptools? I have tried to add this include_dirs = [os.path.dirname(os.path.realpath(__file__))]) but it made no difference.

Edit: Found solution

The .c and .h files need to be added by setuptools to the source distribution. This can be done in a manifest.in file, however you can do this in setup.py by adding this extra line to the setup() function:

package_data={"": ["*.h", "*.c"]}.

I also had to make this change to the build_cffi.py file:

ffibuilder.set_source(
    "pkgName.c_bindings", <- Changed to pkg.file 
    """
     #include "mainCfile.h"   
""",
    sources=["src/pkgName/mainCfile.c"], # <-- Make relative to root directory
    include_dirs=[os.path.dirname(os.path.realpath(__file__))],
)   
0

There are 0 answers