or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

callbacks-handles.mdcore-ffi.mddata-conversion.mderror-handling.mdindex.mdmemory-management.mdsource-generation.mdtype-system.md

source-generation.mddocs/

0

# Source Generation and Compilation

1

2

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.

3

4

## Capabilities

5

6

### Source Code Assignment

7

8

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

9

10

```python { .api }

11

def set_source(self, module_name, source, source_extension='.c', **kwds):

12

"""

13

Set C source code for compilation.

14

15

Parameters:

16

- module_name (str): Name of the generated module

17

- source (str): C source code

18

- source_extension (str): File extension ('.c' or '.cpp')

19

- **kwds: Compilation options (include_dirs, libraries, etc.)

20

21

Returns:

22

None (configures FFI for compilation)

23

"""

24

```

25

26

**Usage Examples:**

27

28

```python

29

ffi = FFI()

30

ffi.cdef("""

31

int add(int a, int b);

32

double calculate_pi(int iterations);

33

""")

34

35

# Set C source code

36

ffi.set_source("_math_ext", """

37

#include <math.h>

38

39

int add(int a, int b) {

40

return a + b;

41

}

42

43

double calculate_pi(int iterations) {

44

double pi = 0.0;

45

for (int i = 0; i < iterations; i++) {

46

pi += (i % 2 == 0 ? 1.0 : -1.0) / (2 * i + 1);

47

}

48

return pi * 4.0;

49

}

50

""",

51

libraries=['m'], # Link with math library

52

include_dirs=['/usr/local/include']

53

)

54

```

55

56

### Pkg-config Integration

57

58

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

59

60

```python { .api }

61

def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, source_extension='.c', **kwds):

62

"""

63

Set source with pkg-config library detection.

64

65

Parameters:

66

- module_name (str): Generated module name

67

- pkgconfig_libs (list): List of pkg-config package names

68

- source (str): C source code

69

- source_extension (str): File extension

70

- **kwds: Additional compilation options

71

72

Returns:

73

None

74

"""

75

```

76

77

**Usage Example:**

78

79

```python

80

ffi = FFI()

81

ffi.cdef("""

82

// OpenSSL functions

83

void SHA256_Init(void *ctx);

84

void SHA256_Update(void *ctx, const void *data, size_t len);

85

void SHA256_Final(unsigned char *md, void *ctx);

86

""")

87

88

# Use pkg-config to find OpenSSL

89

ffi.set_source_pkgconfig("_crypto_ext",

90

["openssl"],

91

"""

92

#include <openssl/sha.h>

93

94

// Wrapper functions if needed

95

""")

96

```

97

98

### Compilation

99

100

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

101

102

```python { .api }

103

def compile(self, tmpdir='.', verbose=0, target=None, debug=None):

104

"""

105

Compile configured source into extension module.

106

107

Parameters:

108

- tmpdir (str): Directory for temporary and output files

109

- verbose (int): Verbosity level for compilation

110

- target (str): Target filename ('*' for default, '*.ext' for custom)

111

- debug (bool): Enable debug compilation

112

113

Returns:

114

str: Path to compiled extension module

115

"""

116

```

117

118

**Usage Example:**

119

120

```python

121

# After set_source(), compile the extension

122

extension_path = ffi.compile(tmpdir='./build', verbose=1)

123

124

# Load the compiled module

125

spec = importlib.util.spec_from_file_location("_math_ext", extension_path)

126

math_ext = importlib.util.module_from_spec(spec)

127

spec.loader.exec_module(math_ext)

128

129

# Use the compiled functions

130

result = math_ext.lib.add(5, 3) # 8

131

pi_approx = math_ext.lib.calculate_pi(100000)

132

```

133

134

### Code Generation

135

136

Generates C or Python source code files without compilation.

137

138

```python { .api }

139

def emit_c_code(self, filename):

140

"""

141

Generate C source code file.

142

143

Parameters:

144

- filename (str): Output C file path

145

146

Returns:

147

None

148

"""

149

150

def emit_python_code(self, filename):

151

"""

152

Generate Python wrapper code file.

153

154

Parameters:

155

- filename (str): Output Python file path

156

157

Returns:

158

None

159

"""

160

```

161

162

**Usage Examples:**

163

164

```python

165

# Generate C extension code

166

ffi.emit_c_code("generated_extension.c")

167

168

# Generate Python wrapper for dlopen() style

169

ffi_pure = FFI()

170

ffi_pure.cdef("int add(int a, int b);")

171

ffi_pure.set_source("_math_pure", None) # None for dlopen() style

172

ffi_pure.emit_python_code("math_wrapper.py")

173

```

174

175

### Distutils Integration

176

177

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

178

179

```python { .api }

180

def distutils_extension(self, tmpdir='build', verbose=True):

181

"""

182

Create distutils Extension object.

183

184

Parameters:

185

- tmpdir (str): Build directory

186

- verbose (bool): Print generation status

187

188

Returns:

189

distutils.extension.Extension: Extension object for setup.py

190

"""

191

```

192

193

**Usage Example:**

194

195

