CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cffi

Foreign Function Interface for Python calling C code.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

source-generation.mddocs/

Source Generation and Compilation

Advanced features for generating and compiling C extensions at runtime. These capabilities enable complex integration scenarios and performance optimization through automatic code generation and compilation.

Capabilities

Source Code Assignment

Associates C source code with FFI declarations for compilation into Python extensions.

def set_source(self, module_name, source, source_extension='.c', **kwds):
    """
    Set C source code for compilation.
    
    Parameters:
    - module_name (str): Name of the generated module
    - source (str): C source code
    - source_extension (str): File extension ('.c' or '.cpp')
    - **kwds: Compilation options (include_dirs, libraries, etc.)
    
    Returns:
    None (configures FFI for compilation)
    """

Usage Examples:

ffi = FFI()
ffi.cdef("""
    int add(int a, int b);
    double calculate_pi(int iterations);
""")

# Set C source code
ffi.set_source("_math_ext", """
    #include <math.h>
    
    int add(int a, int b) {
        return a + b;
    }
    
    double calculate_pi(int iterations) {
        double pi = 0.0;
        for (int i = 0; i < iterations; i++) {
            pi += (i % 2 == 0 ? 1.0 : -1.0) / (2 * i + 1);
        }
        return pi * 4.0;
    }
""", 
    libraries=['m'],  # Link with math library
    include_dirs=['/usr/local/include']
)

Pkg-config Integration

Automatically configures compilation flags using pkg-config for system libraries.

def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, source_extension='.c', **kwds):
    """
    Set source with pkg-config library detection.
    
    Parameters:
    - module_name (str): Generated module name
    - pkgconfig_libs (list): List of pkg-config package names
    - source (str): C source code
    - source_extension (str): File extension
    - **kwds: Additional compilation options
    
    Returns:
    None
    """

Usage Example:

ffi = FFI()
ffi.cdef("""
    // OpenSSL functions
    void SHA256_Init(void *ctx);
    void SHA256_Update(void *ctx, const void *data, size_t len);
    void SHA256_Final(unsigned char *md, void *ctx);
""")

# Use pkg-config to find OpenSSL
ffi.set_source_pkgconfig("_crypto_ext", 
    ["openssl"], 
    """
    #include <openssl/sha.h>
    
    // Wrapper functions if needed
    """)

Compilation

Compiles the configured source code into a loadable Python extension module.

def compile(self, tmpdir='.', verbose=0, target=None, debug=None):
    """
    Compile configured source into extension module.
    
    Parameters:
    - tmpdir (str): Directory for temporary and output files
    - verbose (int): Verbosity level for compilation
    - target (str): Target filename ('*' for default, '*.ext' for custom)
    - debug (bool): Enable debug compilation
    
    Returns:
    str: Path to compiled extension module
    """

Usage Example:

# After set_source(), compile the extension
extension_path = ffi.compile(tmpdir='./build', verbose=1)

# Load the compiled module
spec = importlib.util.spec_from_file_location("_math_ext", extension_path)
math_ext = importlib.util.module_from_spec(spec)
spec.loader.exec_module(math_ext)

# Use the compiled functions
result = math_ext.lib.add(5, 3)  # 8
pi_approx = math_ext.lib.calculate_pi(100000)

Code Generation

Generates C or Python source code files without compilation.

def emit_c_code(self, filename):
    """
    Generate C source code file.
    
    Parameters:
    - filename (str): Output C file path
    
    Returns:
    None
    """

def emit_python_code(self, filename):
    """
    Generate Python wrapper code file.
    
    Parameters:
    - filename (str): Output Python file path
    
    Returns:
    None
    """

Usage Examples:

# Generate C extension code
ffi.emit_c_code("generated_extension.c")

# Generate Python wrapper for dlopen() style
ffi_pure = FFI()
ffi_pure.cdef("int add(int a, int b);")
ffi_pure.set_source("_math_pure", None)  # None for dlopen() style
ffi_pure.emit_python_code("math_wrapper.py")

Distutils Integration

Creates distutils Extension objects for integration with setup.py build systems.

def distutils_extension(self, tmpdir='build', verbose=True):
    """
    Create distutils Extension object.
    
    Parameters:
    - tmpdir (str): Build directory
    - verbose (bool): Print generation status
    
    Returns:
    distutils.extension.Extension: Extension object for setup.py
    """

Usage Example:

# In build script or setup.py
ffi = FFI()
ffi.cdef("int multiply(int a, int b);")
ffi.set_source("_calc_ext", "int multiply(int a, int b) { return a * b; }")

# Get extension for setup.py
ext = ffi.distutils_extension()

# Use in setup.py
from setuptools import setup
setup(
    name="my_package",
    ext_modules=[ext],
    zip_safe=False,
)

Advanced Source Generation Patterns

Multi-File Extensions

def create_complex_extension():
    ffi = FFI()
    
    # Define complete interface
    ffi.cdef("""
        // Data structures
        typedef struct {
            double x, y, z;
        } vector3_t;
        
        // Core functions
        vector3_t vector_add(vector3_t a, vector3_t b);
        double vector_length(vector3_t v);
        
        // Utility functions
        void print_vector(vector3_t v);
    """)
    
    # Multi-part source code
    includes = """
        #include <math.h>
        #include <stdio.h>
    """
    
    data_structures = """
        typedef struct {
            double x, y, z;
        } vector3_t;
    """
    
    implementations = """
        vector3_t vector_add(vector3_t a, vector3_t b) {
            vector3_t result = {a.x + b.x, a.y + b.y, a.z + b.z};
            return result;
        }
        
        double vector_length(vector3_t v) {
            return sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
        }
        
        void print_vector(vector3_t v) {
            printf("Vector(%.2f, %.2f, %.2f)\\n", v.x, v.y, v.z);
        }
    """
    
    full_source = includes + data_structures + implementations
    
    ffi.set_source("_vector_ext", full_source, 
                   libraries=['m'])
    
    return ffi

# Build and use
vector_ffi = create_complex_extension()
lib_path = vector_ffi.compile()

Conditional Compilation

def create_platform_extension():
    ffi = FFI()
    
    # Platform-specific declarations
    ffi.cdef("""
        #ifdef _WIN32
        void windows_specific_func();
        #else
        void unix_specific_func();
        #endif
        
        void cross_platform_func();
    """)
    
    # Platform-specific source
    source = """
        #ifdef _WIN32
        #include <windows.h>
        void windows_specific_func() {
            // Windows implementation
            OutputDebugStringA("Windows function called\\n");
        }
        #else
        #include <unistd.h>
        void unix_specific_func() {
            // Unix implementation
            write(STDOUT_FILENO, "Unix function called\\n", 22);
        }
        #endif
        
        void cross_platform_func() {
            // Cross-platform implementation
        }
    """
    
    # Platform-specific compilation options
    import sys
    if sys.platform == "win32":
        libraries = ['kernel32']
        define_macros = [('_WIN32', '1')]
    else:
        libraries = []
        define_macros = []
    
    ffi.set_source("_platform_ext", source,
                   libraries=libraries,
                   define_macros=define_macros)
    
    return ffi

Template-Based Generation

def create_templated_extension(type_name, c_type):
    """Generate type-specific extensions"""
    ffi = FFI()
    
    # Template declarations
    declarations = f"""
        typedef struct {{
            {c_type} data;
            size_t size;
        }} {type_name}_container_t;
        
        {type_name}_container_t* {type_name}_create(size_t size);
        void {type_name}_destroy({type_name}_container_t* container);
        {c_type} {type_name}_get({type_name}_container_t* container, size_t index);
        void {type_name}_set({type_name}_container_t* container, size_t index, {c_type} value);
    """
    
    ffi.cdef(declarations)
    
    # Template implementation
    source = f"""
        #include <stdlib.h>
        
        typedef struct {{
            {c_type}* data;
            size_t size;
        }} {type_name}_container_t;
        
        {type_name}_container_t* {type_name}_create(size_t size) {{
            {type_name}_container_t* container = malloc(sizeof({type_name}_container_t));
            container->data = calloc(size, sizeof({c_type}));
            container->size = size;
            return container;
        }}
        
        void {type_name}_destroy({type_name}_container_t* container) {{
            if (container) {{
                free(container->data);
                free(container);
            }}
        }}
        
        {c_type} {type_name}_get({type_name}_container_t* container, size_t index) {{
            if (index < container->size) {{
                return container->data[index];
            }}
            return 0;  // Error value
        }}
        
        void {type_name}_set({type_name}_container_t* container, size_t index, {c_type} value) {{
            if (index < container->size) {{
                container->data[index] = value;
            }}
        }}
    """
    
    ffi.set_source(f"_{type_name}_container", source)
    return ffi

