Files
fluxengine/build/c.py
2023-10-27 21:28:47 +01:00

266 lines
5.9 KiB
Python

from os.path import basename, join
from build.ab import (
ABException,
Rule,
Targets,
TargetsMap,
filenameof,
flatten,
filenamesof,
normalrule,
stripext,
)
from os.path import *
from types import SimpleNamespace
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,
)
@Rule
def cfile(
self,
name,
srcs: Targets = [],
deps: Targets = [],
cflags=[],
suffix=".o",
commands=["$(CC) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"],
label="CC",
):
cfileimpl(self, name, srcs, deps, suffix, commands, label, "cfile", cflags)
@Rule
def cxxfile(
self,
name,
srcs: Targets = [],
deps: Targets = [],
cflags=[],
suffix=".o",
commands=["$(CXX) -c -o {outs[0]} {ins[0]} $(CFLAGS) {cflags}"],
label="CXX",
):
cfileimpl(
self, name, srcs, deps, suffix, commands, label, "cxxfile", cflags
)
def findsources(name, srcs, deps, cflags, filerule):
objs = []
for s in flatten(srcs):
objs += [
filerule(
name=join(name, f.removeprefix("$(OBJ)/")),
srcs=[f],
deps=deps,
cflags=cflags,
)
for f in filenamesof(s)
if f.endswith(".c") or f.endswith(".cc") or f.endswith(".cpp")
]
if any(f.endswith(".o") for f in filenamesof(s)):
objs += [s]
return objs
def libraryimpl(
self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, kind
):
if not srcs and not hdrs:
raise ABException(
"clibrary contains no sources and no exported headers"
)
libraries = [d for d in deps if hasattr(d, "clibrary")]
for library in libraries:
if library.clibrary.cflags:
cflags += library.clibrary.cflags
if library.clibrary.ldflags:
ldflags += library.clibrary.ldflags
for f in filenamesof(srcs):
if f.endswith(".h"):
deps += [f]
hdrcs = []
hdrins = list(hdrs.values())
hdrouts = []
i = 0
for dest, src in hdrs.items():
s = filenamesof(src)
if len(s) != 1:
raise ABException(
"a dependency of an export must have exactly one output file"
)
hdrcs += ["cp {ins[" + str(i) + "]} {outs[" + str(i) + "]}"]
hdrouts += [dest]
i = i + 1
if not hasattr(self, "clibrary"):
self.clibrary = SimpleNamespace()
if srcs:
hr = None
if hdrcs:
hr = normalrule(
name=f"{name}_hdrs",
ins=hdrins,
outs=hdrouts,
label="HEADERS",
commands=hdrcs,
)
hr.materialise()
actualsrcs = findsources(
name,
srcs,
deps + ([f"{name}_hdrs"] if hr else []),
cflags + ([f"-I{hr.normalrule.objdir}"] if hr else []),
kind,
)
normalrule(
replaces=self,
ins=actualsrcs,
outs=[basename(name) + ".a"],
label=label,
commands=commands if actualsrcs else [],
)
self.clibrary.ldflags = ldflags
self.clibrary.cflags = ["-I" + hr.normalrule.objdir] if hr else []
else:
r = normalrule(
replaces=self,
ins=hdrins,
outs=hdrouts,
label="HEADERS",
commands=hdrcs,
)
r.materialise()
self.clibrary.ldflags = ldflags
self.clibrary.cflags = ["-I" + r.normalrule.objdir]
@Rule
def clibrary(
self,
name,
srcs: Targets = [],
deps: Targets = [],
hdrs: TargetsMap = {},
cflags=[],
ldflags=[],
commands=["$(AR) cqs {outs[0]} {ins}"],
label="LIB",
):
return libraryimpl(
self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, cfile
)
@Rule
def cxxlibrary(
self,
name,
srcs: Targets = [],
deps: Targets = [],
hdrs: TargetsMap = {},
cflags=[],
ldflags=[],
commands=["$(AR) cqs {outs[0]} {ins}"],
label="LIB",
):
return libraryimpl(
self, name, srcs, deps, hdrs, cflags, ldflags, commands, label, cxxfile
)
def programimpl(
self, name, srcs, deps, cflags, ldflags, commands, label, filerule, kind
):
libraries = [d for d in deps if hasattr(d, "clibrary")]
for library in libraries:
if library.clibrary.cflags:
cflags += library.clibrary.cflags
if library.clibrary.ldflags:
ldflags += library.clibrary.ldflags
deps += [f for f in filenamesof(srcs) if f.endswith(".h")]
ars = [f for f in filenamesof(libraries) if f.endswith(".a")]
normalrule(
replaces=self,
ins=(findsources(name, srcs, deps, cflags, filerule) + ars + ars),
outs=[basename(name) + "$(EXT)"],
deps=deps,
label=label,
commands=commands,
ldflags=ldflags,
)
@Rule
def cprogram(
self,
name,
srcs: Targets = [],
deps: Targets = [],
cflags=[],
ldflags=[],
commands=["$(CC) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"],
label="CLINK",
):
programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
commands,
label,
cfile,
"cprogram",
)
@Rule
def cxxprogram(
self,
name,
srcs: Targets = [],
deps: Targets = [],
cflags=[],
ldflags=[],
commands=["$(CXX) -o {outs[0]} {ins} {ldflags} $(LDFLAGS)"],
label="CXXLINK",
):
programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
commands,
label,
cxxfile,
"cxxprogram",
)