# Using custom Lua plugins

It is possible to extend the capabilities of BuildCache with
[Lua](https://www.lua.org/). See [lua-examples](../lua-examples/) for some
examples of Lua wrappers.

## Location of wrapper scripts

BuildCache first searches for Lua scripts in the paths given in the environment
variable `BUILDCACHE_LUA_PATH` (colon separated on POSIX systems, and semicolon
separated on Windows), and then continues searching in `$BUILDCACHE_DIR/lua`.
If no matching script file was found, BuildCache falls back to the built in
compiler wrappers (as listed above).

## Wrapper identification

The first line of a Lua based program wrapper script must be a Lua comment with
a special "match"-statement that specifies a regex that matches the name of the
program that is to be wrapped, e.g:

```Lua
-- match(gcc.*)
```

More detailed checks can be done in the optional `can_handle_command` method.

## Anatomy of a wrapper

The following methods can be implemented (see
[program_wrapper.hpp](../src/wrappers/program_wrapper.hpp) for a more detailed
documentation):

| Function | Returns | Default |
| --- | --- | --- |
| can_handle_command() | Can the wrapper handle this program? | true |
| resolve_args() | (nothing) | - |
| get_capabilities() | A list of supported capabilities | An empty table |
| get_build_files() | A table of build result files | An empty table |
| get_program_id() | A unique program identification | The MD4 hash of the program binary |
| get_relevant_arguments() | Arguments that can affect the build output | All arguments |
| get_relevant_env_vars() | Environment variables that can affect the build output | An empty table |
| get_input_files()\* | Get the paths to the input files for the command | And empty table |
| preprocess_source() | The preprocessed source code (e.g. for C/C++) | An empty string |
| get_implicit_input_files()\* | Get a list of paths to implicit input files (includes) | And empty table |
| run_for_miss() | A `sys::run_result_t` compatible table | *See note\*\** |

\*: `get_input_files` and `get_implicit_input_files` are only used in direct
mode, which requires that `direct_mode` is reported by `get_capabilities`.

\*\*: `run_for_miss`, when defined, shall run the actual command (as specified by
`ARGS`) if a cache miss occurs. The return value shall be a table consisting of
`std_out`, `std_err` and `return_code` (see
[sys::run_result_t](../src/sys/sys_utils.hpp)). The default implementation is
equivalent to `bcache.run(ARGS, false)`.

## Miscellaneous

All program arguments are available in the global `ARGS` array (an array of
strings). `ARGS[1]` is the path to the program that is being wrapped.

To use Lua standard libraries (`coroutine`, `debug`, `io`, `math`, `os`,
`package`, `string`, `table` or `utf8`), you must first load them by calling
`require_std(name)`. For convenience it is possible to load all standard
libraries with `require_std("*")`, but beware that it is slower than to load
only the libraries that are actually used.

## The bcache library

There is a `bcache` library that exposes some of the internal BuildCache
functions that may be useful. To use the library, call `require_std("bcache")`.

The following functions are available (for more detailed information, look up
the corresponding C++ function documentation):

| Function | Description |
| --- | --- |
| dir_exists(path) | Check if a directory exists |
| file_exists(path) | Check if a file exists |
| get_dir_part(path) | Get the directory part of a path |
| get_extension(path) | Get the file extension of a path |
| get_file_info(path) | Get file information about a single file or directory |
| get_file_part(path, include_ext) | Get the file name part of a path |
| log_debug(str) | Print a log message with log level "DEBUG" |
| log_error(str) | Print a log message with log level "ERROR" |
| log_fatal(str) | Print a log message with log level "FATAL" |
| log_info(str) | Print a log message with log level "INFO" |
| run(args) | Run the given command (passed as a list of arguments) |
| split_args(str) | Construct a list of arguments from a string with a shell-like format |

