[ffigen] Update lib/src/README.md (#100)
diff --git a/pkgs/ffigen/lib/src/README.md b/pkgs/ffigen/lib/src/README.md index d999223..900c9f7 100644 --- a/pkgs/ffigen/lib/src/README.md +++ b/pkgs/ffigen/lib/src/README.md
@@ -1,41 +1,66 @@ -## Project Structure +# **_package:ffigen_**: Internal Working +## Table of Contents - +1. [Overview](#overview) +2. [LibClang](#LibClang) + 1. [The Wrapper library](#The-Wrapper-library) + 2. [Generation and Usage](#Generation-and-Usage) + 3. [Bindings](#Bindings) +3. [Scripts](#scripts) + 1. [ffigen.dart](#ffigen.dart) + 2. [setup.dart](#setup.dart) +4. [Components](#components) + 1. [Config Provider](#Config-Provider) + 2. [Header Parser](#Header-Parser) + 3. [Code Generator](#Code-Generator) +# Overview +`package:ffigen` simplifies the process of generating `dart:ffi` bindings from C header files. It is simple to use, with the input being a small YAML config file. It requires LLVM (9+) to work. This document tries to give a complete overview of every component without going into too many details about every single class/file. +# LibClang +`package:ffigen` binds to LibClang using `dart:ffi` for parsing C header files. A wrapper library must be generated to use it, as `dart:ffi` currently [doesn't support structs by value](https://github.com/dart-lang/ffigen/issues/3). +## The Wrapper library +> Note: The wrapper is only needed because `dart:ffi` currently doesn't support Structs by value. -- `bin` - Contains ffigen.dart script which end user will execute. -- `tool` - Contains script to generate LibClang bindings using Code_Generator submodule (dev use only). -- `example` - Example projects which demonstrate generation of bindings for given C header files. -- `lib/src/code_generator` - Generates binding files. -- `lib/src/config_provider` - Holds configurations to be passed to other modules. -- `lib/src/header_parser` - Parses header files, utilises clang_bindings. +The `wrapper.c` file consists of functions that wrap LibClang functions. Most of them simply convert structs by value to pointers. Except - +- `clang_visitChildren_wrap` - The bindings for this function internally uses a **list** of **stack** for maintaining the supplied visitor functions. This is required because this function takes a function pointer which itself passes a struct by value. All this effort makes `clang_visitChildren_wrap` behave exactly like `clang_visitChildren`. +## Generation and Usage +The files needed for generating the wrapper are in `lib/src/clang_library`. +> The `wrapper.def` file is only needed on windows because the symbols are otherwise hidden. -## Basic Workflow -1. The User provides the location all the header files (as a list of globs or filepaths), -For each header file, we create a translation unit and parse the `declarations` in it -to the bindings. -2. User can provide `header filters` to select which declaration from a particular header file should be added to the generated bindings. The can provide a list of header 'names' to include/exclude. -We compare the header file name (not the exact path) to decide. -The default behaviour is to include everything that's included when parsing a header. -3. Use can provide Compiler options, which are passed to clang compiler as it is. -4. All bindings are generated in a single file. +The libclang wrapper can be _manually_ generated using `pub run ffigen:setup`. See [setup.dart](#setup.dart) for details. -# Code Details -## Modules -We are using libclang to parse header files. -This project is roughly divided in 3 major modules - -### code_generator -Converts a library(all bindings) to an actual string representation. -- Library (output of the header parser). -- Writer (provides configurations for generating bindings). -- Binding (base class for all bindings - Func, Struc, Global, EnumClass, etc). -### config_provider -This takes care of validating user config files, printing config warnings and errors, -converting config.yaml to a format the header_parser can use. -- Spec (represents a single config, which a user can provide in the config file). -- Config (holds all the config which will be required by header parser). -### header_parser -Uses libclang to convert the header to a Library which is then used by code_generator. -- clang_bindings (bindings to libclang which are used for parsing). -- sub_parsers (each sub-parser parses a particular kind of declaration - struct, function, typedef, enum). -- type_extractor (extracts types from variables, function parameters, return types). -- includer (tells what should/shouldn't be included depending of config). -- parser (Main Entrypoint) (creates translation units for all header files, and sets up parsing them). -- translation_unit_parser (parses header files, splits declarations and feeds them to their respective sub_parsers). +The generated file is placed in the project's `.dart_tool/ffigen` folder, the file name also specifies the ffigen version (E.g - `_v0_2_4_libclang_wrapper.dylib`), this helps ensure the correct wrapper is being used for its corresponding version. + +This dynamic library is then used by [Header Parser](#header-parser) for parsing C files. +## Bindings +The config file for generating bindings is `tool/libclang_config.yaml`. The bindings are generated to `lib/src/header_parser/clang_bindings/clang_bindings.dart`. These are used by [Header Parser](#header-parser) for calling libclang functions. +# Scripts +## ffigen.dart +This is the main entry point for the user- `pub run ffigen`. +- Command-line options: + - `--verbose`: Sets log level. + - `--config`: Specifies a config file. +- `ffigen.dart` will first check if a dynamic library already exists and is up to date. If not, it tries to auto-create it. If that fails, user must excplicitly call [setup.dart](#setup.dart). +- The internal modules are called by `ffigen.dart` in the following way: + - It first creates a `Config` object from an input Yaml file. This is used by other modules. + - The `parse` method is then invoked to generate a `Library` object. + - Finally, the code is generated from the `Library` object to the specified file. +## setup.dart +Used to generate the wrapper dynamic library. Users will need to explicitly call this if `pub run ffigen` is unable to auto-create the dynamic library. +> `clang` must be on user's path for `setup.dart` to work. + +- Command-line options: + - `-I`: Specifies header includes. + - `-L`: Specifies library includes. +- `setup.dart` generates the dynamic library to the project's `.dart_tool/ffigen` folder using `clang`. +# Components +## Config Provider +The Config Provider holds all the configurations required by other modules. +- Config Provider handles validation and extraction of configurations from YAML files. +- Config Provider converts configurations to the format required by other modules. This object is passed around to every other module. +## Header Parser +The Header Parser parses C header files and converts them into a `Library` object. +- Header Parser handles including/excluding/renaming of declarations. +- Header Parser also filters out any _unimplemented_ or _unsupported_ declarations before generating a `Library` object. +## Code Generator +The Code Generator generates the actual string bindings. +- Code generator handles all external name collisions, while internal name conflicts are handled by each specific `Binding`. +- Code Generator also handles how workarounds for arrays and bools are generated.