Crefl - a C-type-reflection-API and clang plug-in to write reflection metadata.
The Crefl API and plugin provides access to runtime reflection metadata for C interface declarations with support for arbitrarily nested combinations of: intrinsic, set, enum, struct, union, field, array, constant, and function.
Crefl addresses the following three areas:
This example has an outer-loop iterating through struct types and an inner-loop iterating through struct fields.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <assert.h>
#include <crefl/model.h>
#include <crefl/db.h>
int main(int argc, const char **argv)
{
if (argc != 2) {
fprintf(stderr, "error: usage: %s <filename>\n", argv[0]);
exit(1);
}
decl_db *db = crefl_db_new();
crefl_db_read_file(db, argv[1]);
size_t ntypes = 0;
crefl_source_decls(crefl_root(db), NULL, &ntypes);
decl_ref *_types = calloc(ntypes, sizeof(decl_ref));
assert(_types);
crefl_source_decls(crefl_root(db), _types, &ntypes);
for (size_t i = 0; i < ntypes; i++) {
size_t nfields = 0;
if (crefl_is_struct(_types[i])) {
printf("%s %s : %zu\n",
crefl_tag_name(crefl_decl_tag(_types[i])),
crefl_decl_name(_types[i]),
crefl_type_width(_types[i]));
crefl_struct_fields(_types[i], NULL, &nfields);
decl_ref *_fields = calloc(nfields, sizeof(decl_ref));
assert(_fields);
crefl_struct_fields(_types[i], _fields, &nfields);
for (size_t j = 0; j < nfields; j++) {
printf("\t%s %s : %zu\n",
crefl_tag_name(crefl_decl_tag(_fields[j])),
crefl_decl_name(_fields[j]),
crefl_type_width(_fields[j]));
}
}
}
crefl_db_destroy(db);
}
Crefl implements a data model based on the description of the C data types in ISO/IEC 9899:9999 with minor changes. The following sections describe:
Crefl variations from the C standard:
The Crefl API uses a small number of primary data types for the reflection graph database, the declaration graph nodes and their properties.
Type | Description |
---|---|
decl_node |
graph database declaration node type |
decl_db |
graph database containing the declarations |
decl_ref |
reference to a single declaration graph node |
decl_tag |
enumeration indicating graph node type |
decl_id |
indice of a graph node in the graph database |
decl_sz |
size type used for array size and bit widths |
decl_set |
type used to indicate many-of set enumerations |
decl_raw |
raw value used to store constants |
The Crefl data structure consists of an array of decl nodes which have a type tag, a set of properties, an interned name, a link to the next item in a list, a link to a child item and a link to an optional attribute list.
Type | Name | Description |
---|---|---|
decl_tag |
tag |
tagged union node type |
decl_set |
props |
type specific properties |
decl_id |
name |
link to node name |
decl_id |
next |
link to next item (south) |
decl_id |
link |
link to child item (east) |
decl_id |
attr |
link to attribute list (south-east) |
The semantic topology of the graph links (south, south-east, east) are used to think about graph layout. On a board, the next node would be south, or below the current node. A child or link node would increment to the east (field type, function parameters, etc). Attributes can exist on any node type and thus are semantically referred to as south-east.
The decl node contains a union with type specific properties such as a count, a width or a size. Not all types use the link field or the quantifer. The type none is used in the link field of an empty struct or union, in the next field to indicate the end of lists, and in the attr field to indicate the absense of attributes.
This table table lists the properties used by each subtype:
Type | Link | Properties | Description |
---|---|---|---|
none |
empty type | ||
typedef |
✓ | alias to another type definition | |
intrinsic |
sz width |
machine type quantified with width in bits | |
set |
✓ | sz width |
machine type with many-of sequence of masks |
enum |
✓ | sz width |
machine type with one-of sequence of integers |
struct |
✓ | sequence of non-overlapping types | |
union |
✓ | sequence of overlapping types | |
field |
✓ | sz width |
named field within struct or union |
array |
✓ | sz count |
sequence of one type |
pointer |
✓ | sz width |
pointer type |
constant |
✓ | sz value |
named constant |
function |
✓ | sz addr |
function with input and output parameter list |
param |
✓ | named parameter with link to next | |
qualifier |
✓ | qualifiers for intrinsic types | |
attribute |
✓ | custom attribute name | |
value |
custom attribute value | ||
archive |
✓ | collection of source objects | |
source |
✓ | maps to translation unit | |
alias |
✓ | aliases node overriding its next link |
Crefl contains a work-in-progress experimental model for C linkage that composes the identity of function interfaces and their associated types using Merkle Tree cryptographic hash sums. Merkel Tree style hash sums are composed from the hierachical node properties of an abstract type tree, a portion of the abstract syntax tree containing only the function interfaces and type information. All functions and their associated types are assigned hashes with the following constraints and properties:
This example invocation of crefltool
shows the extended reflection meta-data
generated with ./scripts/run_tests.py --dump-all test/adjacent-decls-3.h
:
The Crefl implementation is currently alpha software.
__attribute__
).
alias(
"symbol")
aligned(
alignment)
always_inline
annotate(
"string")
deprecated
packed
pure
used
unused
crefl has been tested on ubuntu 20.04 LTS.
ubuntu 20.04 LTS:
sudo apt-get install llvm libclang-dev
ubuntu 20.04 LTS:
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo
cmake --build build -- --verbose
to run the crefl plugin and dump the reflection table to stdout:
clang test/simple-struct-1.h \
-Xclang -load -Xclang build/libcrefl.so \
-Xclang -plugin -Xclang crefl \
-Xclang -plugin-arg-crefl -Xclang -dump
to run the crefl plugin and write the reflection data to a file:
clang test/simple-struct-1.h \
-Xclang -load -Xclang build/libcrefl.so \
-Xclang -plugin -Xclang crefl \
-Xclang -plugin-arg-crefl -Xclang -o \
-Xclang -plugin-arg-crefl -Xclang tmp/simple-struct-1.refl
to enable crefl plugin debugging, add the following option:
-Xclang -plugin-arg-crefl -Xclang -debug