Dynamic library + header + ctypes = Module like object!
Create C bindings for python automatically with the help of libclang.
from c_import import loader
import ctypes
libc = loader.load("libc.so.6", ["stdio.h", "stdint.h", "math.h", "stdlib.h", "string.h", "time.h"])
# Work with file streams
filestream = libc.fopen(b"/tmp/x", b"rw+")
text = ctypes.create_string_buffer(b"Hello world")
libc.fwrite(text, len(text), 1, fstream)
libc.fflush(fstream)
libc.fclose(fstream)
libc.fileno(libc.stdin)
# 1
libc.fputc(ord('A'), libc.stdout)
libc.fflush(libc.stdout)
# A
libc.fprintf(libc.stderr, b"%d\n", 100) # 100
# Use math functions
libc.abs(-1)
# 1
# Create instances of structs
cal_date = libc.tm()
dir(cal_date)
# All fields are available
# [...,
# 'tm_gmtoff',
# 'tm_hour',
# 'tm_isdst',
# 'tm_mday',
# 'tm_min',
# 'tm_mon',
# 'tm_sec',
# 'tm_wday',
# 'tm_yday',
# 'tm_year',
# 'tm_zone']
cal_date.tm_sec = 1
cal_date.tm_year = 1999
# View the fields of "private" structs
# Great when experimenting inside an interactive shell.
dir(libc.stdout.contents)
# (Fields differ between libc implementations)
# [...,
# '_IO_backup_base',
# '_IO_buf_base',
# '_IO_buf_end',
# '_IO_read_base',
# '_IO_read_end',
# '_IO_read_ptr',
# '_IO_save_base',
# '_IO_save_end',
# '_IO_write_base',
# '_IO_write_end',
# '_IO_write_ptr',
# '__pad5',
# '_chain',
# '_codecvt',
# '_cur_column',
# '_fields_',
# '_fileno',
# '_flags',
# '_flags2',
# '_freeres_buf',
# '_freeres_list',
# '_lock',
# '_markers',
# '_mode',
# '_objects',
# '_offset',
# '_old_offset',
# '_shortbuf',
# '_unused2',
# '_vtable_offset',
# '_wide_data']
libc.stdout.contents._fileno # 1
# Functions that return a struct work too
x = libc.div(49, 8)
x.quot # 6
x.rem # 1
x.__class__.__name__ # 'div_t'
# Abort the process
libc.abort()
Their declarations are not preserved after the pre-processing.
The CDLL implementation of cpython assumes that the type of every symbol is
int symbol();
This works fine for lots of functions.
import ctypes
libc = ctypes.CDLL('libc.so.6')
libc.printf(b"Hello world %d\n", 5)
# Prints Hello world 5
# returns 14
# Also works
number = ctypes.c_int()
libc.scanf(b"%d", ctypes.pointer(number))
But other functions don’t work properly.
div_result = libc.div(49, 8)
# div_result will be a single int instead of div_t!
And global variables aren’t really usable.
type(libc.stdout)
# ctypes.CDLL.__init__.<locals>._FuncPtr
c_import uses libclang to figure out the types of all the symbols instead of assuming there all the same type.
This library is licensed under GNU Lesser General Public License version 3 or later. See COPYING and COPYING.LESSER for further details.