```python

196

# In build script or setup.py

197

ffi = FFI()

198

ffi.cdef("int multiply(int a, int b);")

199

ffi.set_source("_calc_ext", "int multiply(int a, int b) { return a * b; }")

200

201

# Get extension for setup.py

202

ext = ffi.distutils_extension()

203

204

# Use in setup.py

205

from setuptools import setup

206

setup(

207

name="my_package",

208

ext_modules=[ext],

209

zip_safe=False,

210

)

211

```

212

213

## Advanced Source Generation Patterns

214

215

### Multi-File Extensions

216

217

```python

218

def create_complex_extension():

219

ffi = FFI()

220

221

# Define complete interface

222

ffi.cdef("""

223

// Data structures

224

typedef struct {

225

double x, y, z;

226

} vector3_t;

227

228

// Core functions

229

vector3_t vector_add(vector3_t a, vector3_t b);

230

double vector_length(vector3_t v);

231

232

// Utility functions

233

void print_vector(vector3_t v);

234

""")

235

236

# Multi-part source code

237

includes = """

238

#include <math.h>

239

#include <stdio.h>

240

"""

241

242

data_structures = """

243

typedef struct {

244

double x, y, z;

245

} vector3_t;

246

"""

247

248

implementations = """

249

vector3_t vector_add(vector3_t a, vector3_t b) {

250

vector3_t result = {a.x + b.x, a.y + b.y, a.z + b.z};

251

return result;

252

}

253

254

double vector_length(vector3_t v) {

255

return sqrt(v.x * v.x + v.y * v.y + v.z * v.z);

256

}

257

258

void print_vector(vector3_t v) {

259

printf("Vector(%.2f, %.2f, %.2f)\\n", v.x, v.y, v.z);

260

}

261

"""

262

263

full_source = includes + data_structures + implementations

264

265

ffi.set_source("_vector_ext", full_source,

266

libraries=['m'])

267

268

return ffi

269

270

# Build and use

271

vector_ffi = create_complex_extension()

272

lib_path = vector_ffi.compile()

273

```

274

275

### Conditional Compilation

276

277

```python

278

def create_platform_extension():

279

ffi = FFI()

280

281

# Platform-specific declarations

282

ffi.cdef("""

283

#ifdef _WIN32

284

void windows_specific_func();

285

#else

286

void unix_specific_func();

287

#endif

288

289

void cross_platform_func();

290

""")

291

292

# Platform-specific source

293

source = """

294

#ifdef _WIN32

295

#include <windows.h>

296

void windows_specific_func() {

297

// Windows implementation

298

OutputDebugStringA("Windows function called\\n");

299

}

300

#else

301

#include <unistd.h>

302

void unix_specific_func() {

303

// Unix implementation

304

write(STDOUT_FILENO, "Unix function called\\n", 22);

305

}

306

#endif

307

308

void cross_platform_func() {

309

// Cross-platform implementation

310

}

311

"""

312

313

# Platform-specific compilation options

314

import sys

315

if sys.platform == "win32":

316

libraries = ['kernel32']

317

define_macros = [('_WIN32', '1')]

318

else:

319

libraries = []

320

define_macros = []

321

322

ffi.set_source("_platform_ext", source,

323

libraries=libraries,

324

define_macros=define_macros)

325

326

return ffi

327

```

328

329

### Template-Based Generation

330

331

```python

332

def create_templated_extension(type_name, c_type):

333

"""Generate type-specific extensions"""

334

ffi = FFI()

335

336

# Template declarations

337

declarations = f"""

338

typedef struct {{

339

{c_type} data;

340

size_t size;

341

}} {type_name}_container_t;

342

343

{type_name}_container_t* {type_name}_create(size_t size);

344

void {type_name}_destroy({type_name}_container_t* container);

345

{c_type} {type_name}_get({type_name}_container_t* container, size_t index);

346

void {type_name}_set({type_name}_container_t* container, size_t index, {c_type} value);

347

"""

348

349

ffi.cdef(declarations)

350

351

# Template implementation

352

source = f"""

353

#include <stdlib.h>

354

355

typedef struct {{

356

{c_type}* data;

357

size_t size;

358

}} {type_name}_container_t;

359

360

{type_name}_container_t* {type_name}_create(size_t size) {{

361

{type_name}_container_t* container = malloc(sizeof({type_name}_container_t));

362

container->data = calloc(size, sizeof({c_type}));

363

container->size = size;

364

return container;

365

}}

366

367

void {type_name}_destroy({type_name}_container_t* container) {{

368

if (container) {{

369

free(container->data);

370

free(container);

371

}}

372

}}

373

374

{c_type} {type_name}_get({type_name}_container_t* container, size_t index) {{

375

if (index < container->size) {{

376

return container->data[index];

377

}}

378

return 0; // Error value

379

}}

380

381

void {type_name}_set({type_name}_container_t* container, size_t index, {c_type} value) {{

382

if (index < container->size) {{

383

container->data[index] = value;

384

}}

385

}}

386

"""

387

388

ffi.set_source(f"_{type_name}_container", source)

389

return ffi

390

391

# Generate specialized containers

392

int_container = create_templated_extension("int", "int")

393

float_container = create_templated_extension("float", "float")

394

```

