[+] JSON -> noLink

[*] Most actions can now be json objects. Evaluating lua should be the last thing we want to do from a json file
[+] Added isArray
[*] Update language to C++20 across all modules
[*] Various improvements
[*] Various bug fixes
This commit is contained in:
Reece Wilson 2021-06-03 14:00:02 +01:00
parent 37596a7738
commit 630939c6ac
11 changed files with 328 additions and 157 deletions

View File

@ -4,7 +4,7 @@ function JsonProcessor(info)
local result, err = json.decode(io.readfile(info.jpath))
if (not result) then
print("parse error", info.path, err)
fatal("parse error", info.path, err)
return
end
@ -12,47 +12,53 @@ function JsonProcessor(info)
info.name = result.name
end
local handleUserJsonInclude = function(path)
includedirs(info.path .. "/" .. path)
end
local includeDirEx = function(path, incFiles)
includedirs(path)
local handleJSONInclude = function(result)
if (not result.include) then
includedirs (info.path)
if (not incFiles) then
return
end
forEach(result.include, handleUserJsonInclude)
files(path .. "/**.h")
files(path .. "/**.hpp")
files(path .. "/**.inl")
end
local tryAddDefine = function(aaa)
if (aaa) then
defines(aaa)
end
local handleUserJsonInclude = function(path, prefix, inc)
includeDirEx(prefix .. "/" .. path, inc)
end
local handleInclude = function(this)
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
includedirs (info.path .. "/Include")
includeDirEx(info.path .. "/Include")
elseif (result.type:lower() == "lazy_free") then
handleJSONInclude(result)
includeDirEx(info.path)
handleJSONInclude(result, false, incFiles)
elseif (result.type:lower() == "root") then
includedirs (info.path)
handleJSONInclude(result)
elseif (result.type:lower() == "pair") then
includedirs (info.srcInclude)
handleJSONInclude(result)
includeDirEx(info.path)
handleJSONInclude(result, result.noRootInclude, incFiles)
elseif (result.type:lower() == "generic") then
handleJSONInclude(result)
elseif (result.type:lower() == "empty") then
handleJSONInclude(result)
handleJSONInclude(result, false, incFiles)
elseif ((result.type:lower() == "utility") or (result.type:lower() == "blank")) then
return
end
tryAddDefine(result.defines)
end
local handleBuildEvent = function(obj)
@ -82,12 +88,15 @@ function JsonProcessor(info)
local handleLink = function(this)
dependson(this.info.name)
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
handleDllImportMaybe(this)
end
@ -107,7 +116,29 @@ function JsonProcessor(info)
handleDllExportMaybe(this)
end
handleInclude(this)
this:handleInclude()
defines(("_auhas_" .. this.result.name):upper() .. "=1")
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 handleDependsPreemptive = function(dep, this, soft)
dep = translateDep(this, dep)
if (not isProjectLoaded(dep)) then
processProject(dep, not soft)
end
end
local handleProcess = function (a)
@ -117,6 +148,11 @@ function JsonProcessor(info)
local isUtility = false
forEach(result.depends, handleDependsPreemptive, a, false)
forEach(result["soft-depends"], handleDependsPreemptive, a, true)
attemptNS(a.info.namespace)
if (result.type:lower() == "aurora") then
local srcPath = path .. "/Source"
local incPath = path .. "/Include"
@ -127,17 +163,9 @@ function JsonProcessor(info)
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() == "pair") then
auProject(name, a.info.projectType, {path .. "/" .. result.srcSource}, {path .. "/" .. result.srcInclude}, a.info.out, path)
auProject(name, a.info.projectType, path, path, a.info.out, path)
elseif (result.type:lower() == "generic") then
print("type 'generic' is deprecated, use 'empty' instead")
print("'generic' will soon be replaced by the behaviour of 'aurora'")
auProject(name, a.info.projectType, nil, nil, a.info.out, path)
elseif (result.type:lower() == "empty") then
auProject(name, a.info.projectType, nil, nil, a.info.out, path)
elseif (result.type:lower() == "utility") then
@ -153,34 +181,33 @@ function JsonProcessor(info)
os.exit()
end
handleJSONInclude(result) -- include auProject public headers, do not use handleInclude, that could reinclude a header included in `project`
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 translateDep = function(dep)
if (a.info.translations) then
local override = a.info.translations[dep]
if (override) then
dep = override
end
end
return dep
end
local handleRequire = function(dep)
dep = translateDep(dep)
dep = translateDep(a, dep)
dependson(dep)
end
local handleDepends = function (dep, soft)
dep = translateDep(dep)
local handleDepends = function(dep, soft)
dep = translateDep(a, dep)
local iface = _G["projectsprocessor"][dep]
local proj = _G["projectsprocessor"][dep]
if (not proj) then
if (soft) then
print("Not including, ", dep)
return
end
fatal("Missing project", dep)
end
if (isWeakCircularReference(dep)) then
print("handling circular reference", dep)
@ -188,9 +215,7 @@ function JsonProcessor(info)
return
end
if (not isProjectLoaded(dep)) then
processSubproject(dep)
end
local iface = _G["projectsprocessor"][dep].processor
if (isProjectLoaded(dep)) then
defines(("_auhas_" .. dep):upper() .. "=1")
@ -199,68 +224,92 @@ function JsonProcessor(info)
else
defines(("_auhas_" .. dep):upper() .. "=0")
if (not soft) then
print("missing project: ", dep)
os.exit()
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)
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)
local _if = action["if"]
local _then = action["then"]
_G["info"] = info
if (_if) then
print("DEBUG: IF?? ", _if)
local loadstring = loadstring or load
local eval = loadstring("return " .. _if)
if (not eval) then
if (_if) then
local val = eval("return " .. _if)
if (not val) then
return
end
if (_then) then
print("DEBUG: EVAL ", _then)
forEach(_then, loadstring)
handleEval(_then)
end
else
if (action.eval) then
print("DEBUG: EVAL ", action.eval)
forEach(action.eval, loadstring)
handleEval(action.eval)
end
end
_G["info"] = nil
end
local handleExcludes = function(excludes, path)
removefiles(path .. "/" .. excludes)
end
local handleSoftDepends = function(dep)
handleDepends(dep, true)
end
local handleSources = function(source, path)
files(path .. "/" .. source)
end
forEach(result.require, handleRequire)
if (not isUtility) then
forEach(result.features, handleFeature, info.path)
forEach(result.excludes, handleExcludes, info.path)
forEach(result.sources, handleSources, info.path)
forEach(result.depends, handleDepends, info.path)
forEach(result["soft-depends"], handleSoftDepends)
processJsonBlock(result)
forEach(result.impInclude, handleUserJsonInclude, info.path, true)
if (a.info.projectType:lower() == "sharedlib") then
tryAddDefine(result.dllexport)
end
tryAddDefine(result.impdefines)
defines(result.defines)
end
forEach(result.actions, handleAction, info.path)

