JamPlus manual
Lua Support

Overview

JamPlus has built-in Lua support, provided through a minimal distribution of LuaPlus (http://luaplus.org/) using Lua 5.3. Lua scripts may be run during the Parsing Phase and during the Updating Phase.

JamPlus also utilizes Lua scripts located in bin/scripts/, but these are not executed as part of the build process.


Using Lua during the Parsing Phase

If a Jamfile.lua file is present instead of a Jamfile.jam, Lua execution of Jamfile.lua happens automatically.

There are two rules for execution of Lua script available for use during the rule parsing phase of JamPlus. They are rule LuaString LUA_SCRIPT and rule LuaFile LUA_FILENAME.

rule LuaString LUA_SCRIPT

Executes LUA_SCRIPT, returning any results back to the caller.

Parameters
LUA_SCRIPTSyntactically correct Lua script embedded in a string. Only the first string list item is executed. Please note that double quotes should be escaped.
Returns
If the Lua script doesn't return any values, the return value is an empty list. If the Lua script does return values, the return values are transformed to a Jam string list. Nested tables are collapsed.

rule LuaFile LUA_FILENAME

Executes LUA_FILENAME, returning any results back to the caller.

Parameters
LUA_FILENAMEThe filename of the Lua script to run.
Returns
If the Lua script doesn't return any values, the return value is an empty list. If the Lua script does return values, the return values are transformed to a Jam string list. Nested tables are collapsed.


Using Lua in Actions

Using the lua modifier for an action, Lua script can be run in a thread within the Jam process.

actions lua RunLuaScript
{
osprocess = require 'osprocess'
osprocess.sleep($(SLEEP))
print($(TEXT))
}


Lua Line Filters

The LineFilters table contains a mapping of an action name to a line-by-line parsing function. For every line of output received by the action, the appropriate LineFilters table actionname->function is run. The function can do with the output what it wants and return the result.

For example, in the LineFilters.Compiler function and action below, a GCC-style error message is changed into a Visual C++ compatible error message.

USE_LUA_LINE_FILTERS = 1 ;
LuaString "
LineFilters.UpperCaseRule = function(input)
return '-> ' .. input:upper()
end
LineFilters.LowerCaseRule = function(input)
return '-> ' .. input:lower()
end
LineFilters.Compiler = function(input)
return input:gsub('(.-):(%d+):(.+)', '%1(%2) %3')
end
" ;
actions UpperCaseRule {
echo This text will be uppercase.
echo This text will also be uppercase in the output.
}
actions LowerCaseRule {
echo THIS TEXT will be LOWERCASE.
}
actions Compiler {
echo c:\the\directory\filename.cpp:1000:This is an error message.
}
Always all ;
UpperCaseRule all ;
LowerCaseRule all ;
Compiler all ;


Accessing Jam from Lua

Within a Lua script, it is possible to access Jam variables and execute Jam rules.

Upon first encountering a Jamfile.lua or using rule LuaFile LUA_FILENAME or rule LuaString LUA_SCRIPT, several Jam-related namespaces become available in Lua accessible via the namespaces jam, jamtarget, and jamvar. Also, described in the section below, a more rich API lets you access most Jam functionality.

To read or write from any variables currently within scope in Jam, use the Lua-provided jamvar table.

# Jam:
GameAssets = assets ;
GameSoundAssets = $(GameAssets)/sound ;
MyVariable = Hello ;
MyListOfStrings = Hello how are you? ;
-- Lua equivalent:
jamvar.GameAssets = "assets"
jamvar.GameSoundAssets = jamvar.GameAssets[1] .. '/sound'
jamvar.MyVariable = "Hello"
jamvar.MyListOfStrings = { 'Hello', 'how', 'are', 'you?' }

The only data type in Jam is a list of strings, so even GameAssets containing a single path is still a list of strings containing only one element. Within Lua, jamvar.GameAssets is a table containing an array of strings with the only element being $(SUBDIR)/assets. Therefore, to access the actual contents of a Jam-provided string list requires indexing into the returned table.

It is also possible to access a Jam target directly.

# Jam:
SEARCH on <GameAssets|source>StringTable.lua = $(COOKED_PATH) ;
local search ;
on <GameAssets|source>StringTable.lua search = $(SEARCH) ;
# or:
local search = $(SEARCH:Z=<GameAssets|source>StringTable.lua) ;
-- Lua:
jamtarget['<GameAssets|source>StringTable.lua'].SEARCH = COOKED_PATH
local search = jamtarget['<GameAssets|source>StringTable.lua'].SEARCH

Evaluating a rule is done with ease within the jam namespace:

# Jam:
local inputTarget = <GameAssets|source>StringTable.lua ;
local inputTarget2 = <GameAssets|source>StringTable.merge.lua ;
local outputTarget = <GameAssets>StringTable.lua ;
Depends assets : $(outputTarget) : $(inputTarget) $(inputTarget2) ;
-- Lua:
local inputTarget = '<GameAssets|source>StringTable.lua'
local inputTarget2 = '<GameAssets|source>StringTable.merge.lua'
local outputTarget = '<GameAssets>StringTable.lua'
jam.Depends('assets', outputTarget, { inputTarget, inputTarget2 })
# Jam:
C.Application helloworld : *.c *.h ;
-- Lua:
jam.C.Application('helloworld', { '*.c', '*.h' })
-- or: jam['C.Application']('helloworld', { '*.c', '*.h' })

Note that single element data types in Lua are automatically converted to a list of strings for Jam. That means that the second parameter to jam.Depends is converted to { outputTarget }.

The jam namespace provides the most useful access to Jam functionality. It does not cover the full range of Jam features. For a more extensive API to access Jam from Lua, see the next section.


Lua to Jam API

Within a Lua script, it is possible to access Jam variables and execute Jam rules.

function jam_action(ACTION_NAME, ACTION_TEXT [, FLAGS])

Creates an action to be executed by Jam called ACTION_NAME made up of ACTION_TEXT. If written in the Jam language, the equivalent would be:

jam_action(ACTION_NAME, ACTION_TEXT)
is equivalent to:
actions ACTION_NAME
{
ACTION_TEXT
}

If FLAGS is specified as a table, those flags are applied to the action and have direct correspondence to action modifiers specified in a Jam action.

jam_action(ACTION_NAME, ACTION_TEXT, { updated = true, together = true })
is equivalent to:
actions updated together ACTION_NAME
{
ACTION_TEXT
}

Parameters
ACTION_NAMEThe name of any valid Jam action.
ACTION_TEXTText representing the commands to be executed by the shell.
FLAGS(optional) If specifed, FLAGS must be a table of action modifiers containing one or more of the following: bind = { 'various', 'target', 'names' }, existing = true,ignore = true, lua = true,maxline = true, maxresponse = true, piecemeal = true, quietly = true, removeemptydirs = true, response = true, screenoutput = true, together = true, updated = true

function jam_evaluaterule(RULE_NAME [, PARAMETERS])

Executes rule RULE_NAME using any optional PARAMETERS specified. Returns the result as a Lua table.

Parameters
RULE_NAMEThe name of any valid Jam rule.
PARAMETERS(optional) If specifed, the PARAMETERS are collapsed into a Jam string list and passed to the rule.
Returns
If the Jam rule doesn't return any values, the return value is nil. If the Jam rule does return values, the return values are transformed to a Lua array of strings.

function jam_expand(TEXT_TO_EXPAND)

Expands TEXT_TO_EXPAND according to Jam rules. TEXT_TO_EXPAND must use the $() or @() expansion forms described elsewhere.

Parameters
TEXT_TO_EXPANDThe text to expand.
Returns
Returns the expanded text.

function jam_getvar([ TARGET_NAME, ] VARIABLE_NAME)

Retrieves VARIABLE_NAME from the active Jam globals and returns it as a table of strings.

If TARGET_NAME is specified, VARIABLE_NAME is retrieved as if an on TARGET_NAME had been issued in Jam.

Parameters
TARGET_NAME(optional) The target to make active to retrieve VARIABLE_NAME from.
VARIABLE_NAMEThe Jam variable to retrieve.
Returns
All strings within the VARIABLE_NAME string are returned as a Lua array of strings.

function jam_parse(TEXT_TO_PARSE)

Parses TEXT_TO_PARSE as if it existed in a Jamfile.

Parameters
TEXT_TO_PARSEJam source code to be parsed and executed by Jam immediately.

function jam_print(TEXT_TO_PRINT)

Prints TEXT_TO_PRINT to the standard output stream.

Parameters
TEXT_TO_PRINTThe text to print.

function jam_setvar([ TARGET_NAME, ] VARIABLE_NAME, VALUE)

Sets VALUE into the active Jam global VARIABLE_NAME. VALUE can be a boolean, number, string, or table. Nested tables are collapsed.

If TARGET_NAME is specified, VALUE is set into VARIABLE_NAME as if an VARIABLE_NAME on TARGET_NAME had been issued in Jam.

Parameters
TARGET_NAME(optional) The target to make active to set VARIABLE_NAME into.
VARIABLE_NAMEThe Jam variable to set.


Examples

# Hello
LuaString "print('Hello')" ;
# 10 hi false
Echo [ LuaString "return { 10, 'hi', false }" ] ;
# 5.suf hello.suf true.suf
var = [ LuaString "return { 5, 'hello', true }" ] ;
Echo $(var:S=.suf) ;
#------------------------------------------------------------------------------
# Hello world!
var = Hello world! ;
Echo [ LuaString "return jam_getvar('var')" ] ;
# Hi everyone
LuaString "jam_setvar('var', 'Hi everyone')" ;
Echo $(var) ;
# Hi everyone
Echo [ LuaString "return jam_getvar('var')" ] ;
#------------------------------------------------------------------------------
# The Variable Contents
MyVariable on mytarget = The Variable Contents ;
Echo [ LuaString "return jam_getvar('mytarget', 'MyVariable')" ] ;
# **hello**
LuaString "jam_setvar('mytarget', 'MyVariable', '**hello**')" ;
Echo [ LuaString "return jam_getvar('mytarget', 'MyVariable')" ] ;
rule ReturnList INPUT
{
return **$(INPUT)** ;
}
# **MyStuff** **YourStuff**
Echo [ LuaString "return jam_evaluaterule('ReturnList', { 'MyStuff', 'YourStuff' })" ] ;