#!/usr/bin/env python3 # ============================================================================== # std_probe.py — 快速演示「同一段代码在不同语言标准下的支持情况」 # # 用途(对应任务 1):把一段 C 或 C++ 代码片段,在多个 -std= 下逐个编译,报告 # pass / fail / warnings,从而直观看到「某概念在哪个版本成立」。 # # 用法: # tools/std_probe.py --lang c --code 'int main(){ __auto_type x=1; return x; }' # tools/std_probe.py --lang c++ --file snippet.cpp # tools/std_probe.py --lang c --file snippet.c --standards c89,c99,c11,c17,c23 # # 说明: # * 编译器用宿主机 gcc/g++(本仓库 gcc 13 原生支持全部目标标准)。 # * 仅做语法编译(-fsyntax-only),不链接、不运行,避免副作用。 # * 退出码:全 pass 为 0;任一 fail 为 1(便于脚本/CI 判定)。 # ------------------------------------------------------------------------------ import argparse, os, subprocess, sys, tempfile # 默认要探测的标准列表(C 与 C++ 各一组,覆盖课程相关版本) DEFAULTS = { "c": ["c89", "c99", "c11", "c17", "c23"], "c++": ["c++98", "c++03", "c++11", "c++14", "c++17", "c++20", "c++23"], } def probe(code: str, lang: str, standards, extra_flags=None): """Compile `code` under each standard in `standards` (syntax-only). Returns list of dicts: {std, ok, warnings, errors}.""" compiler = "gcc" if lang == "c" else "g++" results = [] extra_flags = extra_flags or [] with tempfile.NamedTemporaryFile("w", suffix=(".c" if lang == "c" else ".cpp"), delete=False) as f: f.write(code) src = f.name try: for std in standards: cmd = [compiler, f"-std={std}", "-fsyntax-only", "-Wall", "-Wextra"] + extra_flags + [src] p = subprocess.run(cmd, capture_output=True, text=True) combined = (p.stderr or "") + (p.stdout or "") # categorize lines: gcc/clang warnings vs errors warns = [l for l in combined.splitlines() if "warning:" in l] errs = [l for l in combined.splitlines() if "error:" in l] results.append({ "std": std, "ok": p.returncode == 0, "warnings": warns, "errors": errs, }) finally: os.unlink(src) return results def main(): ap = argparse.ArgumentParser(description="Probe a C/C++ snippet across -std= versions.") g = ap.add_mutually_exclusive_group(required=True) g.add_argument("--code", help="inline code snippet") g.add_argument("--file", help="path to a source file") ap.add_argument("--lang", choices=["c", "c++"], required=True, help="language (selects compiler & default standards)") ap.add_argument("--standards", default=None, help="comma-separated -std values (default: course-relevant set)") ap.add_argument("--show-warnings", action="store_true", help="print warning lines (default: only summarize)") ap.add_argument("--pedantic-errors", action="store_true", help="add -pedantic-errors so removed/deprecated features FAIL hard " "(gcc otherwise lets many removed features compile as warnings)") args = ap.parse_args() code = args.code if args.code else open(args.file).read() standards = args.standards.split(",") if args.standards else DEFAULTS[args.lang] extra_flags = ["-pedantic-errors"] if args.pedantic_errors else [] print(f"Compiler : {('gcc' if args.lang=='c' else 'g++')} ({subprocess.run(['gcc','--version'],capture_output=True,text=True).stdout.splitlines()[0]})") print(f"Language : {args.lang}") print(f"Standards: {', '.join(standards)}" + (" [pedantic-errors ON]" if args.pedantic_errors else "")) print("-" * 64) results = probe(code, args.lang, standards, extra_flags=extra_flags) any_fail = False for r in results: flag = "PASS" if r["ok"] else "FAIL" w = f" {len(r['warnings'])} warning(s)" if r["warnings"] else "" e = f" {len(r['errors'])} error(s)" if r["errors"] else "" print(f" -std={r['std']:<8} : {flag}{w}{e}") if not r["ok"]: any_fail = True for line in r["errors"][:3]: print(f" {line.strip()}") if args.show_warnings: for line in r["warnings"][:3]: print(f" (warn) {line.strip()}") print("-" * 64) print("Result : " + ("ALL PASS" if not any_fail else "SOME FAIL")) return 1 if any_fail else 0 if __name__ == "__main__": sys.exit(main())