Last active
September 12, 2022 09:56
-
-
Save RealNeGate/5ce727efd9077c6335bb4457afd1c4bf to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local bit = require("bit") | |
| local ffi = require("ffi") | |
| function get_file_name(file) | |
| local s = file:match("^.+/(.+)$") | |
| if s == nil then | |
| return file | |
| end | |
| return s | |
| end | |
| function cc_cmd(input, cflags) | |
| local output = get_file_name(input) | |
| local cmd = "clang "..input.." "..cflags.." -c -o bin/"..output..".o 2>&1" | |
| return io.popen(cmd) | |
| end | |
| function ccdeps_cmd(input, cflags) | |
| local output = get_file_name(input) | |
| local cmd = "clang -MMD -MF bin/"..output..".d "..input.." "..cflags.." -E > NUL" | |
| return os.execute(cmd) | |
| end | |
| function get_filetime(input) | |
| if ffi.os == "Windows" then | |
| local f = io.popen("forfiles /m build.lua /c \"cmd /c echo @ftime @fdate\"") | |
| local str = f:read("*a"); | |
| f:close() | |
| -- trim whitespace | |
| str = str:match"^%s*(.*)":match"(.-)%s*$" | |
| return str | |
| else | |
| return "0" | |
| end | |
| end | |
| local crc_table = ffi.new("uint32_t[256]", { | |
| 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, | |
| 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, | |
| 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, | |
| 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, | |
| 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, | |
| 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, | |
| 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, | |
| 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, | |
| 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, | |
| 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, | |
| 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, | |
| 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, | |
| 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, | |
| 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, | |
| 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, | |
| 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, | |
| 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, | |
| 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, | |
| 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, | |
| 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, | |
| 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, | |
| 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, | |
| 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, | |
| 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, | |
| 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, | |
| 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, | |
| 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, | |
| 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, | |
| 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, | |
| 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, | |
| 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, | |
| 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d | |
| }) | |
| function hash_file(path) | |
| local f = io.open(path, "rb") | |
| if f == nil then | |
| print("Could not load file: "..path) | |
| return 0 | |
| end | |
| local str = f:read("*a") | |
| f:close() | |
| -- fnv1a | |
| local hash = 0xFFFFFFFF | |
| for i=1,#str do | |
| local c = string.byte(str, i) | |
| local d = bit.band(bit.bxor(hash, c), 0xFF) | |
| hash = bit.bxor(crc_table[d], bit.rshift(hash, 8)) | |
| end | |
| return tonumber(ffi.cast("uint32_t", hash)) | |
| end | |
| function do_match_deps(a, b) | |
| for k,v in pairs(a) do | |
| if v ~= b[k] then | |
| print("Difference! "..v.. " | "..b[k]) | |
| return false | |
| end | |
| end | |
| return true | |
| end | |
| function dump(o) | |
| if type(o) == 'table' then | |
| local s = '{ ' | |
| for k,v in pairs(o) do | |
| if type(k) ~= 'number' then k = '"'..k..'"' end | |
| s = s .. '['..k..'] = ' .. dump(v) .. ',' | |
| end | |
| return s .. '} ' | |
| else | |
| return tostring(o) | |
| end | |
| end | |
| function add_to_database(old_database, new_database, input, deps) | |
| local l = new_database[input] | |
| if (l ~= nil) then | |
| return new_database[input].changed | |
| end | |
| local t = get_filetime(input) | |
| -- check for changes (if it was around before) | |
| local changed = false | |
| local old = old_database[input] | |
| -- default to using the old hash unless the file times change | |
| local hash = 0 | |
| if old ~= nil then | |
| -- avoid file hashing by using the filetimes | |
| if old.last_write ~= t then | |
| -- hash the new file | |
| hash = hash_file(input) | |
| if hash ~= old.hash or not do_match_deps(old.deps, deps) then | |
| print(" Changed! "..input.." "..string.format("%x", hash).." | "..string.format("%x", old.hash)) | |
| changed = true | |
| end | |
| else | |
| hash = old.hash | |
| end | |
| else | |
| print("New file who dis? "..input) | |
| hash = hash_file(input) | |
| changed = true | |
| end | |
| new_database[input] = { ["hash"] = hash, ["last_write"] = t, ["deps"] = deps, ["changed"] = changed } | |
| return changed | |
| end | |
| function read_database(database) | |
| local f = io.open("build.cache", "r") | |
| if f == nil then | |
| print("No cache... first time?") | |
| return | |
| end | |
| for line in f:lines() do | |
| -- filename then a colon, the hash in hex then a list of input files separated by spaces | |
| last_write, path, hash_str, inputs = line:match("([^|]+)|([^:]+):%s(0x%x+)(.*)") | |
| hash = tonumber(hash_str) | |
| deps = {} | |
| for s in inputs:gmatch("%S+") do | |
| table.insert(deps, s) | |
| end | |
| -- print("Conversion: "..hash_str.." -> "..string.format("%08x", hash)) | |
| database[path] = { ["hash"] = hash, ["last_write"] = t, ["deps"] = deps, ["changed"] = false } | |
| end | |
| f:close() | |
| end | |
| function update_deps(old_database, new_database, input) | |
| local dep_path = "bin/"..get_file_name(input)..".d" | |
| local f = io.open(dep_path, "rb") | |
| if (f == nil) then | |
| print("build warning: could not build dependency file for "..input) | |
| return true | |
| end | |
| local str = f:read("*a") | |
| out, ins = str:match("([^:]+):([^:]+)") | |
| -- remove the backslash-newlines | |
| ins = ins:gsub("\\\r\n", "") | |
| -- simplify the slashes | |
| ins = ins:gsub("\\", "/") | |
| -- we keep track of it just for the sake | |
| changes = false | |
| deps = {} | |
| for s in string.gmatch(ins, "%S+") do | |
| table.insert(deps, s) | |
| if (s ~= input) then | |
| -- print(input.." uses "..s) | |
| if add_to_database(old_database, new_database, s, {}) then | |
| changes = true | |
| end | |
| end | |
| end | |
| if add_to_database(old_database, new_database, input, deps) then | |
| changes = true | |
| end | |
| f:close() | |
| return changes | |
| end | |
| function ends_with(str, ending) | |
| return ending == "" or str:sub(-#ending) == ending | |
| end | |
| function expand_paths(files) | |
| new_files = {} | |
| for i,f in ipairs(files) do | |
| if ends_with(f, "/") then | |
| -- read files in directory | |
| if ffi.os == "Windows" then | |
| local command = io.popen("dir /B "..f:gsub("/", "\\")) | |
| for l in command:lines() do | |
| if ends_with(l, ".c") then | |
| local path = string.gsub(f..l, "\\", "/") | |
| table.insert(new_files, path) | |
| end | |
| end | |
| command:close() | |
| else | |
| local command = io.popen("grep -L "..f.."*") | |
| for l in command:lines() do | |
| if ends_with(l, ".c") then | |
| table.insert(new_files, l) | |
| end | |
| end | |
| command:close() | |
| end | |
| else | |
| table.insert(new_files, f) | |
| end | |
| end | |
| return new_files | |
| end | |
| function compile(files, cflags) | |
| -- fixup any directory queries | |
| files = expand_paths(files) | |
| io.stdout:setvbuf("no") | |
| print("Step 1: Read cache") | |
| old_database = {} | |
| read_database(old_database) | |
| -- prepass C files for the dependencies & update deps file | |
| print("Step 2: Get dependencies") | |
| new_database = {} | |
| changed_files = {} | |
| for i,f in ipairs(files) do | |
| local exit_code = ccdeps_cmd(f, cflags) | |
| if exit_code == 0 and update_deps(old_database, new_database, f) then | |
| -- we changed the file so we need to recompile it | |
| table.insert(changed_files, f) | |
| end | |
| end | |
| -- compile C files | |
| print("Step 3: Compile files") | |
| local handles = {} | |
| for i,f in ipairs(changed_files) do | |
| handles[i] = cc_cmd(f, cflags) | |
| end | |
| local has_errors = false | |
| for key,handle in pairs(handles) do | |
| local str = handle:read("*a") | |
| print("~~ "..changed_files[key].." ~~") | |
| if str:len() ~= 0 then | |
| print(str) | |
| new_database[changed_files[key]] = nil | |
| has_errors = true | |
| end | |
| -- if the compile fails then remove from the database | |
| handle:close() | |
| end | |
| -- write new database | |
| print("Step 4: Update database") | |
| database_file = io.open("build.cache", "wb") | |
| for input,entry in pairs(new_database) do | |
| local hash_str = string.format("%08x", entry.hash) | |
| database_file:write(entry.last_write.."|"..input..": 0x"..hash_str.." ") | |
| for k,v in ipairs(entry.deps) do | |
| database_file:write(v.." ") | |
| end | |
| database_file:write("\n") | |
| end | |
| database_file:close() | |
| -- link together | |
| if not has_errors then | |
| if next(changed_files) ~= nil then | |
| return true | |
| else | |
| print("No changes, doesn't need to link") | |
| end | |
| end | |
| return false | |
| end | |
| function link(output) | |
| os.execute("clang bin/*.o -g -o bin/"..output) | |
| end | |
| function lib(output, deps) | |
| if ffi.os == "Windows" then | |
| os.execute("lib /nologo /out:"..output.." bin/*.o "..deps) | |
| else | |
| os.execute("ar -rcs "..output.." bin/*.o "..deps) | |
| end | |
| end | |
| -- your based build system stuff goes here | |
| files = { | |
| "src/tb/", | |
| "src/tb/codegen/", | |
| "src/tb/bigint/", | |
| "src/tb/objects/", | |
| "src/tb/debug/", | |
| "src/tb/debug/cv/", | |
| "src/tb/x64/", | |
| "src/tb/aarch64/", | |
| "src/tb/opt/", | |
| } | |
| if ffi.os == "Windows" then | |
| table.insert(files, "src/tb/system/win32.c") | |
| else | |
| table.insert(files, "src/tb/system/posix.c") | |
| end | |
| local options = "-g -Wall -Werror -Wno-unused-function " | |
| options = options.."-I include " | |
| options = options.."-I deps/mimalloc/include " | |
| options = options.."-I deps/luajit/src " | |
| if compile(files, options) then | |
| print("Step 5: Link") | |
| lib("tildebackend.lib", "deps/mimalloc-static.lib deps/luajit/src/lua51.lib") | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment