Files
fluxengine/build/c.py
David Given af0ce4cf35 Update ab.
2024-09-02 23:51:03 +02:00

381 lines
7.8 KiB
Python

from build.ab import (
Rule,
Targets,
TargetsMap,
filenameof,
filenamesof,
flatten,
simplerule,
)
from build.utils import (
filenamesmatchingof,
stripext,
targetswithtraitsof,
collectattrs,
)
from os.path import *
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
cflags = collectattrs(targets=deps, name="caller_cflags", initial=cflags)
t = simplerule(
replaces=self,
ins=srcs,
deps=deps,
outs=[outleaf],
label=label,
commands=commands,
cflags=cflags,
)
@Rule
def cfile(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags=[],
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=[],
suffix=".o",
toolchain=Toolchain,
commands=None,
label=None,
):
if not label:
label = toolchain.label + "CXX"
if not commands:
commands = toolchain.cxxfile
cfileimpl(
self, name, srcs, deps, suffix, commands, label, "cxxfile", cflags
)
def findsources(name, srcs, deps, cflags, toolchain, filerule, cwd):
headers = filenamesmatchingof(srcs, "*.h")
cflags = cflags + ["-I" + dirname(h) for h in headers]
deps = deps + headers
objs = []
for s in flatten(srcs):
objs += [
filerule(
name=join(name, f.removeprefix("$(OBJ)/")),
srcs=[f],
deps=deps,
cflags=cflags,
toolchain=toolchain,
cwd=cwd,
)
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=[],
deps: Targets = None,
):
cs = []
ins = list(hdrs.values())
outs = []
i = 0
for dest, src in hdrs.items():
s = filenamesof([src])
assert (
len(s) == 1
), "the target of a header must return exactly one file"
cs += ["cp {ins[" + str(i) + "]} {outs[" + str(i) + "]}"]
outs += ["=" + dest]
i = i + 1
r = simplerule(
replaces=self,
ins=ins,
outs=outs,
commands=cs,
deps=deps,
label="CHEADERS",
caller_cflags=caller_cflags + ["-I" + self.dir],
)
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(
self.localname,
srcs,
targetswithtraitsof(deps, "cheaders"),
cflags,
toolchain,
kind,
self.cwd,
)
simplerule(
replaces=self,
ins=objs,
outs=[f"={self.localname}.a"],
label=label,
commands=commands,
caller_cflags=collectattrs(
targets=deps + ([hr] if hr else []), name="caller_cflags"
),
caller_ldflags=collectattrs(
targets=deps, name="caller_ldflags", initial=caller_ldflags
),
)
self.outs = self.outs + (hr.outs if hr else [])
self.traits.add("cheaders")
@Rule
def clibrary(
self,
name,
srcs: Targets = None,
deps: Targets = None,
hdrs: TargetsMap = None,
caller_cflags=[],
caller_ldflags=[],
cflags=[],
ldflags=[],
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=[],
caller_ldflags=[],
cflags=[],
ldflags=[],
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")
cfiles = findsources(
self.localname, srcs, deps, cflags, toolchain, filerule, self.cwd
)
simplerule(
replaces=self,
ins=cfiles + ars + ars,
outs=[f"={self.localname}$(EXT)"],
deps=deps,
label=toolchain.label + label,
commands=commands,
ldflags=collectattrs(
targets=deps, name="caller_ldflags", initial=ldflags
),
)
@Rule
def cprogram(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags=[],
ldflags=[],
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=[],
ldflags=[],
toolchain=Toolchain,
commands=None,
label="CXXLINK",
):
if not commands:
commands = toolchain.cxxprogram
programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
toolchain,
commands,
label,
cxxfile,
"cxxprogram",
)