Version 0.3.5
autoheaders automatically generates header files from C source code.
Install with pip:
sudo pip3 install autoheaders
To install locally, run without sudo
and add the --user
option.
Clone the repository (you’ll need to have Git installed):
git clone https://git.taylor.fish/taylor.fish/autoheaders cd autoheaders
Then install with pip:
sudo pip3 install .
Alternatively, you can run: [1]
sudo ./setup.py install
With either command, to install locally, run without sudo
and add the
--user
option. [2]
Run the first set of commands in the previous section to clone the repository. Then install the required dependencies:
sudo pip3 install -r requirements.txt
To install the dependencies locally, run without sudo
and add the
--user
option.
If you installed autoheaders, you can simply run autoheaders
. [3]
Otherwise, run ./autoheaders.py
. This will display usage information
similar to the following:
autoheaders [options] [--] <c-file> autoheaders -h | --help | --version
Arguments:
<c-file>
: The C source code file from which to generate the header. If-
is passed, standard input is read (unless the argument is preceded by--
).
Options:
-p --private
: Generate a private header file containing static declarations.-o <file>
Write the header file to the specified file. If given after-p
, a private header is written. This option may be given twice: once before-p
, and once after. If not given, the header is written to standard output.-c <cpp-arg>
: Pass arguments to the C preprocessor. Separate arguments with commas, or provide multiple-c
options. Use\
to escape characters. [4] Note that when the preprocessor is run, the current working directory is the parent directory of the C file. It is therefore recommended to convert paths in-c
arguments to absolute paths.--debug
: Run the program in debug mode. Exception tracebacks are shown.
The generated header file is written to standard output.
The C preprocessor command that is used is determined by trying the following options in the order listed:
- The value of the
AUTOHEADERS_CPP
environment variable. This is parsed and interpreted as a shell command. For example:AUTOHEADERS_CPP="gcc -E"
gcc -E
clang -E
The C preprocessor must be compatible with GCC’s preprocessor (gcc -E
).
See the next section for how to structure your C code so that headers can be generated properly.
autoheaders parses the given C file and looks for all function definitions,
global variable definitions, and non-extern
global variable declarations
(which are essentially zero-initialized definitions).
Definitions and declarations marked static
are ignored. The remaining
function definitions are transformed into function declarations and are added
to the header file. The remaining variable definitions and declarations are
transformed into extern
variable declarations and are added to the header
file.
Additionally, you can explicitly specify code to be added to the header—this is
necessary if you define structs or need certain files to be to be included in
the header. All code between #ifdef HEADER
and #endif
is copied to the
header file, intermixed with the generated declarations (depending on where the
#ifdef HEADER
blocks occur in the source file).
Include guards can also be generated. If a comment of the form
@guard <name>
is present, an include guard will be generated using the
macro <name>
. The comment must appear at the top level, outside of any
blocks or preprocessor conditionals.
Files that are included (with #include
) by the C file do not need to exist
and are not processed by autoheaders, except for files inside
#ifdef HEADER
blocks. [5]
Sometimes, however, certain #include
statements do need to be processed for
autoheaders to parse the file properly, especially if the included files define
macros that are used at the top level (i.e., not inside functions) by the
original C file. In this case, a comment of the form @include
can be placed
after the #include <...>
, on the same line. For example:
#include <assert.h> /* @include */
#include <stdio.h>
will cause autoheaders to include assert.h
during its processing, but
stdio.h
will not be included (unless these #include
statements appear
in an #ifdef HEADER
block [5]).
In addition to the public header files normally generated by autoheaders, private header files can be generated as well. These header files are designed to be included only by the corresponding C file and remove the need for forward declarations of static functions.
To generate a private header file, provide the option -p
.
#ifdef HEADER
blocks will not be included in the private header. To include
code in the private header (for things like private structures), use
#ifdef PRIVATE_HEADER
blocks (also closed with #endif
, of course).
Finally, the macro ANY_HEADER
will be defined for both public and private
headers, which allows you to use #ifdef ANY_HEADER
blocks to include code
in both headers. You shouldn’t usually need to do this, however.
Also see the example/ directory for a more complete example.
If the following code is in test.c
:
// @guard TEST_H
#include "test.h"
#include "test.priv.h"
#include <stdio.h>
#ifdef HEADER
#include <stdint.h>
typedef struct {
int32_t first;
int32_t second
} IntPair;
#endif
const IntPair zero_pair = { 0, 0 };
// Adds a pair of integers.
int32_t add_pair(IntPair pair) {
return add(pair.first, pair.second);
}
// Adds two integers.
static int32_t add(int32_t first, int32_t second) {
printf("Adding %"PRId32" and %"PRId32"\n", first, second);
return first + second;
}
then you can run autoheaders test.c -o test.h
to generate the public header
file. test.h
will then contain the following code:
#ifndef TEST_H
#define TEST_H
#include <stdint.h>
typedef struct {
int32_t first;
int32_t second;
} IntPair;
extern const IntPair zero_pair;
// Adds a pair of integers.
int32_t add_pair(IntPair pair);
#endif
Similarly, you can run autoheaders test.c -p -o test.priv.h
to generate the
private header file. test.priv.h
will then contain the following code:
// Adds two integers.
static int32_t add(int32_t first, int32_t second);
You can also generate both the public and private headers at the same time, which is faster than generating each individually, by running:
autoheaders test.c -o test.h -p -o test.priv.h
See the example/ directory for a more complete example.
If an included header contains a large about of code, it can cause autoheaders to run slowly. Certain non-standard headers may not even be able to parse. In these cases, you can create fake headers that override the real ones when autoheaders runs.
Fake headers simply need to declare the types and macros from the real header
that your code uses. The types do not need to match the real ones; they just
need to be declared. The recommended way to do this is with typedefs. For
example, typedef int div_t;
is a suitable definition of div_t
,
regardless of whether or not div_t
is actually an integer.
Macros used by your code must be defined in the fake header as well. While, as with types, the fake header macros don’t need to match the real ones, a little more care must be taken to ensure that the fake macros produce syntactically valid code.
For example, a fake header for pthread.h
could contain the following:
typedef int pthread_t;
typedef int pthread_mutex_t;
#define PTHREAD_MUTEX_INITIALIZER 0
Put your fake headers in a directory with a structure that matches that of the
real headers. For example, using the directory fake/
, if your code
contained #include <pthread.h>
, the fake header would be stored in
fake/pthread.h
. If your code contained #include <pthread/pthread.h>
,
the fake header would be stored in fake/pthread/pthread.h
.
After creating your fake headers, you can run autoheaders as follows:
autoheaders <c-file> -c -I<fake-header-dir>
where <fake-header-dir>
is the directory containing the fake headers.
Following the examples above, autoheaders might be invoked as:
autoheaders file.c -c -Ifake/
Additionally, you can include your fake header directory automatically by
giving it a special name. When running, autoheaders will look for a directory
named .fake-headers/
in the directory containing the C file or in any parent
directory. If such a directory is found, it will be included with -I
.
See this article about pycparser for more information about fake headers.
The most likely error to be encountered is when code contains non-standard C
extensions; for example, __attribute__
in GCC. C code is parsed after
preprocessing, so the use of non-standard features in any included files causes
problems for the parser.
These issues can be easily mitigated by modifying shim.h.
(__attribute__
and some other extensions are currently handled and do not
cause errors.) shim.h
contains typedefs and macro definitions that
transform the code into standards-compliant C (at least enough to be parsed).
For more information, see this article about pycparser.
If you find that something is missing from shim.h
, please file an issue or
open a pull request.
- Python ≥ 3.5 with pip installed
- A GCC-compatible compiler (specifically, a compatible C preprocessor); see the Usage section.
- The following Python packages:
The installation instructions above handle installing the Python packages.
Alternatively, running pip3 install -r requirements.freeze.txt
will install
specific versions of the dependencies that have been confirmed to work.
Version 0.3.3:
- autoheaders can now be installed from PyPI.
Version 0.3.2:
- Array declarations without explicit sizes (appearing as part of a definition) are no longer copied to header files, as this causes compilation errors.
Version 0.3.1:
- Fixed issue where array declarations would be ignored.
Version 0.3.0:
- Public and private headers can now be generated at the same time.
Version 0.2.1:
- Clarified how the current working directory changes when the preprocessor is run.
Version 0.2.0:
- The order of
#ifdef HEADER
blocks and definitions is now preserved. If an#ifdef HEADER
block appears after a function definition, it will now appear after the generated declaration in the header file.
autoheaders is licensed under the GNU General Public License, version 3 or any later version. See LICENSE. [7]
This README file has been released to the public domain using CC0.
[1] | setuptools must be installed before running setup.py . If pip
is installed, setuptools likely is as well; otherwise, run
sudo pip3 install setuptools or pip3 install --user setuptools . |
[2] | If using setup.py , add the --user option after install
(rather than before it). |
[3] | If Python package binary directories are not in your $PATH , you may
have to run python3 -m autoheaders instead. |
[4] | Backslashes can be used to include commas in the passed arguments: for
example, -c 'arg\,with\,commas' will pass the single argument
arg,with,commas to the preprocessor. Other backslash escapes are simply
interpreted as the second character: -c 'a\bc\\d' becomes abc\d . |
[5] | (1, 2) Including #ifdef PRIVATE_HEADER and #ifdef ANY_HEADER blocks. |
[6] | Specifically, pkg_resources must be installed. Some package managers
distribute pkg_resources separately from setuptools . For example,
in Debian GNU/Linux and many derivatives, pkg_resources is available
via apt in python3-pkg-resources . |
[7] | This does not apply to generated header files; the copyright and license status of such files is unaffected by autoheaders. |