View File

@ -58,7 +58,6 @@ local tbl =
"target-linux",
"target-switch",
"target-ps5",
"target-ps5",
"target-x86_64",
"target-arm",
"target-wayland"

View File

@ -60,8 +60,18 @@ local boilerplateProject = function(name, projectType, src, inc, dest, root)
targetname(name)
language("C++") -- C and MASM compiler overloads are still available to files requiring different compilers
cppdialect("C++20")
if (usingMSVC) then
filter {"files:**.cpp or files:**.cc"}
buildoptions {"/experimental:module-", "/Zc:__cplusplus"}
filter {}
end
kind(projectType)
buildoptions {"-utf-8"}
targetprefix ""
if (not _G.win32) then
if ((projectType == "SharedLib") or
(projectType == "StaticLib")) then
@ -78,10 +88,6 @@ local boilerplateProject = function(name, projectType, src, inc, dest, root)
if (root and (root ~= "MAGIC")) then
location(root)
else
if (_G["use-workspace-root"]) then
location("../Build_CompilerWorkingDirectory")
end
end
-- V8 takes minutes to start up on an i9-9900k, QST/VM tests result in highs of ~30MB/s from 900MB/s

View File

@ -71,11 +71,7 @@ workspace "Aurora Project"
buildoptions {"-fms-extensions"}
filter {"files:**.cpp"} -- TODO: `.. " or files:**.cc"` should be possible
buildoptions {"-stdlib=libc++"}
filter {}
filter {"files:**.cc"}
filter {"files:**.cpp or files:**.cc"}
buildoptions {"-stdlib=libc++"}
filter {}
@ -90,29 +86,30 @@ workspace "Aurora Project"
elseif (isWin) then
usingMSVC = true
disablewarnings "4996" -- The whiny C99 is no longer supported nag, please needlessly use _s and _'d functions
disablewarnings
{
"4996", -- The whiny C99 is no longer supported nag
-- please needlessly use '_s' and '_'d functions __error__
-- fuck off
disablewarnings "4251" -- MSVC's hurrdurr abis will break if you dynamically link classes
-- counter: fuck off, we have full control of the build process, and we only link against
"4251", -- MSVC's hurrdurr abis will break if you dynamically link classes
-- counter: fuck off again. we have full control of the build process, and we only link against
-- dynamic c/stl runtimes. which brainlet thought this was a good idea?
-- even microsofts docs doesn't state what is guaranteed to be safe. rtti works so who cares
-- even microsofts docs dont state what is guaranteed to be safe.
-- dont mix optimizations, cookie/security flags, and so on. rtti works so who cares
disablewarnings "4244" -- conversion from 'double' to 'float', possible loss of data
"4244", -- conversion from 'double' to 'float', possible loss of data
-- this warning is extremely important; however, we're making a game engine.
-- pragma warning push, disable and/or static_casts to hint we expect floating point precision
-- pragma warning push + disable + pop and/or static_casts to hint we expect floating point precision
-- loss is extremely annoying and impractical. further, projects including harfbuzz, freetype,
-- and v8 don't seem to care about these warnings either
-- and v8 don't seem to care about this warning either
"4267" -- TODO: remove. its not that we dont want this warning - we see spam where clang doesnt care, annoying
}
end
if (_G.linux and usingClang) then
linkoptions {"-nodefaultlibs"}
links "c++abi"
links "c++"
links "c"
links "gcc"
links "gcc_s"
links "m"
end
if (isWin) then

