# Writing a Toolchain Toolchains tell `lrc` how to configure the underlying C compiler for a specific target platform. The platform could be an excentric CPU architecture or an operating system/execution environemnt which requires extra processing (such as e.g. WebAssembly). ## Setup To create a custom toolchain, create a new folder containing a file `lrocket/toolchain/.lua`. ### Packaging > **Note** If you are creating a toolchain in the frame of creating a custom `otype`, you may skip the following steps and just add a file at `lrocket/toolchain/` to your `otype` directory. If your toolchain is standalone (not part of a custom `otype`), you may wish to generate a [rockspec](https://github.com/luarocks/luarocks/blob/main/docs/luarocks_write_rockspec.md) via luarocks, in order to install, test and distribute your toolchain: ```bash > mkdir -p /lrocket/toolchain > cd > touch lrocket/toolchain/.lua > luarocks write_rockspec ``` Your directory should then look like this: ``` > tree . ├── lrocket │ └── toolchain │ └── my-toolchain.lua └── lrocket-toolchain-my-toolchain-dev-1.rockspec 2 directories, 2 files ``` ## Implementation The main file of your toolchain is `lrocket/toolchain/.lua`. It should export a Lua table which implements the following functions: ### Required Functions * [`configure (cfg, userargs)`](#function-configure-cfg-userargs) ### Basic Structure ```lua --lr:abi 1.2.0 local = {} -- implementation ... return ``` ### function `configure (cfg, userargs)` **Parameters** * `cfg` – the read/write accessible LRocket compiler configuration (`lrocket.FinalConf`) containing all settings for this toolchain * `userargs` – the build arguments specified by the user (`lrocket.BuildConf`) e.g. via their rockspec.build config, global settings or `lrc` command-line arguments This function is required and should perform any required configuration steps for the toolchain, such as adding global compiler arguments, setting toolchain-specific environment variables (variables such as `CC` or `LDFLAGS` are set automatically) or selecting a required Lua version. To see how exisiting toolchains do it, take a look at the following examples: * [The "WebAssembly" Toolchain (`lrocket-build-wasm`)](https://codeberg.org/leso-kn/lrocket-build-wasm/src/branch/main/lrocket/toolchain/wasm.lua) * [The `gnu` Toolchain](https://codeberg.org/lrocket/lrc/src/branch/main/lrocket/toolchain/gnu.lua) SDKs typically use GNU style compilers. In this case you can often inherit from the pre-shipped [`gnu` Toolchain](https://codeberg.org/lrocket/lrc/src/branch/main/lrocket/toolchain/gnu.lua): ```diff @ 'lrocket/toolchain/' [top of file] +local gnu = require 'lrocket.toolchain.gnu' +local utils = require 'lrocket.utils' [end of file] -return +return utils.inherit(, gnu) ``` An example `configure` function based on the `gnu` Toolchain could look like this: **Example** ```lua -- example toolchain 'minimal' local gnu = require 'lrocket.toolchain.gnu' local utils = require 'lrocket.utils' --lr:abi 1.2.0 local minimal = {} function minimal.configure(cfg, userargs) -- example: force LuaJIT cfg.lua_version = 'jit' cfg.env.LUA_VERSION = cfg.lua_version -- set some environment variable cfg.env.MINIMAL_BUILDVAR = tostring(cfg.target) -- add some compiler arguments cfg.cconf:addarg('include', '~/.minimalos/include') cfg.cconf:addarg('ldflag', '-lminimalcore') -- custom lua library cfg.env.LUA_INCDIR = '~/.minimalos/include/minimal-luajit-2.1' cfg.env.LUA_LIBDIR = '~/.minimalos/lib/minimal-luajit-2.1' cfg.env.LUA_LIBDIR_FILE = 'liblua-jit.a' -- configure the toolchain since our toolchain is based on it gnu.configure(cfg, userargs) end -- inherit from the `gnu` toolchain return utils.inherit(minimal, gnu) ``` ### ABI specification When you are writing compiler extensions, you will likely be using parts of the compiler API that are not under semantic versioning. It is therefor recommended to specify the LRocket ABI version by placing a comment in your file: ```lua --lr:abi 1.2.0 ``` This is technically optional, but `lrc` will throw a warning if the LRocket ABI is not specified. ## Testing the Toolchain For testing your toolchain you need to select (use) it. There are two common options for activating a toolchain: Telling an `otype` to force a toolchain or the usually recommended way: defining a [Target Rule](#target-rules). After putting one of the two options in place you can install your toolchain locally in order to test it: > **Note** If you added your toolchain as part of a custom `otype`, [install your otype locally](writing-an-otype.md#testing-the-otype) instead. ```bash > luarocks make # install the toolchain # Option 1: using a target rule > lrc --target x86_64-minimalos-musl -o # Option 2: using an otype which forces using the toolchain > lrc --otype -o ``` or in a test `.rockspec` file: ```lua ... build = { type = 'lrocket', otype = 'executable' entrypoint = 'test.lua', output = '', # Option 1: using a target rule target = 'x86_64-minimalos-musl' # Option 2: using an otype which forces using the toolchain otype = '', } ``` ## Publishing > **Note** If you added your toolchain as part of a custom `otype`, continue reading at [Publishing (Writing an `otype`)](writing-an-otype.md#publishing) instead. Once you have [tested your toolchain](#testing-the-toolchain), move on to [choosing a license](https://choosealicense.com/) and follow [Publishing your code online](https://github.com/luarocks/luarocks/blob/main/docs/creating_a_rock.md#publishing-your-code-online) at the LuaRocks documentation. ## Target Rules Target rules are triggers that are activated when the user builds for a specific operating system, architecture or ABI. They are the recommended way for selecting a toolchain automatically, when it is implicitly needed (e.g. the `android`-toolchain when the target OS is `android-`). > **Note** Target rule Lua files are run in alphabetical order, so it is recommended to prefix them with with a number for the priority, e.g. `lrocket/targetrules/50-.lua` To define a target rule, create a file `lrocket/targetrules/-.lua` in your toolchain or `otype` directory. The file should export a Lua table which implements the `.apply (cfg, userargs)` function. **Parameters** * `cfg` – the read/write accessible LRocket compiler configuration (`lrocket.FinalConf`) containing all settings known at the time when the rule is evaluated * `userargs` – the build arguments specified by the user (`lrocket.BuildConf`) e.g. via their rockspec.build config, global settings or `lrc` command-line arguments **Example** ```lua -- lrocket/targetrules/50-example.lua --lr:abi 1.2.0 local rule = {} function rule.apply(cfg, userargs) if tostring(cfg.target) ~= 'any-any-any' and (cfg.target:matches 'minimalos') then -- automatically select the 'minimal' example toolchain cfg.toolchain = 'minimal' end end return rule ```