# Generate specialized containers
int_container = create_templated_extension("int", "int")
float_container = create_templated_extension("float", "float")

Build System Integration

Setup.py Integration

# build_extensions.py
from cffi import FFI

def build_math_extension():
    ffi = FFI()
    ffi.cdef("double fast_sin(double x);")
    ffi.set_source("_fast_math", """
        #include <math.h>
        double fast_sin(double x) {
            // Optimized sine implementation
            return sin(x);
        }
    """, libraries=['m'])
    
    return ffi.distutils_extension()

# setup.py
from setuptools import setup
from build_extensions import build_math_extension

setup(
    name="my_math_package",
    ext_modules=[build_math_extension()],
    cffi_modules=["build_extensions.py:build_math_extension"],
    setup_requires=["cffi>=1.0.0"],
    install_requires=["cffi>=1.0.0"],
)

CMake Integration

def generate_cmake_compatible():
    """Generate extensions compatible with CMake builds"""
    ffi = FFI()
    ffi.cdef("void process_data(double* input, double* output, size_t count);")
    
    # Generate source that can be built with CMake
    ffi.emit_c_code("cffi_generated.c")
    ffi.emit_c_code("cffi_generated.h")  # If header generation supported
    
    # Create CMakeLists.txt content
    cmake_content = """
    cmake_minimum_required(VERSION 3.10)
    project(CFfiExtension)
    
    find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
    
    add_library(cffi_extension SHARED
        cffi_generated.c
    )
    
    target_link_libraries(cffi_extension Python3::Python)
    """
    
    with open("CMakeLists.txt", "w") as f:
        f.write(cmake_content)

Setuptools Extension Utilities

CFFI provides utilities for integrating with setuptools build systems.

# From cffi.setuptools_ext module
def add_cffi_module(dist, mod_spec):
    """
    Add CFFI module to distribution.
    
    Parameters:
    - dist: Distribution object
    - mod_spec (str): Module specification in format "path/build.py:ffi_variable"
    
    Returns:
    None (modifies distribution)
    """

Usage Example:

# myproject_build.py
from cffi import FFI

ffi = FFI()
ffi.cdef("int calculate(int x, int y);")
ffi.set_source("_myproject", """
    int calculate(int x, int y) {
        return x * y + x + y;
    }
""")

# setup.py
from setuptools import setup

setup(
    name="myproject",
    cffi_modules=["myproject_build.py:ffi"],
    setup_requires=["cffi>=1.0.0"],
    install_requires=["cffi>=1.0.0"],
)

Performance Optimization

Inline Functions

def create_optimized_extension():
    ffi = FFI()
    
    ffi.cdef("""
        double fast_math_operation(double x, double y);
    """)
    
    # Use inline functions for performance
    source = """
        #include <math.h>
        
        static inline double inline_helper(double x) {
            return x * x + 2 * x + 1;
        }
        
        double fast_math_operation(double x, double y) {
            return inline_helper(x) + inline_helper(y);
        }
    """
    
    ffi.set_source("_optimized_math", source,
                   extra_compile_args=['-O3', '-finline-functions'])
    
    return ffi

SIMD Instructions

def create_simd_extension():
    ffi = FFI()
    
    ffi.cdef("""
        void vector_add_simd(float* a, float* b, float* result, size_t count);
    """)
    
    source = """
        #ifdef __SSE__
        #include <xmmintrin.h>
        #endif
        
        void vector_add_simd(float* a, float* b, float* result, size_t count) {
        #ifdef __SSE__
            size_t simd_count = count & ~3;  // Process 4 elements at a time
            for (size_t i = 0; i < simd_count; i += 4) {
                __m128 va = _mm_load_ps(&a[i]);
                __m128 vb = _mm_load_ps(&b[i]);
                __m128 vr = _mm_add_ps(va, vb);
                _mm_store_ps(&result[i], vr);
            }
            // Handle remaining elements
            for (size_t i = simd_count; i < count; i++) {
                result[i] = a[i] + b[i];
            }
        #else
            for (size_t i = 0; i < count; i++) {
                result[i] = a[i] + b[i];
            }
        #endif
        }
    """
    
    ffi.set_source("_simd_math", source,
                   extra_compile_args=['-msse', '-O3'])
    
    return ffi

Install with Tessl CLI

npx tessl i tessl/pypi-cffi

docs

callbacks-handles.md

core-ffi.md

data-conversion.md

error-handling.md

index.md

memory-management.md

source-generation.md

type-system.md

tile.json