Files
fluxengine/build/c.py
2025-03-17 22:33:54 +01:00

354 lines
7.1 KiB
Python

from build.ab import (
Rule,
Targets,
TargetsMap,
filenameof,
filenamesof,
flatten,
simplerule,
emit,
)
from build.utils import filenamesmatchingof, stripext, collectattrs
from os.path import *
emit(
"""
ifeq ($(OSX),no)
STARTGROUP ?= -Wl,--start-group
ENDGROUP ?= -Wl,--end-group
endif
"""
)
def _combine(list1, list2):
r = list(list1)
for i in list2:
if i not in r:
r.append(i)
return r
def _indirect(deps, name):
r = []
for d in deps:
r = _combine(r, d.args.get(name, [d]))
return r
def cfileimpl(self, name, srcs, deps, suffix, commands, label, cflags):
outleaf = "=" + stripext(basename(filenameof(srcs[0]))) + suffix
hdr_deps = _indirect(deps, "cheader_deps")
cflags = collectattrs(
targets=hdr_deps, name="caller_cflags", initial=cflags
)
t = simplerule(
replaces=self,
ins=srcs,
deps=sorted(_indirect(hdr_deps, "cheader_files")),
outs=[outleaf],
label=label,
commands=commands,
args={"cflags": cflags},
)
@Rule
def cfile(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags=[],
suffix=".o",
commands=["$(CC) -c -o $[outs[0]] $[ins[0]] $(CFLAGS) $[cflags]"],
label="CC",
):
cfileimpl(self, name, srcs, deps, suffix, commands, label, cflags)
@Rule
def cxxfile(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags=[],
suffix=".o",
commands=["$(CXX) -c -o $[outs[0]] $[ins[0]] $(CFLAGS) $[cflags]"],
label="CXX",
):
cfileimpl(self, name, srcs, deps, suffix, commands, label, cflags)
def _removeprefix(self, prefix):
if self.startswith(prefix):
return self[len(prefix) :]
else:
return self[:]
def _isSourceFile(f):
return (
f.endswith(".c")
or f.endswith(".cc")
or f.endswith(".cpp")
or f.endswith(".S")
or f.endswith(".s")
or f.endswith(".m")
or f.endswith(".mm")
)
def findsources(name, srcs, deps, cflags, filerule, cwd):
for f in filenamesof(srcs):
if not _isSourceFile(f):
cflags = cflags + [f"-I{dirname(f)}"]
deps = deps + [f]
objs = []
for s in flatten(srcs):
objs += [
filerule(
name=join(name, _removeprefix(f, "$(OBJ)/")),
srcs=[f],
deps=deps,
cflags=sorted(set(cflags)),
cwd=cwd,
)
for f in filenamesof([s])
if _isSourceFile(f)
]
if any(f.endswith(".o") for f in filenamesof([s])):
objs += [s]
return objs
def libraryimpl(
self,
name,
srcs,
deps,
hdrs,
caller_cflags,
caller_ldflags,
cflags,
ldflags,
commands,
label,
filerule,
):
hdr_deps = _combine(_indirect(deps, "cheader_deps"), [self])
lib_deps = _combine(_indirect(deps, "clibrary_deps"), [self])
hr = None
hf = []
ar = None
if hdrs:
cs = []
ins = 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 += [f"$(CP) $[ins[{i}]] $[outs[{i}]]"]
outs += ["=" + dest]
i = i + 1
hr = simplerule(
name=f"{self.localname}_hdr",
ins=ins,
outs=outs,
commands=cs,
label="CHEADERS",
)
hr.materialise()
hf = [f"-I{hr.dir}"]
if srcs:
objs = findsources(
self.localname,
srcs,
deps + ([hr] if hr else []),
cflags + hf,
filerule,
self.cwd,
)
ar = simplerule(
name=f"{self.localname}_lib",
ins=objs,
outs=[f"={self.localname}.a"],
label=label,
commands=commands,
)
ar.materialise()
self.outs = ([hr] if hr else []) + ([ar] if ar else [])
self.deps = self.outs
self.args["cheader_deps"] = hdr_deps
self.args["clibrary_deps"] = lib_deps
self.args["cheader_files"] = [hr] if hr else []
self.args["clibrary_files"] = [ar] if ar else []
self.args["caller_cflags"] = caller_cflags + hf
self.args["caller_ldflags"] = caller_ldflags
@Rule
def clibrary(
self,
name,
srcs: Targets = None,
deps: Targets = None,
hdrs: TargetsMap = None,
caller_cflags=[],
caller_ldflags=[],
cflags=[],
ldflags=[],
commands=["rm -f $[outs[0]] && $(AR) cqs $[outs[0]] $[ins]"],
label="LIB",
cfilerule=cfile,
):
libraryimpl(
self,
name,
srcs,
deps,
hdrs,
caller_cflags,
caller_ldflags,
cflags,
ldflags,
commands,
label,
cfilerule,
)
@Rule
def cxxlibrary(
self,
name,
srcs: Targets = None,
deps: Targets = None,
hdrs: TargetsMap = None,
caller_cflags=[],
caller_ldflags=[],
cflags=[],
ldflags=[],
commands=["rm -f $[outs[0]] && $(AR) cqs $[outs[0]] $[ins]"],
label="CXXLIB",
cxxfilerule=cxxfile,
):
libraryimpl(
self,
name,
srcs,
deps,
hdrs,
caller_cflags,
caller_ldflags,
cflags,
ldflags,
commands,
label,
cxxfilerule,
)
def programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
commands,
label,
filerule,
):
cfiles = findsources(self.localname, srcs, deps, cflags, filerule, self.cwd)
lib_deps = []
for d in deps:
lib_deps = _combine(lib_deps, d.args.get("clibrary_deps", {d}))
libs = filenamesmatchingof(lib_deps, "*.a")
ldflags = collectattrs(
targets=lib_deps, name="caller_ldflags", initial=ldflags
)
simplerule(
replaces=self,
ins=cfiles + libs,
outs=[f"={self.localname}$(EXT)"],
deps=_indirect(lib_deps, "clibrary_files"),
label=label,
commands=commands,
args={
"ldflags": collectattrs(
targets=lib_deps, name="caller_ldflags", initial=ldflags
)
},
)
@Rule
def cprogram(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags=[],
ldflags=[],
commands=[
"$(CC) -o $[outs[0]] $(STARTGROUP) $[ins] $[ldflags] $(LDFLAGS) $(ENDGROUP)"
],
label="CLINK",
cfilerule=cfile,
):
programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
commands,
label,
cfilerule,
)
@Rule
def cxxprogram(
self,
name,
srcs: Targets = None,
deps: Targets = None,
cflags=[],
ldflags=[],
commands=[
"$(CXX) -o $[outs[0]] $(STARTGROUP) $[ins] $[ldflags] $(LDFLAGS) $(ENDGROUP)"
],
label="CXXLINK",
cxxfilerule=cxxfile,
):
programimpl(
self,
name,
srcs,
deps,
cflags,
ldflags,
commands,
label,
cxxfilerule,
)