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/<name>.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 atlrocket/toolchain/<name.lua>to yourotypedirectory.
If your toolchain is standalone (not part of a custom otype), you may wish to generate a rockspec via luarocks, in order to install, test and distribute your toolchain:
> mkdir -p <lrocket-toolchain-my-toolchain>/lrocket/toolchain
> cd <lrocket-toolchain-my-toolchain>
> touch lrocket/toolchain/<my-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/<my-toolchain>.lua.
It should export a Lua table which implements the following functions:
Required Functions
Basic Structure
--lr:abi 1.2.0
local <my-toolchain> = {}
-- implementation
...
return <my-toolchain>
function configure (cfg, userargs)
Parameters
cfg– the read/write accessible LRocket compiler configuration (lrocket.FinalConf) containing all settings for this toolchainuserargs– the build arguments specified by the user (lrocket.BuildConf) e.g. via their rockspec.build config, global settings orlrccommand-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:
SDKs typically use GNU style compilers.
In this case you can often inherit from the pre-shipped gnu Toolchain:
@ 'lrocket/toolchain/<my-toolchain.lua>'
[top of file]
+local gnu = require 'lrocket.toolchain.gnu'
+local utils = require 'lrocket.utils'
[end of file]
-return <my-toolchain>
+return utils.inherit(<my-toolchain>, gnu)
An example configure function based on the gnu Toolchain could look like this:
Example
-- 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:
--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.
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 instead.
> luarocks make # install the toolchain
# Option 1: using a target rule
> lrc <test.lua> --target x86_64-minimalos-musl -o <output.xxx>
# Option 2: using an otype which forces using the toolchain
> lrc <test.lua> --otype <my-otype> -o <ouptut.xxx>
or in a test .rockspec file:
...
build = {
type = 'lrocket',
otype = 'executable'
entrypoint = 'test.lua',
output = '<output.xxx>',
# Option 1: using a target rule
target = 'x86_64-minimalos-musl'
# Option 2: using an otype which forces using the toolchain
otype = '<my-otype>',
}
Publishing
Note If you added your toolchain as part of a custom
otype, continue reading at Publishing (Writing anotype) instead.
Once you have tested your toolchain, move on to choosing a license and follow 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-<name>.lua
To define a target rule, create a file lrocket/targetrules/<priority>-<name>.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 evaluateduserargs– the build arguments specified by the user (lrocket.BuildConf) e.g. via their rockspec.build config, global settings orlrccommand-line arguments
Example
-- 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