Files
c-toxcore/other/docker/modules/check
T

273 lines
8.1 KiB
Python
Executable File

#!/usr/bin/env python3
import glob
import os
import subprocess
import sys
from dataclasses import dataclass
from dataclasses import field
from typing import Any
from typing import Dict
from typing import List
# We no longer define 'std' or 'musl' manually.
# We rely on -fimplicit-module-maps to find the system-provided ones.
# We only define modules for our project and third-party libraries.
EXTRA_MODULES = """
module "_benchmark" [system] {
header "/usr/include/benchmark/benchmark.h"
export *
}
module "_com_google_googletest___gtest" [system] {
header "/usr/include/gtest/gtest.h"
header "/usr/include/gmock/gmock.h"
export *
}
module "_com_google_googletest___gtest_main" [system] {
use _com_google_googletest___gtest
export *
}
module "_libsodium" [system] {
header "/usr/include/sodium.h"
export *
}
module "_c_std" [system] {
header "/usr/include/stdint.h"
header "/usr/include/stdbool.h"
header "/usr/include/stddef.h"
header "/usr/include/stdio.h"
header "/usr/include/stdlib.h"
header "/usr/include/string.h"
header "/usr/include/inttypes.h"
export *
}
module "_pthread" [system] {
header "/usr/include/pthread.h"
use _c_std
export _c_std
export *
}
module "_psocket" [system] {
header "/usr/include/arpa/inet.h"
header "/usr/include/fcntl.h"
header "/usr/include/fortify/sys/socket.h"
header "/usr/include/linux/if.h"
header "/usr/include/netdb.h"
header "/usr/include/netinet/in.h"
header "/usr/include/sys/epoll.h"
header "/usr/include/sys/ioctl.h"
header "/usr/include/sys/socket.h"
header "/usr/include/sys/stat.h"
header "/usr/include/sys/types.h"
header "/usr/include/unistd.h"
use _c_std
export _c_std
export *
}
"""
@dataclass
class Target:
name: str
package: str
srcs: List[str] = field(default_factory=list)
hdrs: List[str] = field(default_factory=list)
deps: List[str] = field(default_factory=list)
@property
def label(self) -> str:
# Sanitize label for module name
sanitized = (f"//c-toxcore/{self.package}:{self.name}".replace(
"/", "_").replace(":",
"_").replace(".",
"_").replace("-",
"_").replace("@", "_"))
if sanitized.startswith("__"):
sanitized = sanitized[2:]
return sanitized
TARGETS: List[Target] = []
class BuildContext:
def __init__(self, package: str):
self.package = package
def bzl_load(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_exports_files(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_alias(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_sh_library(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_cc_fuzz_test(self, *args: Any, **kwargs: Any) -> None:
pass
def bzl_select(self, selector: Dict[str, List[str]]) -> List[str]:
return selector.get("//tools/config:linux",
selector.get("//conditions:default", []))
def bzl_glob(self, include: List[str]) -> List[str]:
results = []
for pattern in include:
full_pattern = os.path.join(self.package, pattern)
files = glob.glob(full_pattern)
results.extend([os.path.relpath(f, self.package) for f in files])
return results
def _add_target(self, name: str, srcs: Any, hdrs: Any, deps: Any) -> None:
srcs = list(srcs) if srcs else []
hdrs = list(hdrs) if hdrs else []
deps = list(deps) if deps else []
TARGETS.append(Target(name, self.package, srcs, hdrs, deps))
def bzl_cc_library(self,
name: str,
srcs: Any = (),
hdrs: Any = (),
deps: Any = (),
**kwargs: Any) -> None:
self._add_target(name, srcs, hdrs, deps)
def bzl_cc_binary(self,
name: str,
srcs: Any = (),
hdrs: Any = (),
deps: Any = (),
**kwargs: Any) -> None:
self._add_target(name, srcs, hdrs, deps)
def bzl_cc_test(self,
name: str,
srcs: Any = (),
hdrs: Any = (),
deps: Any = (),
**kwargs: Any) -> None:
self._add_target(name, srcs, hdrs, deps)
def resolve_module_name(dep: str, current_pkg: str) -> str:
# Resolve to canonical label first
label = dep
if dep.startswith("@"):
label = dep
elif dep.startswith("//"):
if ":" in dep:
label = dep
else:
pkg_name = os.path.basename(dep)
label = f"{dep}:{pkg_name}"
elif dep.startswith(":"):
label = f"//c-toxcore/{current_pkg}{dep}"
# Sanitize
sanitized = (label.replace("/", "_").replace(":", "_").replace(
".", "_").replace("-", "_").replace("@", "_"))
if sanitized.startswith("__"):
sanitized = sanitized[2:]
return sanitized
def main() -> None:
packages = ["toxcore", "testing/support"]
for pkg in packages:
ctx = BuildContext(pkg)
build_file = os.path.join(pkg, "BUILD.bazel")
if not os.path.exists(build_file):
continue
with open(build_file, "r") as f:
exec(
f.read(),
{
"load": ctx.bzl_load,
"exports_files": ctx.bzl_exports_files,
"cc_library": ctx.bzl_cc_library,
"cc_binary": ctx.bzl_cc_binary,
"cc_test": ctx.bzl_cc_test,
"cc_fuzz_test": ctx.bzl_cc_fuzz_test,
"select": ctx.bzl_select,
"glob": ctx.bzl_glob,
"alias": ctx.bzl_alias,
"sh_library": ctx.bzl_sh_library,
},
)
with open("module.modulemap", "w") as f:
f.write(EXTRA_MODULES)
for t in TARGETS:
f.write(f'module "{t.label}" {{\n')
for hdr in t.hdrs:
# Proper modular header
f.write(f' header "{os.path.join(t.package, hdr)}"\n')
# Export all dependencies
for dep in t.deps:
mod_name = resolve_module_name(dep, t.package)
f.write(f" use {mod_name}\n")
f.write(f" export {mod_name}\n")
# Basic system modules used everywhere
f.write(" use std\n")
f.write(" use _c_std\n")
f.write(" use _psocket\n")
f.write(" use _pthread\n")
f.write(" use _libsodium\n")
f.write(" export *\n")
f.write("}\n")
with open("module.modulemap", "r") as f:
print("--- Generated module.modulemap ---", file=sys.stderr)
print(f.read(), file=sys.stderr)
print("----------------------------------", file=sys.stderr)
src_to_module = {}
for t in TARGETS:
for src in t.srcs:
full_src = os.path.join(t.package, src)
src_to_module[full_src] = t.label
all_srcs = sorted(src_to_module.keys())
os.makedirs("/tmp/clang-modules", exist_ok=True)
for src in all_srcs:
print(f"Validating {src}", file=sys.stderr)
module_name = src_to_module[src]
subprocess.run(
[
"clang",
"-fsyntax-only",
"-xc++",
"-stdlib=libc++",
"-Wall",
"-Werror",
"-Wno-missing-braces",
"-DTCP_SERVER_USE_EPOLL",
"-std=c++23",
"-fdiagnostics-color=always",
"-fmodules",
"-fimplicit-module-maps",
"-fbuiltin-module-map",
"-fmodules-cache-path=/tmp/clang-modules",
"-fmodule-map-file=module.modulemap",
f"-fmodule-name={module_name}",
"-I.",
src,
],
check=True,
)
if __name__ == "__main__":
main()