Build/Boilerplate/jsonProcessor.lua
Reece 9f5fa6d8e4 [+] Linkable libraries can now ask for the dependent to compile a script
-> Consider libraries that require some kind of static initialization
  -> Used for AuroraRuntime c++ allocator overloads
[*] Fix copy by abs
2021-07-02 06:27:32 +01:00

452 lines
12 KiB
Lua

local auProject = require("project")
function JsonProcessor(info)
local result, err = json.decode(io.readfile(info.jpath))
if (not result) then
fatal("parse error", info.path, err)
return
end
if (not info.name) then
info.name = result.name
end
local translateDep = function(this, dep)
if (this.info.translations) then
local override = this.info.translations[dep]
if (override) then
dep = override
end
end
return dep
end
local includeDirEx = function(path, incFiles)
includedirs(path)
if (not incFiles) then
return
end
files(path .. "/**.h")
files(path .. "/**.hpp")
files(path .. "/**.inl")
end
local handleUserJsonInclude = function(path, prefix, inc)
includeDirEx(prefix .. "/" .. path, inc)
end
local handleJSONInclude = function(result, val, incFiles)
if (not result.include) then
if (val) then
return
end
includeDirEx (info.path, incFiles)
return
end
forEach(result.include, handleUserJsonInclude, info.path, incFiles)
end
local handleInclude = function(this, incFiles)
local otherREsult = info
local result = this.result
forEach(result.defines, defines)
if (result.type:lower() == "aurora") then
includeDirEx(info.path .. "/Include")
elseif (result.type:lower() == "lazy_free") then
includeDirEx(info.path)
handleJSONInclude(result, false, incFiles)
elseif (result.type:lower() == "root") then
includeDirEx(info.path)
handleJSONInclude(result, result.noRootInclude, incFiles)
elseif (result.type:lower() == "generic") then
handleJSONInclude(result, false, incFiles)
elseif ((result.type:lower() == "utility") or (result.type:lower() == "blank")) then
return
end
end
local handleBuildEvent = function(obj)
local type = ""
if ( obj.lua) then
type = "lua"
elseif (obj.bin) then
type = "bin"
else
return
end
addBuildAction(obj.when, type, obj[type], obj.isCwdProjRoot)
end
local handleDllImportMaybe = function(this)
if (this.info.isShared) then
forEach(this.result.dllimport, defines)
end
end
local handleDllExportMaybe = function(this)
if (this.info.isShared) then
forEach(this.result.dllexport, defines)
end
end
local handleDependsShort = function(dep, this, soft)
dep = translateDep(this, dep)
local proj = _G["projectsprocessor"][dep]
if (not proj) then
if (soft) then
print("Not including, ", dep)
return
end
fatal("Missing project", dep)
end
local iface = proj.processor
if (isProjectLoaded(dep) and not _G["_linkingcur"][dep]) then
iface:handleLink()
end
end
local processJsonBlockForLinks = function(object, this)
forEach(object.links, links)
forEach(object.depends, handleDependsShort, this, false)
forEach(object["soft-depends"], handleDependsShort, this, true)
end
function handleEvalForLinks(object, this)
if (isArray(object)) then
forEach(object, handleEvalForLinks, this)
return
end
if (type(object) == "string") then
return
end
processJsonBlockForLinks(object, this)
end
local handleActionCommon = function(action, cb, ...)
local _if = action["if"]
local _then = action["then"]
_G["info"] = info
local loadstring = loadstring or load
if (_if) then
local val = eval("return " .. _if)
if (not val) then
return
end
if (_then) then
cb(_then, ...)
end
else
if (action.eval) then
cb(action.eval, ...)
end
end
_G["info"] = nil
end
local handleActionsForLinks = function(action, this)
handleActionCommon(action, handleEvalForLinks, this)
end
local processSubLinks = function(this)
processJsonBlockForLinks(result, this)
forEach(result.actions, handleActionsForLinks, this)
end
local handleSourcesRel = function(source, path)
files(path .. "/" .. source)
end
local handleLink = function(this)
dependson (this.info.name)
forEach(result.linkSources, handleSourcesRel, info.path)
local erase = false;
if (not _G["_linkingcur"]) then
erase = true
_G["_linkingcur"] = {}
end
_G["_linkingcur"][this.info.name] = true
local type = this.result.type
if ((type:lower() == "utility") or (type:lower() == "blank")) then
return
end
if ((not this.result.noLink)) then
links(this.info.name)
end
--if (not this.info.isStatic) then
processSubLinks(this)
--end
if (erase) then
_G["_linkingcur"] = nil
end
end
local handleReference = function(this, circular)
local type = this.result.type
if ((type:lower() == "utility") or (type:lower() == "blank")) then
return
end
local cur = nil
if (circular) then
cur = getProjectInfo(getCurrentProjectName())
else
cur = this.info
end
if (cur and cur.isShared) then
-- shared libraries are only allowed to import other shared libraries
handleDllImportMaybe(this)
elseif (cur and cur.isStatic) then
-- static libs are allowed to reference dllexports in translation units of the parent shared module
handleDllExportMaybe(this)
forEach(result.staticImport, defines)
end
if (this.info.isStatic) then
forEach(result.staticImpDefines, defines)
end
handleInclude(this, false)
defines(("_auhas_" .. this.result.name):upper() .. "=1")
end
local handleDependsPreemptive = function(dep, this, soft, resolve)
dep = translateDep(this, dep)
if (not isProjectLoaded(dep)) then
resolve(dep, soft)
end
end
local pokeDeps = function(this, resolve)
local result = this.result
forEach(result.depends, handleDependsPreemptive, this, false, resolve)
forEach(result["soft-depends"], handleDependsPreemptive, this, true, resolve)
end
local handleParse = function(this)
end
local handleProcess = function (a)
local result = a.result
local name = a.info.name
local path = a.info.path
local isUtility = false
if (result.type:lower() == "aurora") then
local srcPath = path .. "/Source"
local incPath = path .. "/Include"
auProject(name, a.info.projectType, {srcPath}, {srcPath, incPath}, a.info.out, path)
elseif (result.type:lower() == "lazy_free") then
auProject(name, a.info.projectType, {path .. "/*.*"}, {path .. "/"}, a.info.out, path)
elseif (result.type:lower() == "root") then
auProject(name, a.info.projectType, path, path, a.info.out, path)
elseif (result.type:lower() == "generic") then
auProject(name, a.info.projectType, nil, nil, a.info.out, path)
elseif (result.type:lower() == "utility") then
project(name)
kind "utility"
isUtility = true
elseif (result.type:lower() == "blank") then
return
else
print "invalid project type"
os.exit()
end
_G["_linkingcur"] = {}
_G["_linkingcur"][name] = true
handleInclude(a, true)
--forEach(result.defines, defines)
--handleJSONInclude(result) -- include auProject public headers, do not use handleInclude, that could reinclude a header included in `project`
-- that could potentially fuck with #include_next
local handleFeature = function(feature)
addFeature(feature)
end
local handleRequire = function(dep)
dep = translateDep(a, dep)
dependson(dep)
end
local handleDepends = function(dep, this, soft)
dep = translateDep(this, dep)
local proj = _G["projectsprocessor"][dep]
if (not proj) then
if (soft) then
print("Not including, ", dep)
return
end
fatal("Missing project", dep)
end
local iface = proj.processor
if (isProjectLoaded(dep)) then
defines(("_auhas_" .. dep):upper() .. "=1")
iface:handleReference(isWeakCircularReference(dep))
if (not this.info.isStatic) then
iface:handleLink()
end
else
defines(("_auhas_" .. dep):upper() .. "=0")
if (not soft) then
fatal("missing project: ", dep)
end
end
end
local handleExcludes = function(excludes, path)
removefiles(excludes)
end
local handleSources = function(source, path)
--files(path .. "/" .. source)
files(source)
end
local handleSourcePaths = function(source, path)
files
{
path .. "/" .. source .. "/**.*pp",
path .. "/" .. source .. "/**.inl",
path .. "/" .. source .. "/**.c",
path .. "/" .. source .. "/**.cc",
path .. "/" .. source .. "/**.h",
path .. "/" .. source .. "/**.masm"
}
end
local processJsonBlock = function(object)
forEach(object.features, handleFeature, info.path)
forEach(object.sourcePaths, handleSourcePaths, info.path)
forEach(object.excludes, handleExcludes, info.path)
forEach(object.sources, handleSources, info.path)
forEach(object.depends, handleDepends, a, false)
forEach(object["soft-depends"], handleDepends, a, true)
forEach(object.impDefines, defines)
forEach(object.links, links)
if (usingMSVC) then
forEach(object.msvcIgnore, disablewarnings)
end
if (usingClang) then
forEach(object.clangIgnore, disablewarnings)
end
end
function handleEval(object)
if (isArray(object)) then
forEach(object, handleEval)
return
end
if (type(object) == "string") then
eval(object)
return
end
processJsonBlock(object)
end
local handleAction = function(action)
handleActionCommon(action, handleEval)
end
forEach(result.require, handleRequire)
if (not isUtility) then
processJsonBlock(result)
forEach(result.impInclude, handleUserJsonInclude, info.path, true)
if (a.info.projectType:lower() == "sharedlib") then
forEach(result.dllexport, defines)
end
end
forEach(result.actions, handleAction, info.path)
forEach(result.events, handleBuildEvent, info.path)
if (info.isStatic) then
forEach(result.staticImpDefines, defines)
end
_G["_linkingcur"] = nil
end
forEach(result.subprojs, function(subproj)
local subinfo = {
namespace = info.namespace,
path = info.path .. "/" .. subproj.path,
projectType = subproj.projectType,
out = info.out,
name = nil,
translations = info.translations
}
addVist(subinfo)
end)
local interface = {}
interface.result = result
interface.info = info
interface.resolveDependencies = pokeDeps
interface.process = handleProcess
interface.handleLink = handleLink
interface.handleReference = handleReference
return interface
end
return JsonProcessor