Debug c_import C-header interop failures and pin fixes as torture fixtures. Use when a c_import fails to preprocess, parse or import a header, when an imported function, constant or struct misbehaves at runtime, or when adding a c_import regression test.
Install
npx skillscat add reardan/w/w-c-import-debug Install via the SkillsCat registry.
Debugging c_import interop
c_import "libc.so.6" "/usr/include/stdio.h" runs three stages, all
compiled into the compiler (design doc: docs/projects/c_import.md):
- Preprocess —
libs/extras/c_preprocessor/: macro expansion,
conditionals,#includeresolution, predefined platform macros
keyed off the target word size. - Parse —
libs/extras/c_import/generated_c_parser.w, a PEG
parser generated fromtests/parser_generator/c.pg. - Import —
libs/extras/c_import/importer.w: lowers typedefs,
structs (C-aligned via inserted__ci_pad_*filler fields),
enums, andexternfunctions (as weak dynamic symbols); exports
integer object-like macros as constants.
Reproduce failures cheaply with ./bin/wv2 check file.w (insert x64
before check for the 64-bit target) — no binary is written.
Failure shapes
c preprocessor: could not read <path>— bad header path (thec_importpath itself gets no existence pre-check).c preprocessor: #error in <header>: <text>— a live#error
branch, usually a conditional the predefined macros do not satisfy.<header>:line:col: syntax error: expected ..., found ...followed
byc_import: header parse failed in <file>:<line>— the parser
reports the furthest token any parse attempt reached; usually a
declaration shape the C grammar lacks.- A function silently missing: first-definition-wins collision (W's
ownopen/read/mallocwrappers keep priority over libc's), or
astatic/inlinedeclaration, which is declared-but-skipped.
Compile with-vto surfacenote: c_import skipped '<name>': ...
(a note, not a warning —-v --strictstill passes). - A call that faults at runtime: imported functions are weak, so
a symbol the library does not actually export loads as a null GOT
slot instead of failing at startup. A hand-writtenextern
declaration stays strong and fails at load time instead. - Struct layout drift inside bit-field regions: bit-field members are
skipped, so that region's layout is coarse.
Pinning a fix: torture fixtures
Regressions go into the compile-only fixture groupc_import_torture_test, following tests/c_import_torture_fixture.w:
a tests/<name>_fixture.w + local tests/<name>_fixture.h pair whose
W body uses every imported shape, so an import regression fails the
compile. The fixture's header comment carries # expect_stderr: /# reject_stderr: / # expect_fail directives asserted bybin/wfixture, plus # wbuild: fixture_group=c_import_torture_test
to join the group (the generated manifest picks it up on the next run),
then ./wbuild c_import_torture_test.
Env-blocked targets and their substitutes
c_import_test, c_import_errno_test and c_import_libc_test
produce 32-bit dynamically linked binaries that need the i386 loader
(/lib/ld-linux.so.2, package libc6:i386); without it they fail at
exec with "required file not found". On such hosts assert through the
compile-only fixture targets (c_import_torture_test,c_import_error_directive_test, c_import_missing_header_test,c_import_verbose_note_test) or the x64 twins
(c_import_libc_64_test, x64_c_import_knr_test), which run with the
host's own x86-64 loader.