Customized fork of github.com/rxi/lite

Replaced `build.py/build.config.py` with `build.sh`

rxi dfcbc48a 18b7d70a

+1 -1
README.md
··· 23 23 [user module](data/user/init.lua). 24 24 25 25 ## Building 26 - You can build the project yourself on Linux using the provided `build.py` 26 + You can build the project yourself on Linux using the provided `build.sh` 27 27 script. Note that the project does not need to be rebuilt if you are only making 28 28 changes to the Lua portion of the code. 29 29
-29
build.config.py
··· 1 - import os 2 - 3 - cflags = [ "-Wall", "-O3", "-g", "-DLUA_USE_POPEN" ] 4 - lflags = [ "-lSDL2", "-lm" ] 5 - include = [ "src" ] 6 - output = "lite" 7 - 8 - 9 - if "sanitize" in opt: 10 - log("address sanitizer enabled") 11 - cflags += [ "-fsanitize=address" ] 12 - lflags += [ "-fsanitize=address" ] 13 - 14 - 15 - if "windows" in opt: 16 - compiler = "x86_64-w64-mingw32-gcc" 17 - output += ".exe" 18 - cflags += [ "-Iwinlib/SDL2-2.0.10/x86_64-w64-mingw32/include" ] 19 - lflags += [ "-Lwinlib/SDL2-2.0.10/x86_64-w64-mingw32/lib" ] 20 - lflags = [ "-lmingw32", "-lSDL2main" ] + lflags 21 - lflags += [ "-lwinmm" ] 22 - lflags += [ "-mwindows" ] 23 - lflags += [ "res.res" ] 24 - 25 - def pre(): 26 - os.system("x86_64-w64-mingw32-windres res.rc -O coff -o res.res") 27 - 28 - def post(): 29 - os.remove("res.res")
-307
build.py
··· 1 - #!/usr/bin/python2.7 2 - import os, sys, platform, shutil 3 - import re, threading, time, json 4 - from os import path 5 - from hashlib import sha1 6 - from multiprocessing import cpu_count 7 - 8 - 9 - config_file = "build.config.py" 10 - cache_dir = ".buildcache" 11 - object_dir = path.join(cache_dir, "obj") 12 - cache_file = path.join(cache_dir, "cache.json") 13 - max_workers = cpu_count() 14 - 15 - 16 - config = { 17 - "compiler" : "gcc", 18 - "output" : "a.out", 19 - "source" : [ "src" ], 20 - "include" : [], 21 - "cflags" : [], 22 - "lflags" : [], 23 - "run" : "./{output}" 24 - } 25 - 26 - 27 - Hint, Warn, Error = range(3) 28 - log_prefix = { 29 - Hint: "\x1b[32mHint:\x1b[0m", 30 - Warn: "\x1b[33mWarn:\x1b[0m", 31 - Error: "\x1b[31;1mError:\x1b[0m" 32 - } 33 - 34 - 35 - log_lock = threading.Lock() 36 - 37 - def log(msg, mode=Hint): 38 - log_lock.acquire() 39 - print log_prefix[mode], msg 40 - sys.stdout.flush() 41 - log_lock.release() 42 - 43 - 44 - def error(msg): 45 - log(msg, mode=Error) 46 - os._exit(1) 47 - 48 - 49 - def load_config(filename): 50 - """ loads the given config file into the `config` global dict """ 51 - if not path.exists(filename): 52 - error("config file does not exist: '%s'" % filename) 53 - 54 - d = { 55 - "opt": sys.argv, 56 - "platform": platform.system(), 57 - "error": error, 58 - "log": log, 59 - "Hint": Hint, 60 - "Warn": Warn, 61 - "Error": Error 62 - } 63 - execfile(filename, d) 64 - config.update(d) 65 - 66 - if len(config["source"]) == 0: 67 - error("no source directories specified in config") 68 - 69 - 70 - def load_cache(cache_file): 71 - if not path.exists(cache_file): 72 - return { "hashes": [], "cmd": "" } 73 - with open(cache_file) as fp: 74 - log("loaded cache") 75 - return json.load(fp) 76 - 77 - 78 - def update_cache(cache_file, obj): 79 - with open(cache_file, "wb") as fp: 80 - json.dump(obj, fp, indent=2) 81 - log("updated cache") 82 - 83 - 84 - def resolve_file(filename, dir): 85 - """ finds the actual location of an included file """ 86 - f = path.join(dir, filename) 87 - if path.exists(f): 88 - return short_name(f) 89 - 90 - for dir in config["include"]: 91 - f = path.join(dir, filename) 92 - if path.exists(f): 93 - return short_name(f) 94 - 95 - 96 - file_info_cache = {} 97 - 98 - def get_file_info(filename): 99 - """ returns a dict of file info for the given file """ 100 - if filename in file_info_cache: 101 - return file_info_cache[filename] 102 - 103 - hash = sha1() 104 - includes = [] 105 - 106 - with open(filename) as fp: 107 - for line in fp.readlines(): 108 - # get includes 109 - if "#include" in line: 110 - match = re.match('^\s*#include\s+"(.*?)"', line) 111 - if match: 112 - includes.append( match.group(1) ) 113 - # update hash 114 - hash.update(line) 115 - hash.update("\n") 116 - 117 - res = { "hash": hash.hexdigest(), "includes": includes } 118 - file_info_cache[filename] = res 119 - return res 120 - 121 - 122 - def short_name(filename): 123 - """ returns the filename relative to the current path """ 124 - n = len(path.abspath(".")) 125 - return path.abspath(filename)[n+1:] 126 - 127 - 128 - def get_deep_hash(filename): 129 - """ creates a hash from the file and all its includes """ 130 - h = sha1() 131 - processed = set() 132 - files = [ resolve_file(filename, ".") ] 133 - 134 - while len(files) > 0: 135 - f = files.pop() 136 - info = get_file_info(f) 137 - processed.add(f) 138 - 139 - # update hash 140 - h.update(info["hash"]) 141 - 142 - # add includes 143 - for x in info["includes"]: 144 - resolved = resolve_file(x, path.dirname(f)) 145 - if resolved: 146 - if resolved not in processed: 147 - files.append(resolved) 148 - else: 149 - log("could not resolve file '%s'" % x, mode=Warn) 150 - 151 - return h.hexdigest() 152 - 153 - 154 - def build_deep_hash_dict(cfiles): 155 - """ returns a dict mapping each cfile to its hash """ 156 - res = {} 157 - for f in cfiles: 158 - res[f] = get_deep_hash(f) 159 - return res 160 - 161 - 162 - def get_cfiles(): 163 - """ returns all .h and .c files in source directories """ 164 - res = [] 165 - for dir in config["source"]: 166 - for root, dirs, files in os.walk(dir): 167 - for file in files: 168 - if file.endswith((".c", ".h")): 169 - f = path.join(root, file) 170 - res.append( short_name(f) ) 171 - return res 172 - 173 - 174 - def build_compile_cmd(): 175 - """ creates the command used to compile files """ 176 - lst = [ 177 - config["compiler"], 178 - " ".join(map(lambda x: "-I" + x, config["include"])), 179 - " ".join(config["cflags"]), 180 - "-c", "{infile}", "-o", "{outfile}" 181 - ] 182 - return " ".join(lst) 183 - 184 - 185 - def obj_name(filename): 186 - """ creates the object file name for a given filename """ 187 - filename = re.sub("[^\w]+", "_", filename) 188 - return filename[:-2] + "_" + sha1(filename).hexdigest()[:8] + ".o" 189 - 190 - 191 - def compile(cmd, filename): 192 - """ compiles the given file into an object file using the cmd """ 193 - log("compiling '%s'" % filename) 194 - 195 - outfile = path.join(object_dir, obj_name(filename)) 196 - 197 - res = os.system(cmd.format(infile=filename, outfile=outfile)) 198 - if res != 0: 199 - error("failed to compile '%s'" % filename) 200 - 201 - 202 - def link(): 203 - """ links objects and outputs the final binary """ 204 - log("linking") 205 - lst = [ 206 - config["compiler"], 207 - "-o", config["output"], 208 - path.join(object_dir, "*"), 209 - " ".join(config["lflags"]) 210 - ] 211 - cmd = " ".join(lst) 212 - res = os.system(cmd) 213 - if res != 0: 214 - error("failed to link") 215 - 216 - 217 - def parallel(func, workers=4): 218 - """ runs func on multiple threads and waits for them all to finish """ 219 - threads = [] 220 - for i in range(workers): 221 - t = threading.Thread(target=func) 222 - threads.append(t) 223 - t.start() 224 - for t in threads: 225 - t.join() 226 - 227 - 228 - 229 - if __name__ == "__main__": 230 - 231 - start_time = time.time() 232 - 233 - load_config(config_file) 234 - run_at_exit = False 235 - output_dir = path.join(".", path.dirname(config["output"])) 236 - cache = load_cache(cache_file) 237 - cmd = build_compile_cmd() 238 - 239 - if "run" in sys.argv: 240 - run_at_exit = True 241 - 242 - if cache["cmd"] != cmd: 243 - sys.argv.append("clean") 244 - 245 - if "clean" in sys.argv: 246 - log("performing clean build") 247 - shutil.rmtree(cache_dir, ignore_errors=True) 248 - cache = load_cache(cache_file) 249 - 250 - 251 - if not path.exists(object_dir): 252 - os.makedirs(object_dir) 253 - 254 - if not path.exists(output_dir): 255 - os.makedirs(output_dir) 256 - 257 - 258 - if "pre" in config: 259 - config["pre"]() 260 - 261 - 262 - cfiles = get_cfiles() 263 - hashes = build_deep_hash_dict(cfiles) 264 - 265 - 266 - # delete object files for cfiles that no longer exist 267 - obj_files = set(map(obj_name, cfiles)) 268 - for f in os.listdir(object_dir): 269 - if f not in obj_files: 270 - os.remove(path.join(object_dir, f)) 271 - 272 - 273 - # build list of all .c files that need compiling 274 - pending = [] 275 - for f in cfiles: 276 - if f.endswith(".c"): 277 - if f not in cache["hashes"] or cache["hashes"][f] != hashes[f]: 278 - pending.append(f) 279 - 280 - 281 - # compile files until there are none left 282 - def worker(): 283 - while True: 284 - try: 285 - f = pending.pop() 286 - except: 287 - break 288 - compile(cmd, f) 289 - 290 - 291 - parallel(worker, workers=max_workers) 292 - 293 - 294 - link() 295 - update_cache(cache_file, { "hashes": hashes, "cmd": cmd }) 296 - 297 - if "post" in config: 298 - config["post"]() 299 - 300 - 301 - log("done [%.2fs]" % (time.time() - start_time)) 302 - 303 - 304 - if run_at_exit: 305 - log("running") 306 - cmd = config["run"].format(output=config["output"]) 307 - os.system(cmd)
+42
build.sh
··· 1 + #!/bin/bash 2 + 3 + cflags="-Wall -O3 -g -std=gnu11 -Isrc -DLUA_USE_POPEN" 4 + lflags="-lSDL2 -lm" 5 + 6 + if [[ $* == *windows* ]]; then 7 + platform="windows" 8 + outfile="lite.exe" 9 + compiler="x86_64-w64-mingw32-gcc" 10 + cflags="$cflags -Iwinlib/SDL2-2.0.10/x86_64-w64-mingw32/include" 11 + lflags="$lflags -Lwinlib/SDL2-2.0.10/x86_64-w64-mingw32/lib" 12 + lflags="-lmingw32 -lSDL2main $lflags -mwindows -o $outfile res.res" 13 + x86_64-w64-mingw32-windres res.rc -O coff -o res.res 14 + else 15 + platform="unix" 16 + outfile="lite" 17 + compiler="gcc" 18 + lflags="$lflags -o $outfile" 19 + fi 20 + 21 + if command -v ccache >/dev/null; then 22 + compiler="ccache $compiler" 23 + fi 24 + 25 + 26 + echo "compiling ($platform)..." 27 + for f in `find src -name "*.c"`; do 28 + $compiler -c $cflags $f -o "${f//\//_}.o" 29 + if [[ $? -ne 0 ]]; then 30 + got_error=true 31 + fi 32 + done 33 + 34 + if [[ ! $got_error ]]; then 35 + echo "linking..." 36 + $compiler *.o $lflags 37 + fi 38 + 39 + echo "cleaning up..." 40 + rm *.o 41 + rm res.res 2>/dev/null 42 + echo "done"
+2 -2
build_release.sh
··· 1 1 #!/bin/bash 2 - ./build.py release windows 3 - ./build.py release 2 + ./build.sh release windows 3 + ./build.sh release 4 4 rm lite.zip 2>/dev/null 5 5 cp winlib/SDL2-2.0.10/x86_64-w64-mingw32/bin/SDL2.dll SDL2.dll 6 6 strip lite