Background
Due to performance reasons in my Python application, I will eventually be trying to write a couple of functions in the C language to convert integers to/from a VLQ binary string representation. Since I don't want to deal with implementation details, and since this application is targeting the standard CPython interpreter, I have decided for now to use the SWIG wrapper generator and have been trying to use the Python package 'setuptools' in order to automatically compile and bundle a sample function (that simply increments a number by 1).
Problem
I have been trying for much too long now to properly write my 'setup.py' file so that it both A) compiles the relevant C sources, and B) includes the auto-generated Python wrapper component as well. I am able to accomplish 'A', but not 'B' (I have been inspecting the generated wheel file to check this).
Attempted solutions
I have tried reading the 'setuptools' documentation and inspecting its source code (including the source of the package 'distutils'), as well as tried reading other users' input on Stack Overflow, and have tried inspecting various example packages from GitHub. If I could've solved this problem by now, I would've.
Acceptable solutions
This is basically just one giant headache to me. So, in order from most-specific to least-specific solutions that would solve my problem:
- Either fix the 'setup.py' file or some other aspect of the project configuration/layout so that it includes the relevant Python sources (I would prefer to be able to do this without a 'MANIFEST.in' or binary-data-file-inclusion hack)
- Find an alternative Python packaging tool that will still work with CPython and 'pip'
- Compile the C code example and create the relevant package some other way that is still compatible with CPython and 'pip' (for example, using GNU 'make', with which I am very comfortable with)
Additional
I don't believe that I'm including the header file 'example.h' in the source distribution right now, so I would appreciate any help with both fixing that, as well as fixing any other miscellaneous bugs that you may find.
Configuration and code
Relevant files
./README.md
# Greetings programs!!!
Don't panic!
I am primarily using this example package to test my ability to create compiled C code extensions for the Python interpreter via the SWIG mechanism. I will also be using this package to test that I can, ultimately, access the contents of a package of this sort from within 'python' itself on my computer.
# License
Anything contained within this package is licensed under [WTFPL][4] where applicable (though, obviously, you may not use my username and email without my permission). If there are any files contained within this project that I, Mr. Minty Fresh, do not have copyright control over, then said files' copyright statuses belong to each respective owner(s) (this may or may not include some files automatically generated by SWIG).
File ./setup.py
#!/usr/bin/env python3
import os
import setuptools
from setuptools import Extension, Command, find_packages
from setuptools.command.build_ext import build_ext
from distutils.command.clean import clean
class build_swig(build_ext):
"""Use SWIG on some files within the 'swig_example/' directory."""
def run(self):
print("building SWIG interface")
os.system("swig -python ./swig_example/example.swig")
super().run()
class clean_swig(clean):
"""Cleanup all files generated by SWIG in the 'swig_example/' directory."""
def run(self):
print("removing temporary SWIG files")
os.system("rm -f ./swig_example/example_wrap.c")
os.system("rm -f ./swig_example/example.py")
print("removing dist-ish files")
os.system("rm -rf ./dist/")
os.system("rm -rf ./*.egg-info/")
super().run()
class noop(Command):
"""Do absolutely nothing (successfully)!"""
user_options = []
def initialize_options(self): pass
def finalize_options(self): pass
def run(self): pass
noop.description = noop.__doc__
with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name = "example-pkg-mrmintyfresh",
version = "0.0.1",
author = "mrmintyfresh",
author_email = "mrmintyfresh@example.com",
description = "Sample SWIG usage package.",
long_description = long_description,
url = "https://www.example.com/",
ext_modules = [
Extension("_example", ["./swig_example/example_wrap.c", "./swig_example/example.c"]),
],
cmdclass = {
"build_ext": build_swig,
"clean": clean_swig,
"noop": noop,
},
packages = find_packages("./swig_example/"),
python_requires = ">=3.0",
)
File ./swig_example/example.c
#include "example.h"
int increment(int x){
return ++x;
}
File ./swig_example/example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
extern int increment(int x);
#endif /* EXAMPLE_H */
File ./swig_example/example.swig
%module example
%{
#include "example.h"
%}
%include "example.h"
File ./swig_example/init.py
(empty file)
File ./swig_example/example_wrap.c (auto-generated)
(Omitted for brevity)
File ./swig_example/example.py (auto-generated)
(Omitted for brevity)