Skip to content

Instantly share code, notes, and snippets.

@jarikomppa jarikomppa/m.py
Last active Oct 8, 2018

Embed
What would you like to do?
using multiple processes now!
# Sol's Stupidly Simple Build System v.2.1
# (c) 2018 Jari Komppa http://iki.fi/sol
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
import os
import subprocess
# Add source files here.
# Special names:
# "*" is a sync point, causing all running processes to finish before
# continuing, so if you're generating files needed by later sources,
# add sync point before them.
# "+" is a literal shell command, like "+del *.bak" runs "del *.bak".
src = [
"+cls",
"crt0.s",
"primdraw.c",
"data.c",
"drawstring.c",
"ingame.c",
"tour.c",
"heal.c",
"newcard.c",
"shop.c",
"app.c",
"tools.c"
]
# Add targets here. Note that if there's dependencies,
# you need the sync ("*") points.
product = [
"crt0.ihx",
"*",
"engarde.tap",
"*",
"+speccy engarde.tap"
]
# Add file suffix based methods here: first param is the resulting
# suffix, second param is the command to execute. Tags are replaced
# before execution: %SRCFILE for source file, %DSTFILE for resulting
# file. %TARGETSUFFIX for lists of target files - so if you generate
# .obj files, %OBJ has list of all object files from src list.
methods = {
"c" : [ "rel", "..\\cc\\sdcc360\\bin\\sdcc -c -o %DSTFILE %SRCFILE -mz80 --no-std-crt0 --opt-code-speed --Werror --peep-asm --peep-return " ],
"s" : [ "rel", "..\\cc\\sdcc360\\bin\\sdasz80 -xlos -g %DSTFILE %SRCFILE" ],
"ihx" : [ "ihx", "..\\cc\\sdcc360\\bin\\sdcc -mz80 --no-std-crt0 --opt-code-speed --nostdlib --code-loc 0x6007 --data-loc 0x5b00 -Wl -b_HEADER=0x6000 %REL"],
"tap" : [ "tap", "..\\tools\\mackarel crt0.ihx %DSTFILE Engarde loader.scr -nosprestore -noei"]
}
# If you want to add tags, just add keys here,
# like "SDCC": "../sdcc350/bin/sdcc":
objectlists = {}
#####################################################################
#####################################################################
#####################################################################
class BuildTask:
def __init__(self, proc, dstfile):
self.proc = proc
self.dstfile = dstfile
procs = []
changed = False
# If we want to track includes from .s files, we just need to
# make a variant of this..
def scandeps_c(srcfile, reftime, ignore = None):
# Avoid infinite loops
if ignore is None:
ignore = set()
if srcfile not in ignore:
ignore.add(srcfile)
# It's ok if we don't find the file, we'll just skip it
if os.path.isfile(srcfile):
dtime = os.path.getmtime(srcfile)
if (dtime > reftime):
reftime = dtime
# Scan for includes and recurse
inc = []
with open(srcfile, "r") as f:
for line in f:
if len(line.strip()) > 0 and line.strip()[0] == "#" and "include" in line and '"' in line:
inc.append(line)
for x in inc:
dtime = scandeps_c(x[x.find('"')+1:x.rfind('"')], reftime, ignore)
if (dtime > reftime):
reftime = dtime
# Return the biggest timestamp found
return reftime
def scandeps(srcfile, reftime):
if srcfile[srcfile.rfind(".")+1:] in "c h cpp hpp".split():
return scandeps_c(srcfile, reftime)
return reftime
def agecheck(srcfile, dstfile):
if not os.path.isfile(dstfile):
return True
srctime = scandeps(srcfile, os.path.getmtime(srcfile))
dsttime = os.path.getmtime(dstfile)
if (srctime > dsttime):
return True
return False
def build(srcfile, dstfile, method):
global changed
print "building " + dstfile
if os.path.isfile(dstfile):
os.remove(dstfile)
cmd = method.replace("%SRCFILE", srcfile).replace("%DSTFILE", dstfile)
for key, value in objectlists.iteritems():
cmd = cmd.replace("%"+key.upper(), value)
procs.append(BuildTask(subprocess.Popen(cmd, shell=True, bufsize=8192, stdout=subprocess.PIPE, stderr=subprocess.STDOUT), dstfile))
changed = True
def sync():
global procs
failboat = False
livecount = 0
for x in procs:
if x.proc.poll() is None:
livecount += 1
# If more than one process is still running, print info.
if livecount > 1:
print "Waiting for", len(procs), "processes to finish.."
for x in procs:
(a,b) = x.proc.communicate()
# avoid printing empty lines..
if a != "":
print a
if not os.path.isfile(x.dstfile):
print "Error: " + x.dstfile + " not generated."
failboat = True
procs = []
if failboat:
exit()
#####################################################################
#####################################################################
#####################################################################
# scan all source files, build if changed
for x in src:
if x[0] == "*":
sync()
else:
if x[0] == "+":
os.system(x[1:])
else:
if not os.path.isfile(x):
print x + " does not exist."
exit()
fname = x[:x.rfind(".")]
suffix = x[x.rfind(".")+1:]
if suffix not in methods:
print "Don't know how to handle files of type " + suffix + " (in " + x + ")."
exit()
if methods[suffix][0] not in objectlists:
objectlists[methods[suffix][0]] = fname + "." + methods[suffix][0];
else:
objectlists[methods[suffix][0]] += " " + fname + "." + methods[suffix][0];
if agecheck(x, fname + "." + methods[suffix][0]):
build(x, fname + "." + methods[suffix][0], methods[suffix][1])
# Sync before moving to product phase
sync()
# If targets don't exist, build them
for x in product:
if x[0] not in "*+" and not os.path.isfile(x):
changed = True
# if source files have changed, or targets don't change, link
if changed:
for x in product:
if x[0] == "*":
sync()
else:
if x[0] == "+":
os.system(x[1:])
else:
fname = x[:x.rfind(".")]
suffix = x[x.rfind(".")+1:]
if suffix not in methods:
print "Don't know how to handle files of type " + suffix + " (in " + x + ")."
build(x, fname + "." + methods[suffix][0], methods[suffix][1])
else:
print "Nothing to do."
exit()
# Final sync just to be sure
sync()
print "All done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.