103 ap = argparse.ArgumentParser(description=__doc__,
104 formatter_class=argparse.RawDescriptionHelpFormatter)
105 ap.add_argument(
"-p",
"--build", required=
True, help=
"dir holding compile_commands.json")
106 ap.add_argument(
"-s",
"--source-dir", default=
"src")
107 ap.add_argument(
"-o",
"--out", default=
"selfcontained.json")
108 ap.add_argument(
"--jobs", type=int, default=
max(1, (os.cpu_count()
or 2)))
109 args = ap.parse_args()
112 sys.stderr.write(
"selfcontained: %s with %d flags\n" % (compiler, len(flags)))
114 headers, skipped = [], []
115 for dirpath, dirnames, filenames
in os.walk(args.source_dir):
116 rel_dir =
"/" + dirpath.replace(os.sep,
"/").strip(
"/") +
"/"
117 if any(p
in rel_dir
for p
in SKIP_DIR_PARTS):
120 for name
in filenames:
121 if not name.endswith((
".h",
".hpp")):
123 rel = os.path.join(dirpath, name).replace(os.sep,
"/")
124 if any(rel.endswith(x)
for x
in X_MACRO_HEADERS):
125 skipped.append({
"header": rel,
"reason":
"X-macro header, no guard by design"})
129 sys.stderr.write(
"selfcontained: %d headers, %d skipped\n" % (len(headers), len(skipped)))
132 src =
'#include "%s"\n' % os.path.abspath(rel)
133 with tempfile.NamedTemporaryFile(
"w", suffix=
".c", delete=
False)
as tf:
140 env = dict(os.environ, LC_ALL=
"C", LANG=
"C")
141 r = subprocess.run([compiler] + flags
142 + [
"-fdiagnostics-color=never",
"-fsyntax-only", tmp],
143 capture_output=
True, text=
True, errors=
"replace",
144 cwd=workdir, check=
False, env=env)
145 ok = r.returncode == 0
150 clean = ANSI.sub(
"", r.stderr)
151 for line
in clean.splitlines():
152 if ": error:" in line
or ": fatal error:" in line:
156 first = (clean.strip().splitlines()
or [
""])[0]
157 return {
"header": rel,
"ok": ok,
"first_error": first}
161 with ThreadPoolExecutor(max_workers=args.jobs)
as pool:
162 results = list(pool.map(check, headers))
164 bad = [r
for r
in results
if not r[
"ok"]]
165 payload = {
"results": results,
"skipped": skipped,
166 "headers": len(results),
"failing": len(bad)}
167 with open(args.out,
"w", encoding=
"utf-8")
as fh:
168 json.dump(payload, fh, indent=1)
169 sys.stderr.write(
"selfcontained: %d/%d self-contained (%.1f%%), wrote %s\n"
170 % (len(results) - len(bad), len(results),
171 100.0 * (len(results) - len(bad)) /
max(1, len(results)), args.out))