Microdragon / Kernel

A microkernel written in Rust
Mozilla Public License 2.0
0 stars 1 forks source link

Feature: Compile-time Configuration Framework #3

Open Rain336 opened 10 months ago

Rain336 commented 10 months ago

Feature: Compile-time Configuration Framework

Microdragon needs a compile-time configuration framework to simplify configuring the kernel for users and developers alike. Additionally a command line tool should be made to simplify configuring the kernel for end users who don't know or don't want to dig deeper into the kernel.

The Config.toml File

The configuration framework will add a new files to crates besides their Cargo.toml file. This Config.toml will contain the compile time configuration of the crate and it's schema is defined by how the crate uses it. Each crate should supply a default Config.toml with sane default values and comments describing each option.

The value! Macro

The configuration framework should supply a proc-macro value! that reads out a value from the config with an optional default if it's missing. The general syntax should be as follows: value!($option:lit $(, $( $default:expr )?)?); The second $option parameter has to be a string literal. If the macro parameters isn't given as displayed, a compile_error! with a descriptive message should be generated to fail compilation and notify the developer. The $option parameter is used to find which key to return from the config. It's a string literal allowing the same dotted key syntax as defined in the TOML spec to access values in the Config.toml. This syntax is slightly extended by allowing arrays to be accessed by tier index, so the second element of foo = [ "A", "B", "C" ] can be accessed using foo.2 returning "B". This also works for arrays of tables, so bar inside foo = [ { bar = 1 } ] can be accessed using foo.0.bar. Most data types are returned as their respective literals by this macro. Arrays and tables cannot be returned, doing so will generate a compile_error!. Date and time types are returned as ISO-8601 formatted strings, assuming the build computer's local time zone. It is recommended to cache the Config.toml to prevent further disk I/O.

The #[config(...)] Macro

A version of the built-in #[cfg(...)] macro that reads it's values out of the Config.toml. Similar to it's built-in counterpart, it can use any(...), all(...) and not(...) to match multiple options and invert options. For actually matching an option, a syntax similar to the built-in is used, but instead of a simple identifier, the dotted notation as described above can be used, with one exception. Only quoted keys with " are allowed due to the way that rust macros work. For the matching option not only strings, but any literal should be supported, using the same conversion as described above for the value! macro. If the type of the resolved key is a bool, the the = true/false can be left out in which case the option matches, if the resolved bool is true.

The #[config_attr(..., ...)] Macro

A version of the built-in #[cfg_attr(...)] macro that reads it's values out of the Config.toml. It accepts the same syntax as described above for #[config(...)] as it's first parameter with the second being the attribute to insert, if the first parameter matches.

Configuration CLI

Finally a CLI tool should be crated to help configure the kernel for users who don't plant to delve too deep into the kernel's code and instead just want to configure and build the kernel, be it manual or automated with scripts. This CLI tool should support two modes of usage, one setting, getting and listing keys using command line arguments and another mode using a terminal UI.

Command Line Args Mode

The command line mode allows doing multiple operations at once, each returning one line in the result. The operations are as follows:

Terminal UI Mode

The terminal UI displays the config in a tree view, displaying a key's comment. The tree should be collapsed on start with the user expanding options they are interested in. The user should also be able to restrict their view onto a certain sub-tree, with the option to go back up a sub-tree restriction using a button press. Trying to go out of the root tree, will close the terminal UI. The key comments should be able to pick a widget for their option using a mnemonic line, otherwise a set of default widgets gets displayed. These mnemonic line are not displayed in the terminal UI. If the CLI is started in a cargo workspace, a tree of projects inside the workspace is displayed. Selecting a project, restricts the view onto that project's configuration tree. Trying to go out of that root tree will return the user back to the project select tree. Finally the terminal UI accepts some command line arguments too.

Disambiguate -p <project-path>

The -p parameter is used in both command line mode and terminal UI mode. To disambiguate what mode should be used, the other arguments should be examined. If one of the unambiguous arguments is passed, -r for terminal UI mode and -s / -g / -l for command line mode, the corresponding mode should be use. If arguments from both modes are passed, the tool should error out with a message explaining the error. If only -p is passed, terminal UI mode should be assumed, since command line mode with only -p is basically a no-op.

Terminal UI Comment Mnemonics

Rain336 commented 10 months ago

After thinking, instead of supplying custom cfgs using a build.rs script, it makes more sense to supply custom #[cfg(...)] and #[cfg_attr(...)] macros. This way we can allow a more flexible and appropriate syntax for querying keys. Updated the feature accordingly.

Rain336 commented 10 months ago

Rust disallows creating attribute proc-macros called cfg or cfg_attr, so I had to rename them.

config! -> value! #[config::cfg(...)] -> #[config(...)] #[config::cfg_attr(..., ...)] -> #[config_attr(..., ...)]