I'm attempting to compile libspng with PyBind11 so I can easily convert image data into a numpy array.
The compilation process requires compiling a few C files and then linking them to C++. However, I'm not sure how to do this with Python setuptools. I've so far been compiling all C++ or all C modules in my practice, but on clang, this results in problems when I mix the pybind11 file with the C files.
Is there a simple way that I'm missing to compile and link the C files to C++ within setup.py?
I tried building an extension for libspng, but I wasn't sure how to reference the compiled shared object file which was in the build folder.
Thanks!
In case it's helpful (and because I am procrastinating) I built a small demo based on the spng example
// pywrappers.cpp
#include <pybind11/pybind11.h>
#include <utility>
#include <cstdio>
extern "C" {
#include <spng/spng.h>
}
namespace py = pybind11;
std::pair<size_t, size_t> get_size(const std::string& filename)
{
FILE* fp = fopen(filename.c_str(), "rb");
if (fp == nullptr)
{
fclose(fp);
throw std::runtime_error("File not found");
}
spng_ctx* ctx = spng_ctx_new(0);
spng_set_crc_action(ctx, SPNG_CRC_USE, SPNG_CRC_USE);
size_t limit = 1024 * 1024 * 64;
spng_set_chunk_limits(ctx, limit, limit);
spng_set_png_file(ctx, fp);
struct spng_ihdr ihdr;
spng_get_ihdr(ctx, &ihdr);
spng_ctx_free(ctx);
fclose(fp);
return std::make_pair<size_t, size_t>(ihdr.width, ihdr.height);
}
PYBIND11_MODULE(foo, m)
{
m.def("get_size", &get_size);
}
# setup.py
from setuptools import setup, Extension
import pybind11
SPNG_SOURCE = './libspng-0.7.1' # Wherever you put the spng headers and .a
libfoo = Extension(
'foo',
sources=['pywrappers.cpp'],
extra_compile_args = ['-std=c++14'],
include_dirs=[SPNG_SOURCE, pybind11.get_include()],
extra_link_args=['-lspng_static','-lz'],
library_dirs=[SPNG_SOURCE]
)
if __name__ == "__main__":
setup(
name = 'foo',
ext_modules=[libfoo],
)
Build the extension as usual with e.g. python setup.py build_ext --inplace
. Then for example
import foo
foo.get_size('stuff.png')