pyclibrary
PyCLibrary is a pure-python C parser and ctypes automation library, designed to simplify the process of creating Python bindings for C libraries. It parses C header files to automatically generate ctypes structures, unions, enums, and function prototypes, enabling easier interaction with shared C libraries. The project is actively maintained, with recent updates focused on stability and improvements, and currently supports Python 3.10 and newer.
Warnings
- gotcha While PyCLibrary aims for an FFI-agnostic API, currently only the `ctypes` backend is implemented. Code that manipulates complex C objects directly may not be easily portable if other FFI backends (e.g., cffi) are introduced later.
- gotcha When calling C functions that expect uninitialized pointers, PyCLibrary can automatically create them. However, you must access the results of these pointers through the `CallResult` object returned by the function call, which encapsulates both the return value and modified arguments.
- gotcha The C parser evaluates macros and preprocessor directives. Complex macros or those relying on external build-time definitions not provided to `CParser` might lead to incorrect parsing or unexpected values.
Install
-
pip install pyclibrary
Imports
- CParser
from pyclibrary import CParser
- CLibrary
from pyclibrary import CLibrary
Quickstart
import os
from pyclibrary import CParser
# Create a dummy header file for demonstration
header_content = '''
#define MY_VERSION_MAJOR 1
#define MY_VERSION_MINOR 0
typedef struct {
int width;
int height;
} Size;
enum Color {
RED = 0,
GREEN,
BLUE
};
int calculate_area(Size s);
void print_message(const char* msg);
'''
header_file_path = "temp_example_header.h"
with open(header_file_path, "w") as f:
f.write(header_content)
try:
# Initialize the CParser with the header file(s)
parser = CParser([header_file_path])
print("--- Parsed Macros ---")
print(f"MY_VERSION_MAJOR: {parser.macros['MY_VERSION_MAJOR']}")
print(f"MY_VERSION_MINOR: {parser.macros['MY_VERSION_MINOR']}")
print("\n--- Parsed Types ---")
print(f"Size struct definition: {parser.structs['Size']}")
print(f"Color enum definition: {parser.enums['Color']}")
print("\n--- Parsed Functions ---")
print(f"calculate_area signature: {parser.functions['calculate_area']}")
print(f"print_message signature: {parser.functions['print_message']}")
# To bind to a C library, you would typically do:
# from pyclibrary import CLibrary
# # Assuming a compiled shared library like 'libmyexample.so' or 'myexample.dll'
# # For this quickstart, we only demonstrate parsing, not live binding.
# try:
# lib = CLibrary(header_file_path, 'libmyexample.so') # Or 'myexample.dll' on Windows
# # Example function call (requires a real shared library):
# # area = lib.calculate_area(width=10, height=20).r # Access return value
# # lib.print_message(msg='Hello from Python')
# except OSError as e:
# print(f"\nCould not load C library for live binding: {e}")
except Exception as e:
print(f"An error occurred during parsing: {e}")
finally:
# Clean up the dummy header file
if os.path.exists(header_file_path):
os.remove(header_file_path)