Files
fluxengine/build/c.py
2024-03-30 19:14:02 +01:00

373 lines
7.7 KiB
Python

from os.path import basename, join
from build.ab import (
ABException,
List,
Rule,
Targets,
TargetsMap,
filenameof,
filenamesmatchingof,
filenamesof,
flatten,
normalrule,
bubbledattrsof,
stripext,
targetswithtraitsof,
)
from os.path import *
from types import SimpleNamespace
class Toolchain:
label = ""
cfile = ["$(CC) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"]
cxxfile = ["$(CXX) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"]
clibrary = ["$(AR) cqs {outs[0]} {ins}"]
cxxlibrary = ["$(AR) cqs {outs[0]} {ins}"]
cprogram = ["$(CC) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"]
cxxprogram = ["$(CXX) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"]
class HostToolchain:
label = "HOST "
cfile = ["$(HOSTCC) -c -o {outs[0]} {ins[0]} $(HOSTCFLAGS) {cflags}"]
cxxfile = ["$(HOSTCXX) -c -o {outs[0]} {ins[0]} $(HOSTCFLAGS) {cflags}"]
clibrary = ["$(HOSTAR) cqs {outs[0]} {ins}"]
cxxlibrary = ["$(HOSTAR) cqs {outs[0]} {ins}"]
cprogram = ["$(HOSTCC) -o {outs[0]} {ins} {ldflags} $(HOSTLDFLAGS)"]
cxxprogram = ["$(HOSTCXX) -o {outs[0]} {ins} {ldflags} $(HOSTLDFLAGS)"]
def cfileimpl(self, name, srcs, deps, suffix, commands, label, kind, cflags):
outleaf = stripext(basename(filenameof(srcs[0]))) + suffix
normalrule(
replaces=self,
ins=srcs,
deps=deps,
outs=[outleaf],
label=label,
commands=commands,
cflags=cflags + bubbledattrsof(deps, "caller_cflags"),
)
@Rule
def cfile(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags: List = [],
suffix=".o",
toolchain=Toolchain,
commands=None,
label=None,
):
if not label:
label = toolchain.label + "CC"
if not commands:
commands = toolchain.cfile
cfileimpl(self, name, srcs, deps, suffix, commands, label, "cfile", cflags)
@Rule
def cxxfile(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags: List = [],
suffix=".o",
toolchain=Toolchain,
commands=None,
label=None,
):
if not label:
label = toolchain.label + "CC"
if not commands:
commands = toolchain.cfile
cfileimpl(
self, name, srcs, deps, suffix, commands, label, "cxxfile", cflags
)
def findsources(name, srcs, deps, cflags, toolchain, filerule):
objs = []
for s in flatten(srcs):
objs += [
filerule(
name=join(name, f.removeprefix("$(OBJ)/")),
srcs=[f],
deps=deps,
cflags=cflags,
toolchain=toolchain,
)
for f in filenamesof(s)
if f.endswith(".c")
or f.endswith(".cc")
or f.endswith(".cpp")
or f.endswith(".S")
or f.endswith(".s")
]
if any(f.endswith(".o") for f in filenamesof(s)):
objs += [s]
return objs
@Rule
def cheaders(
self,
name,
hdrs: TargetsMap = None,
caller_cflags: List = None,
deps: Targets = None,
):
cs = []
ins = list(hdrs.values())
outs = []
i = 0
for dest, src in hdrs.items():
s = filenamesof(src)
if len(s) != 1:
raise ABException(
"the target of a header must return exactly one file"
)
cs += ["cp {ins[" + str(i) + "]} {outs[" + str(i) + "]}"]
outs += [dest]
i = i + 1
r = normalrule(
replaces=self,
ins=ins,
outs=outs,
commands=cs,
deps=deps,
label="CHEADERS",
)
r.materialise()
self.attr.caller_cflags = caller_cflags + ["-I" + r.attr.objdir]
self.bubbleattr("caller_cflags", deps)
def libraryimpl(
self,
name,
srcs,
deps,
hdrs,
caller_cflags,
caller_ldflags,
cflags,
ldflags,
toolchain,
commands,
label,
kind,
):
hr = None
if hdrs and not srcs:
cheaders(
replaces=self,
hdrs=hdrs,
deps=targetswithtraitsof(deps, "cheaders"),
caller_cflags=caller_cflags,
)
return
if hdrs:
hr = cheaders(
name=self.localname + "_hdrs",
hdrs=hdrs,
deps=targetswithtraitsof(deps, "cheaders"),
caller_cflags=caller_cflags,
)
hr.materialise()
deps = deps + [hr]
objs = findsources(
name,
srcs,
targetswithtraitsof(deps, "cheaders"),
cflags + bubbledattrsof(deps, "caller_cflags"),
toolchain,
kind,
)
normalrule(
replaces=self,
ins=objs,
outs=[basename(name) + ".a"],
label=label,
commands=commands,
)
self.outs = self.outs + (hr.outs if hr else [])
self.traits.add("cheaders")
self.attr.caller_ldflags = caller_ldflags
self.bubbleattr("caller_ldflags", deps)
self.bubbleattr("caller_cflags", deps)
@Rule
def clibrary(
self,
name,
srcs: Targets = None,
deps: Targets = None,
hdrs: TargetsMap = None,
caller_cflags: List = [],
caller_ldflags: List = [],
cflags: List = [],
ldflags: List = [],
toolchain=Toolchain,
commands=None,
label=None,
cfilerule=cfile,
):
if not label:
label = toolchain.label + "LIB"
if not commands:
commands = toolchain.clibrary
libraryimpl(
self,
name,
srcs,
deps,
hdrs,
caller_cflags,
caller_ldflags,
cflags,
ldflags,
toolchain,
commands,
label,
cfilerule,
)
@Rule
def cxxlibrary(
self,
name,
srcs: Targets = None,
deps: Targets = None,
hdrs: TargetsMap = None,
caller_cflags: List = [],
caller_ldflags: List = [],
cflags: List = [],
ldflags: List = [],
toolchain=Toolchain,
commands=None,
label=None,
):
if not label:
label = toolchain.label + "LIB"
if not commands:
commands = toolchain.clibrary
libraryimpl(
self,
name,
srcs,
deps,
hdrs,
caller_cflags,
caller_ldflags,
cflags,
ldflags,
toolchain,
commands,
label,
cxxfile,
)
def programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
toolchain,
commands,
label,
filerule,
kind,
):
ars = filenamesmatchingof(deps, "*.a")
deps = deps + filenamesmatchingof(srcs, "*.h")
ldflags = ldflags + bubbledattrsof(deps, "caller_ldflags")
cfiles = findsources(name, srcs, deps, cflags, toolchain, filerule)
normalrule(
replaces=self,
ins=cfiles + ars + ars,
outs=[basename(name) + "$(EXT)"],
deps=deps,
label=toolchain.label + label,
commands=commands,
ldflags=ldflags,
)
@Rule
def cprogram(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags: List = [],
ldflags: List = [],
toolchain=Toolchain,
commands=None,
label="CLINK",
cfilerule=cfile,
cfilekind="cprogram",
):
if not commands:
commands = toolchain.cprogram
programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
toolchain,
commands,
label,
cfilerule,
cfilekind,
)
@Rule
def cxxprogram(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags: List = [],
ldflags: List = [],
toolchain=Toolchain,
commands=None,
label="CXXLINK",
):
if not commands:
commands = toolchain.cxxprogram
programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
toolchain,
commands,
label,
cxxfile,
"cxxprogram",
)