View File

@ -7,24 +7,49 @@
"type":
{
"type": "string",
"enum": ["pair", "empty", "root", "lazy_free", "utility", "blank"],
"enum": ["aurora", "generic", "root", "lazy_free", "utility", "blank"],
"description": "https://pastebin.com/ThE2t9EJ"
},
"srcSource":
"sources":
{
"type": "string",
"description": "use with type == pair"
"type": ["array", "string"],
"items":
{
"type": "string"
},
"srcInclude":
"description": "add most files matching regex('${path}'). .masm, .inl, and others may not match unless specifically requested because premake do be premake. "
},
"sourcePaths":
{
"type": "string",
"description": "use with type == pair"
"type": ["array", "string"],
"items":
{
"type": "string"
},
"description": "add files projectDir/${path}/**.[common exts and some]"
},
"excludes":
{
"type": ["array", "string"],
"items":
{
"type": "string"
},
"description": "removes files matching regex('${exclude}') "
},
"include":
{
"type": ["array", "string"],
"description": "path + suffix/include, is added to the includedirs after internal source includes. included by public and internal (obviously) translation units. (when internal available, internal -> include_next -> public) "
"description": "include directory. accessible from all translation units. inc order: internal -> include_next -> public "
},
"noLink":
{
"type": "boolean",
"description": "indicates the current project is a header only library and therefore one does not link against a compiled module"
},
"dllexport":
{
"type": ["array", "string"],
@ -43,7 +68,9 @@
},
"description": "adds a preprocessor definition to translation units linking against a shared project"
},
"impdefines":
"impDefines":
{
"type": ["array", "string"],
"items":
@ -52,6 +79,13 @@
},
"description": "adds a preprocessor definition to translation units compiling the project"
},
"impInclude":
{
"type": ["array", "string"],
"description": "appends a relative path to the include paths"
},
"defines":
{
"type": ["array", "string"],
@ -59,8 +93,10 @@
{
"type": "string"
},
"description": "adds preprocessor definition, supports '=value' "
"description": "adds preprocessor definition. supports '=value'. availablity extends to dependents"
},
"require":
{
"type": ["array", "string"],
@ -68,8 +104,10 @@
{
"type": "string"
},
"description": "depend on another project. this can be used to fence build stages and integrate other native build+execaction ahead of module compilation time"
"description": "depend on another project. this can be used to fence build stages and integrate other native build+execute utils ahead of project compilation time"
},
"soft-depends":
{
"type": ["array", "string"],
@ -84,17 +122,11 @@
"items":
{
"type": "string"
}
},
"excludes":
{
"type": ["array", "string"],
"items":
{
"type": "string"
},
"description": "removes files matching regex('projectDir/${exclude}') "
"description": "link against another library"
},
"features":
{
"type": ["array", "string"],
@ -105,6 +137,8 @@
},
"description": "remove-platform-code -> excludes paths which appear to be tied to common hardware and software architectures (win32,mac,xnu,nt,intel,amiga,x86_64,mips,arm,powerpc,riscv,etc)"
},
"actions":
{
"type": "array",
@ -114,12 +148,14 @@
"properties":
{
"if": {"type": "string"},
"then": {"type": "string"},
"then": {"type": ["string", "object", "array"] },
"eval": {"type": "string"}
"eval": {"type": ["string", "object", "array"]}
}
}
},
"isCwdProjRoot":
{
"type": "boolean"

3
Utils/eval.lua Normal file
View File

@ -0,0 +1,3 @@
function eval(src)
return (loadstring or load)(src)()
end

4
Utils/fatal.lua Normal file
View File

@ -0,0 +1,4 @@
function fatal(...)
print(...)
os.exit(1)
end

View File

@ -7,6 +7,6 @@ function forEach(xd, cb, ...)
cb(v, ...)
end
else
cb(xd)
cb(xd, ...)
end
end

23
Utils/isArray.lua Normal file
View File

@ -0,0 +1,23 @@
-- lua-cjson's is_array by Mark Pulford
function isArray(table)
local max = 0
local count = 0
if (type(object) ~= "table") then
return false
end
for k, v in pairs(table) do
if type(k) == "number" then
if k > max then max = k end
count = count + 1
else
return false
end
end
if max > count * 2 then
return false
end
return max > 0
end

View File

@ -3,3 +3,6 @@ require("forEach")
require("strings")
require("userRequire")
require("lookupCmdArgs")
require("fatal")
require("eval")
require("isArray")

View File

@ -154,38 +154,87 @@ end
-- private
local processLocalProject = function(proj)
processSubproject(proj.info.name);
processProject(proj.info.name)
end
function processProject()
forEach(projectsprocessor, processLocalProject)
end
local processNS = function(namespace)
local projs = {}
local projsIdxs = {}
function processSubproject(name)
if (projectsblocked[name]) then
forEach(projectsprocessor, function(proj)
if (proj.info.namespace ~= namespace) then
return
end
local name = proj.info.name
projs[name] = proj
table.insert(projsIdxs, name)
end)
table.sort(projsIdxs, function(a, b)
return a:upper() < b:upper()
end)
forEach(projsIdxs, function(idx)
processLocalProject(projs[idx])
end)
end
function processSolution()
local hack = {}
local hackIdx = {}
forEach(projectsprocessor, function(proj)
table.insert(hackIdx, proj.info.namespace)
end)
table.sort(hackIdx, function(a, b)
return a:upper() < b:upper()
end)
forEach(hackIdx, processNS)
end
function attemptNS(ns)
local attemptLoad = false
if (not namespacesemitted[ns]) then
namespacesemitted[ns] = "";
dbgGroup(ns) -- only print the group once
attemptLoad = true
end
-- this seems to be singleshot.
-- once you switch namespaces, theres no going back, it seems.
-- we try to preserve namespace-project contiguity as much as possible through sorting and evil recursion
namespace(ns)
if (attemptLoad) then
processNS(ns)
end
end
function processProject(name, required)
if (projectsblocked[name]) then
return true
end
projectsblocked[name] = name
local a = projectsprocessor[name]
if (not a) then
print("missing project: ", name)
return
if (required) then
fatal("missing project: ", name)
else
return false
end
local info = a.info
local ns = info.namespace
if (not namespacesemitted[ns]) then
namespacesemitted[ns] = "";
dbgGroup(ns)
end
local cwd = os.getcwd()
local old = _G["current_project"]
_G["current_project"] = name
os.chdir(info.path)
os.chdir(a.info.path)
a.processor:process(a.processor)
@ -193,6 +242,8 @@ function processSubproject(name)
_G["current_project"] = old
projectsemitted[name] = name
return true
end
function isWeakCircularReference(name)