115 lines
5.1 KiB
Lua
115 lines
5.1 KiB
Lua
local lib = {}
|
|
-- TODO: Specify what should happen if srcobj_mapping_fn returns nil for an object or source file
|
|
|
|
function lib.get_object_files(obj_dirs, obj_postfixes)
|
|
local objs = {}
|
|
if type(obj_dirs) == "string" then obj_dirs = {obj_dirs} end
|
|
for _,dir in ipairs(obj_dirs) do
|
|
for fsobj in fs.forall(dir) do
|
|
if not fs.is_dir(fsobj) and obj_postfixes[fs.extension(fsobj)] then
|
|
objs[#objs+1] = fsobj
|
|
end
|
|
end
|
|
end
|
|
return objs
|
|
end
|
|
|
|
--- Generates a list of source files that are newer than their corresponding object and returns it
|
|
---@param dirs string[] An array of source directories to scan
|
|
---@param src_postfixes {[string]: boolean} A map of source file extensions to a boolean value
|
|
---@param srcobj_mapping_fn fun(src_file: string | nil, obj_file: string | nil): string Called with (src_file, nil), should return object file path or nil. nil assumes source is newer, otherwise it is checked
|
|
---@return string[] An array of source files that are newer than their corresponding object file, according to srcobj_mapping_fn
|
|
function lib.get_newer_src_files(dirs, src_postfixes, srcobj_mapping_fn)
|
|
local srcs = {}
|
|
if type(dirs) == "string" then dirs = {dirs} end
|
|
for _,dir in ipairs(dirs) do
|
|
for fsobj in fs.forall(dir) do
|
|
local src_file = fsobj
|
|
if not fs.is_dir(fsobj) then repeat
|
|
if not src_postfixes[fs.extension(src_file)] then break end
|
|
-- Only bother checking if the source is newer than its corresponding obj file if it has a mapping,
|
|
-- Otherwise queue it to be potentially recompiled
|
|
local obj = srcobj_mapping_fn(src_file, nil)
|
|
if obj ~= nil then
|
|
if not fs.is_newer(src_file, obj) then break end
|
|
end
|
|
srcs[#srcs+1] = src_file
|
|
until true end
|
|
end
|
|
end
|
|
return srcs
|
|
end
|
|
|
|
--- Given a list of source files and a bi-directional src-obj mapping function, will return a list of translation units
|
|
---@param src_list string[] A list of source files to be included
|
|
---@param srcobj_mapping_fn fun(src_file: string | nil, obj_file: string | nil): string A bi-directional mapping function that will return the object a source is related to or the sources that are related to an object
|
|
---@return {obj: string, src: string[]}[] Returns a list of translation units, describing the source files that go into generating a particular object file
|
|
function lib.generate_translation_units(src_list, srcobj_mapping_fn)
|
|
local srcs_handled = {}
|
|
local units = {}
|
|
for _, src_file in ipairs(src_list) do repeat
|
|
if (srcs_handled[src_file]) then break end
|
|
local obj = srcobj_mapping_fn(src_file, nil)
|
|
units[#units+1] = {}
|
|
units[#units].obj = obj
|
|
units[#units].src = srcobj_mapping_fn(nil, obj)
|
|
for _,src in ipairs(units[#units].src) do
|
|
srcs_handled[src] = true
|
|
end
|
|
until true end
|
|
return units
|
|
end
|
|
|
|
|
|
--- Compiles a list of translation units using cmd, appending any additional arguments to all commands
|
|
--- This compilation occurs in parallel with up to num_parallel simultanious processes
|
|
---@param cmd string The command to use in order to compile a translation unit
|
|
---@param num_parallel integer Maximum number of processes that may exist at one time
|
|
---@param translation_units {obj: string, src: string[]}[] An array of translation units, each containing a list of one or more source files and an output file
|
|
---@param ... string additional arguments to add to all invocation of the compiler
|
|
---@return integer[] return codes from all processes dispatched
|
|
---@return string[] stdout output from all processes dispatched
|
|
---@return string[] stderr output from all processes dispatched
|
|
function lib.compile_translation_units(cmd, num_parallel, translation_units, ...)
|
|
local argv = {}
|
|
local mirror_args = table.concat({...}, " ")
|
|
for _,unit in ipairs(translation_units) do
|
|
fs.create_dir(fs.dir(unit.obj))
|
|
argv[#argv+1] = {table.concat({mirror_args, unpack(unit.src), "-o", unit.obj}, ' ')}
|
|
print(cmd .. " " .. table.concat(argv[#argv], ' '))
|
|
end
|
|
return platform.exec_parallel(cmd, num_parallel, argv)
|
|
end
|
|
|
|
--- Runs a single invocation of cmd with the obj component of every translation unit appended
|
|
---@param cmd string The command to be executed
|
|
---@param obj_postfixes {[string]: boolean | nil} a list of postfixes to look for in the object directories
|
|
---@param output string the filename and path for the output file
|
|
---@param ... string additional arguments provided to the command
|
|
function lib.link_translation_units(cmd, obj_dirs, obj_postfixes, output, ...)
|
|
local inputs = {...}
|
|
local obj_files = lib.get_object_files(obj_dirs, obj_postfixes)
|
|
inputs[#inputs+1] = output
|
|
inputs[#inputs+1] = table.concat(obj_files, ' ')
|
|
print("Executing " .. cmd .. ' ' .. table.concat(inputs, ' '))
|
|
return platform.exec(cmd, inputs)
|
|
end
|
|
|
|
function lib.print_errors(err, stdout, stderr)
|
|
if type(err) == "number" then err = {err} end
|
|
if type(stdout) == "string" then stdout = {stdout} end
|
|
if type(stderr) == "string" then stderr = {stderr} end
|
|
for i,ec in ipairs(err) do
|
|
if (ec ~= 0) then
|
|
print("Invocation ".. tostring(i) .. " failed with exit code " .. tostring(ec) .. " and output;")
|
|
print()
|
|
print(stderr[i])
|
|
print()
|
|
print(stdout[i])
|
|
print()
|
|
end
|
|
end
|
|
end
|
|
|
|
return lib
|