.. | ||
include-override | ||
src | ||
example-libc.h | ||
Makefile | ||
README.md |
Wrapper helper
This folder is semi-independent from the parent project (box64
). This sub-project aims to (partially) automating the generation of the private headers in src/wrapped
. This is, however, still a work-in-progress and in alpha.
As such, this sub-project is mainly aimed at people who know how to read code and are familiar with the wrapped libraries part of box64
.
Licensing
This program is under the MIT license. However, some system header files under the LGPL license (copied from a GNU libc Arch Linux installation) have been adapted into the include-fixed
folder; these files are not copied into the output and simply serve as data. As such, I believe this falls under fair use, and does not lead to the output of this program (used in the parent box64
project) being under the (L)GPL license.
Compiling
You need a C compiler and GNU Make. No library is required.
Go to this folder, then run the make
command. This will produce a binary called bin/wrapperhelper
.
This project has been compiled and tested with GCC 14.2.1 20240805
on an x86_64
machine, with no warning emitted.
You may also use the make clean
and make distclean
commands to remove output files (clean
) and directories (distclean
).
Usage
To use the wrapper helper, run the following command in the folder containing this README.md
:
bin/wrapperhelper -I/path/to/system/include "path_to_support_file" "path_to_private.h" "path_to_private.h"
You may add as many -I
options as needed. The folders include-override/<arch>
and include-override/common
are always prioritized, as if they appeared first in the command line.
You may also use the -32
and -64
switches to generate box32
or box64
files respectively. Alterately, you can use the --emu arch
and --target arch
options to select more precisely the emlated and executing platforms, though only x86
, x86_64
and aarch64
are supported for now. By default, everything is as if -64
was supplied.
The first file is a C
file containing every declaration required. The second file is the "requests" input. The third file is the output file, which may be a different file.
The support file may contain pragma declarations of the form
#pragma wrappers type_letters c TYPE
#pragma wrappers type_letters_strict c TYPE
where TYPE
is a type-name
. The second form marks the exact type TYPE
as being a complex type though with a conversion as c
(which may be multiple characters), while the first marks the type TYPE
, regardless of type qualifers (_Atomic
, const
, restrict
, volatile
). Meaning:
- if a parameter has type
TYPE
, the character output will bec
; - if a parameter has a pointer to
TYPE
, or a structure containingTYPE
, the output will be aGOM
function.
Declarations of the form
#pragma wrappers mark_simple TAG
will mark the structure or union with tag TAG
, or the structure or union aliased to TAG
by a typedef
if no such structure exist, as simple. This means that a pointer to such a structure will have a character output of p
.
This is not the same as making the pointer to the structure a complex type with conversion as p
as e.g. pointers to pointers will behave differently.
System headers included (directly or indirectly) by the support file are overriden by the files in include-fixed
.
The first three lines of the input are ignored.
A "request" is a structure containing an object name and, eventually, a default value (GO
, GO2
with type vFiV
to function xxx
, DATA
...) and/or a "solved" value (which is similar, but deduced from the support file).
Valid requests (in the reference file) are:
{GO/GOM/GOW/GOWM} ( name , type )
{GOD/GO2/GOWD/GOW2} ( name , type , name )
// {GO/GOM/GOW/GOWM} ( name ,
// {GO/GOM/GOW/GOWM} ( name , type )
// {GOD/GO2/GOWD/GOW2} ( name ,
// {GOD/GO2/GOWD/GOW2} ( name , type , name )
DATA[V/B/M] ( name , int )
// DATA[V/B/M] ( name ,
// DATA[V/B/M] ( name , int )
(where {A/B}
means A
or B
and [A/B]
means A
, B
or nothing). All other comments are ignored.
If you want to explore the output of the different stages of the helper, you can use the following forms:
bin/wrapperhelper --prepare "path_to_support_file" # (1)
bin/wrapperhelper --preproc "path_to_support_file" # (2)
bin/wrapperhelper --proc "path_to_support_file" # (3)
bin/wrapperhelper "path_to_support_file" # (3) as well
- This form outputs the list of preprocessor tokens (the "post-prepare" phase).
- This form outputs the list of processor tokens (the "post-preprocessor" phase).
- This form outputs the list of constants, type definitions, structure definitions, and declarations (the "post-processor" phase).
Example
To remake the wrappedlibc_private.h
file, use the following command:
bin/wrapperhelper example-libc.h ../src/wrapped/wrappedlibc_private.h ../src/wrapped/wrappedlibc_private.h
This will emit a few marnings and (non-fatal) errors, then write the result directly in wrappedlibc_private.h
.
Maintaining
All of the source code is included in the src
folder.
The main
function is in main.c
.
The first phase of compilation (steps 1-3 and a part of step 5 of the translation phases) is implemented in prepare.c
.
The second phase of compilation (steps 4 and 6) is implemented in preproc.c
.
The third phase of compilation (step 7) is implemented in parse.c
, though no actual parsing of function definitions takes place.
The reading and writing of the _private.h
files is implemented in generator.c
.
Known issues
Only native structures are read. This means that the current version of wrapperhelper
does not detect an issue when a structure has different members or alignments in two different architectures.
No checking of signatures under #ifdef
s is made.
Phase 5 is partially implemented, but could be greatly improved.
The following features are missing from the generator:
- Structures with at least two elements as a parameter
- Large structure as a return type (more than 16 bytes on 64bits, or 8 bytes on 32bits)
- Atomic types
The following features are missing from the preprocessor:
- General token concatenation (though the concatenation of two
PTOK_IDENT
works without issue) - Stringify
- Skipped unexpected token warnings
The following features are missing from the parser:
_Alignas(type-name)
and_Alignas(constant-expression)
(type-name){initializer-list}
- Old style function declarations
- Function definitions are ignored, not parsed
- Attributes are ignored everywhere (with a
#define __attribute__(_)
)