Skip to content

Commit 64a6a84

Browse files
authored
fix: change CFFI writer default output extension from .py to .cdef.txt (#45)
* fix: change CFFI writer default output extension from .py to .cdef.txt CFFI writer output is C declarations for ffi.cdef(), not Python code. Using .py was misleading. Updated default_output_pattern and all docs to use .cdef.txt, consistent with cffi_buildtool's read-sources mode. * fix: use C-style comments in CFFI writer hash_comment_format pycparser does not support shell-style # comments, so cache metadata prepended to .cdef.txt output should use // instead. * fix: use C89-compatible /* */ comments in CFFI hash_comment_format pycparser may run in C89 mode where // is not supported.
1 parent dad0a88 commit 64a6a84

6 files changed

Lines changed: 29 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- CFFI writer default output extension changed from `.py` to `.cdef.txt` (output is C declarations, not Python)
13+
1014
## [0.18.0] - 2026-04-04
1115

1216
### Added

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ _lib.distance.restype = ctypes.c_int
4545

4646
**CFFI -- declarations for `ffibuilder.cdef()`:**
4747
```bash
48-
headerkit mylib.h -w cffi -o cffi:_defs.py
48+
headerkit mylib.h -w cffi -o cffi:_defs.cdef.txt
4949
```
5050
```c
51-
/* generated _defs.py */
51+
/* generated _defs.cdef.txt */
5252
typedef struct Point {
5353
int x;
5454
int y;
@@ -296,7 +296,7 @@ output = generate("mylib.h", "cffi")
296296

297297
```bash
298298
# CLI: generate with caching (on by default)
299-
headerkit mylib.h -w cffi -o cffi:bindings.py --store-dir .headerkit
299+
headerkit mylib.h -w cffi -o cffi:mylib.cdef.txt --store-dir .headerkit
300300
```
301301

302302
headerkit also ships a PEP 517 build backend. Consumer projects declare it in `pyproject.toml` and get bindings generated automatically during `pip install` or `python -m build`, with no libclang required when the cache is committed:

docs/guides/build-backend.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ include_dirs = ["/usr/local/include"]
4848
Run headerkit locally on a machine with libclang installed:
4949

5050
```bash
51-
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib_cffi.py
51+
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib.cdef.txt
5252
```
5353

5454
This writes cache entries to `.headerkit/`.
@@ -255,7 +255,7 @@ To fix a cache miss:
255255
headerkit install-libclang
256256

257257
# Re-generate and populate cache
258-
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib_cffi.py
258+
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib.cdef.txt
259259

260260
# Commit updated cache
261261
git add .headerkit/
@@ -328,7 +328,7 @@ If bindings are outdated after modifying a header:
328328
```bash
329329
# Clear the cache and regenerate
330330
headerkit cache clear --store-dir .headerkit
331-
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib_cffi.py
331+
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib.cdef.txt
332332
git add .headerkit/
333333
git commit -m "cache: regenerate after header changes"
334334
```
@@ -377,7 +377,7 @@ ensure `.headerkit/` is packaged.
377377
Verify the committed cache matches current sources:
378378

379379
```bash
380-
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib_cffi.py
380+
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib.cdef.txt
381381
git diff --exit-code .headerkit/ bindings/
382382
```
383383

docs/guides/cache.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ results = generate_all(
8787
"include/mylib.h",
8888
writers=["cffi", "ctypes", "json"],
8989
output_paths={
90-
"cffi": "bindings/mylib_cffi.py",
90+
"cffi": "bindings/mylib.cdef.txt",
9191
"ctypes": "bindings/mylib_ctypes.py",
9292
"json": "bindings/mylib_ir.json",
9393
},
@@ -114,13 +114,13 @@ output = generate(
114114

115115
```bash
116116
# Generate with caching (default behavior)
117-
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib_cffi.py
117+
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib.cdef.txt
118118

119119
# Second run uses cache automatically
120-
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib_cffi.py
120+
headerkit include/mylib.h -w cffi -o cffi:bindings/mylib.cdef.txt
121121

122122
# Multiple writers in one pass
123-
headerkit include/mylib.h -w cffi -o cffi:bindings/cffi.py -w ctypes -o ctypes:bindings/ctypes.py
123+
headerkit include/mylib.h -w cffi -o cffi:bindings/cffi.cdef.txt -w ctypes -o ctypes:bindings/ctypes.py
124124

125125
# Custom store directory
126126
headerkit include/mylib.h -w cffi --store-dir /tmp/headerkit-store
@@ -273,10 +273,10 @@ To verify the committed cache is up-to-date in CI:
273273

274274
```bash
275275
# Generate with current sources
276-
headerkit mylib.h -w cffi -o cffi:bindings.py
276+
headerkit mylib.h -w cffi -o cffi:mylib.cdef.txt
277277

278278
# Check for uncommitted changes
279-
git diff --exit-code .headerkit/ bindings.py
279+
git diff --exit-code .headerkit/ mylib.cdef.txt
280280
```
281281

282282
If the diff is non-empty, the cache is stale and needs to be regenerated.
@@ -464,7 +464,7 @@ to select headers:
464464
465465
```bash
466466
# Process all .h files under include/
467-
headerkit 'include/**/*.h' -w cffi -o cffi:{dir}/{stem}_cffi.py
467+
headerkit 'include/**/*.h' -w cffi -o cffi:{dir}/{stem}.cdef.txt
468468

469469
# Exclude internal headers
470470
headerkit 'include/**/*.h' --exclude 'include/internal/**' -w cffi
@@ -486,11 +486,11 @@ Templates support these variables:
486486

487487
```bash
488488
# Each header gets its own output file
489-
headerkit 'include/**/*.h' -w cffi -o cffi:{dir}/{stem}_cffi.py
489+
headerkit 'include/**/*.h' -w cffi -o cffi:{dir}/{stem}.cdef.txt
490490

491491
# Multiple writers with different templates
492492
headerkit 'include/**/*.h' \
493-
-w cffi -o cffi:{dir}/{stem}_cffi.py \
493+
-w cffi -o cffi:{dir}/{stem}.cdef.txt \
494494
-w json -o json:{dir}/{stem}.json
495495
```
496496

@@ -510,7 +510,7 @@ pattern = "vendor/special.h"
510510
defines = ["VENDOR_MODE"]
511511

512512
[tool.headerkit.output]
513-
cffi = "{dir}/{stem}_cffi.py"
513+
cffi = "{dir}/{stem}.cdef.txt"
514514
json = "{dir}/{stem}.json"
515515
```
516516

headerkit/writers/cffi.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -526,7 +526,7 @@ class CffiWriter:
526526
cdef_string = writer.write(header)
527527
"""
528528

529-
default_output_pattern: str = "{dir}/{stem}_cffi.py"
529+
default_output_pattern: str = "{dir}/{stem}.cdef.txt"
530530

531531
def __init__(
532532
self,
@@ -564,8 +564,8 @@ def format_description(self) -> str:
564564
return "CFFI cdef declarations for ffibuilder.cdef()"
565565

566566
def hash_comment_format(self) -> str:
567-
"""Return format string for wrapping TOML cache metadata in Python comments."""
568-
return "# {line}"
567+
"""Return format string for wrapping cache metadata in C-style comments."""
568+
return "/* {line} */"
569569

570570

571571
# Uses bottom-of-module self-registration. Unlike backends (which import

tests/test_cli_integration.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,8 @@ def test_one_writer_explicit_one_writer_default(
415415

416416
assert result == 0
417417
assert json_out.exists()
418-
# cffi writer uses default pattern {dir}/{stem}_cffi.py
419-
cffi_default = tmp_path / "test_cffi.py"
418+
# cffi writer uses default pattern {dir}/{stem}.cdef.txt
419+
cffi_default = tmp_path / "test.cdef.txt"
420420
assert cffi_default.exists()
421421
assert "multiply" in cffi_default.read_text(encoding="utf-8")
422422

@@ -457,9 +457,9 @@ def test_two_files_declarations_both_present(
457457
result = main()
458458

459459
assert result == 0
460-
# Batch mode writes to default output pattern {dir}/{stem}_cffi.py
461-
cffi_a = tmp_path / "a_cffi.py"
462-
cffi_b = tmp_path / "b_cffi.py"
460+
# Batch mode writes to default output pattern {dir}/{stem}.cdef.txt
461+
cffi_a = tmp_path / "a.cdef.txt"
462+
cffi_b = tmp_path / "b.cdef.txt"
463463
assert cffi_a.exists()
464464
assert cffi_b.exists()
465465
assert "func_a" in cffi_a.read_text(encoding="utf-8")

0 commit comments

Comments
 (0)