Search code examples
cfileheader-files

What is a .c.h file?


When looking through the CPython source code I came across a file called listobject.c.h. I'm not sure what this file extension ".c.h" is. The file has a mix of function prototypes and function definitions. Is there a reason to add .c to the extension instead of just making it a .h file?

I couldn't find any information about this file extension on Google since they remove special characters in search queries so I got information about .ch files instead.


Solution

  • It has no generally applicable meaning, but typically, it's used to imply that it's really an implementation file that, due to the needs of the build system, is #include-ed in another file.

    Normal header files provide prototypes and declarations, and typically only provide implementations of things that are declared inline or static (and even static is frowned on unless link-time optimization is used to deduplicate the compiled versions of it). Providing other sorts of implementations risks repeated definitions of the same visible entities in multiple compiled object files, leading to problems with duplicates at link time. Since the .c.h file in this case is intended to be #includeed in exactly one file (e.g. longobject.c.h is only intended to be included in longobject.c in the parent directory), there are no problems with #includeing it, as it won't create duplicate definitions.

    The reason CPython specifically uses them is the Argument Clinic. It's a tool that lets them generate optimized argument parsing code for built-ins without having to either:

    1. Hand-write optimal parsing code on a function-by-function basis, or
    2. Rely on general purpose, "printf-like" parsing APIs that are convenient, but less efficient

    As an extra benefit, when they improve their parsing framework and options (e.g. when they added vectorcall as an option for implementing methods/functions), Argument Clinic can be updated in one place, and the benefits immediately accrue across the entire code base.

    Because Argument Clinic regenerates the files from scratch on each run, they can't be easily incorporated into the hand-written "real work" implementation functions without creating a lot of code churn and causing problems for people submitting patches, so they factored out the generated code into the .c.h files to avoid conflicts like that.