box64/wrapperhelper/README.md

126 lines
6.5 KiB
Markdown

# 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`:
```sh
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
```c
#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 be `c`;
- if a parameter has a pointer to `TYPE`, or a structure containing `TYPE`, the output will be a `GOM` function.
Declarations of the form
```c
#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:
```c
{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:
```sh
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
```
1. This form outputs the list of preprocessor tokens (the "post-prepare" phase).
2. This form outputs the list of processor tokens (the "post-preprocessor" phase).
3. 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:
```sh
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__(_)`)