395

396

## Build System Integration

397

398

### Setup.py Integration

399

400

```python

401

# build_extensions.py

402

from cffi import FFI

403

404

def build_math_extension():

405

ffi = FFI()

406

ffi.cdef("double fast_sin(double x);")

407

ffi.set_source("_fast_math", """

408

#include <math.h>

409

double fast_sin(double x) {

410

// Optimized sine implementation

411

return sin(x);

412

}

413

""", libraries=['m'])

414

415

return ffi.distutils_extension()

416

417

# setup.py

418

from setuptools import setup

419

from build_extensions import build_math_extension

420

421

setup(

422

name="my_math_package",

423

ext_modules=[build_math_extension()],

424

cffi_modules=["build_extensions.py:build_math_extension"],

425

setup_requires=["cffi>=1.0.0"],

426

install_requires=["cffi>=1.0.0"],

427

)

428

```

429

430

### CMake Integration

431

432

```python

433

def generate_cmake_compatible():

434

"""Generate extensions compatible with CMake builds"""

435

ffi = FFI()

436

ffi.cdef("void process_data(double* input, double* output, size_t count);")

437

438

# Generate source that can be built with CMake

439

ffi.emit_c_code("cffi_generated.c")

440

ffi.emit_c_code("cffi_generated.h") # If header generation supported

441

442

# Create CMakeLists.txt content

443

cmake_content = """

444

cmake_minimum_required(VERSION 3.10)

445

project(CFfiExtension)

446

447

find_package(Python3 COMPONENTS Interpreter Development REQUIRED)

448

449

add_library(cffi_extension SHARED

450

cffi_generated.c

451

)

452

453

target_link_libraries(cffi_extension Python3::Python)

454

"""

455

456

with open("CMakeLists.txt", "w") as f:

457

f.write(cmake_content)

458

```

459

460

### Setuptools Extension Utilities

461

462

CFFI provides utilities for integrating with setuptools build systems.

463

464

```python { .api }

465

# From cffi.setuptools_ext module

466

def add_cffi_module(dist, mod_spec):

467

"""

468

Add CFFI module to distribution.

469

470

Parameters:

471

- dist: Distribution object

472

- mod_spec (str): Module specification in format "path/build.py:ffi_variable"

473

474

Returns:

475

None (modifies distribution)

476

"""

477

```

478

479

**Usage Example:**

480

481

```python

482

# myproject_build.py

483

from cffi import FFI

484

485

ffi = FFI()

486

ffi.cdef("int calculate(int x, int y);")

487

ffi.set_source("_myproject", """

488

int calculate(int x, int y) {

489

return x * y + x + y;

490

}

491

""")

492

493

# setup.py

494

from setuptools import setup

495

496

setup(

497

name="myproject",

498

cffi_modules=["myproject_build.py:ffi"],

499

setup_requires=["cffi>=1.0.0"],

500

install_requires=["cffi>=1.0.0"],

501

)

502

```

503

504

## Performance Optimization

505

506

### Inline Functions

507

508

```python

509

def create_optimized_extension():

510

ffi = FFI()

511

512

ffi.cdef("""

513

double fast_math_operation(double x, double y);

514

""")

515

516

# Use inline functions for performance

517

source = """

518

#include <math.h>

519

520

static inline double inline_helper(double x) {

521

return x * x + 2 * x + 1;

522

}

523

524

double fast_math_operation(double x, double y) {

525

return inline_helper(x) + inline_helper(y);

526

}

527

"""

528

529

ffi.set_source("_optimized_math", source,

530

extra_compile_args=['-O3', '-finline-functions'])

531

532

return ffi

533

```

534

535

### SIMD Instructions

536

537

```python

538

def create_simd_extension():

539

ffi = FFI()

540

541

ffi.cdef("""

542

void vector_add_simd(float* a, float* b, float* result, size_t count);

543

""")

544

545

source = """

546

#ifdef __SSE__

547

#include <xmmintrin.h>

548

#endif

549

550

void vector_add_simd(float* a, float* b, float* result, size_t count) {

551

#ifdef __SSE__

552

size_t simd_count = count & ~3; // Process 4 elements at a time

553

for (size_t i = 0; i < simd_count; i += 4) {

554

__m128 va = _mm_load_ps(&a[i]);

555

__m128 vb = _mm_load_ps(&b[i]);

556

__m128 vr = _mm_add_ps(va, vb);

557

_mm_store_ps(&result[i], vr);

558

}

559

// Handle remaining elements

560

for (size_t i = simd_count; i < count; i++) {

561

result[i] = a[i] + b[i];

562

}

563

#else

564

for (size_t i = 0; i < count; i++) {

565

result[i] = a[i] + b[i];

566

}

567

#endif

568

}

569

"""

570

571

ffi.set_source("_simd_math", source,

572

extra_compile_args=['-msse', '-O3'])

573

574

return ffi

575

```