Skip to content

Commit 745f8d3

Browse files
committed
Small compile_flags helper script
1 parent 85ddfca commit 745f8d3

File tree

2 files changed

+188
-0
lines changed

2 files changed

+188
-0
lines changed

examples/small_world/src/base_math/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ swift_cc_library(
55
srcs = ["base_math.cc"],
66
hdrs = ["base_math.hpp"],
77
visibility = ["//visibility:public"],
8+
standard = "20"
89
)
910

1011
swift_cc_test(
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Script to generate compile_commands.json and analyze compile flags for duplicates.
4+
"""
5+
6+
import argparse
7+
import json
8+
import subprocess
9+
import sys
10+
from collections import Counter
11+
12+
13+
def main():
14+
# Parse command line arguments
15+
parser = argparse.ArgumentParser(
16+
description="Generate compile_commands.json and analyze compile flags"
17+
)
18+
parser.add_argument(
19+
"filename",
20+
nargs="?",
21+
default="src/base_math/base_math.cc",
22+
help="Source file to analyze (default: src/base_math/base_math.cc)"
23+
)
24+
args = parser.parse_args()
25+
26+
print("Running: bazel run @hedron_compile_commands//:refresh_all")
27+
print("-" * 60)
28+
29+
# Execute the bazel command
30+
try:
31+
result = subprocess.run(
32+
["bazel", "run", "@hedron_compile_commands//:refresh_all"],
33+
capture_output=True,
34+
text=True,
35+
check=True
36+
)
37+
print(result.stdout)
38+
if result.stderr:
39+
print(result.stderr, file=sys.stderr)
40+
except subprocess.CalledProcessError as e:
41+
print(f"Error running bazel command: {e}", file=sys.stderr)
42+
print(e.stderr, file=sys.stderr)
43+
sys.exit(1)
44+
45+
print("\n" + "=" * 60)
46+
print("Reading compile_commands.json...")
47+
print("=" * 60 + "\n")
48+
49+
# Read the generated compile_commands.json
50+
try:
51+
with open("compile_commands.json", "r") as f:
52+
compile_commands = json.load(f)
53+
except FileNotFoundError:
54+
print("Error: compile_commands.json not found", file=sys.stderr)
55+
sys.exit(1)
56+
except json.JSONDecodeError as e:
57+
print(f"Error parsing compile_commands.json: {e}", file=sys.stderr)
58+
sys.exit(1)
59+
60+
if not compile_commands:
61+
print("Error: compile_commands.json is empty", file=sys.stderr)
62+
sys.exit(1)
63+
64+
# Find the entry for the specified file
65+
target_entry = None
66+
for entry in compile_commands:
67+
if entry.get("file", "").endswith(args.filename):
68+
target_entry = entry
69+
break
70+
71+
if not target_entry:
72+
print(f"Error: No entry found for file '{args.filename}'", file=sys.stderr)
73+
print(f"\nAvailable files:", file=sys.stderr)
74+
for entry in compile_commands[:5]:
75+
print(f" - {entry.get('file', 'N/A')}", file=sys.stderr)
76+
if len(compile_commands) > 5:
77+
print(f" ... and {len(compile_commands) - 5} more", file=sys.stderr)
78+
sys.exit(1)
79+
80+
print(f"Target file: {target_entry.get('file', 'N/A')}")
81+
print(f"Directory: {target_entry.get('directory', 'N/A')}")
82+
print("\n" + "-" * 60)
83+
print("Compile options from target entry:")
84+
print("-" * 60 + "\n")
85+
86+
# Parse the command to extract compile options
87+
command = target_entry.get("command", "")
88+
if not command:
89+
# Try 'arguments' field if 'command' is not present
90+
arguments = target_entry.get("arguments", [])
91+
if arguments:
92+
compile_options = [arg for arg in arguments if arg.startswith("-")]
93+
else:
94+
print("Error: No command or arguments found in target entry", file=sys.stderr)
95+
sys.exit(1)
96+
else:
97+
# Split command string and extract options starting with '-'
98+
import shlex
99+
parts = shlex.split(command)
100+
compile_options = [part for part in parts if part.startswith("-")]
101+
102+
# Display all compile options
103+
for i, option in enumerate(compile_options, 1):
104+
print(f"{i:3d}. {option}")
105+
106+
print(f"\nTotal compile options: {len(compile_options)}")
107+
108+
# Check for duplicates
109+
print("\n" + "=" * 60)
110+
print("Checking for duplicate compile options...")
111+
print("=" * 60 + "\n")
112+
113+
option_counts = Counter(compile_options)
114+
duplicates = {opt: count for opt, count in option_counts.items() if count > 1}
115+
116+
if duplicates:
117+
print(f"Found {len(duplicates)} duplicate compile option(s):\n")
118+
for option, count in sorted(duplicates.items(), key=lambda x: x[1], reverse=True):
119+
print(f" '{option}' appears {count} times")
120+
else:
121+
print("No duplicate compile options found.")
122+
123+
# Check for contradicting flags
124+
print("\n" + "=" * 60)
125+
print("Checking for contradicting compile options...")
126+
print("=" * 60 + "\n")
127+
128+
contradictions_found = False
129+
130+
# Check for multiple -std= flags
131+
std_flags = [opt for opt in compile_options if opt.startswith("-std=")]
132+
if len(std_flags) > 1:
133+
contradictions_found = True
134+
print(f"Found {len(std_flags)} conflicting C++ standard flags:")
135+
for flag in std_flags:
136+
print(f" {flag}")
137+
print()
138+
139+
# Check for multiple optimization levels
140+
opt_flags = [opt for opt in compile_options if opt in ["-O0", "-O1", "-O2", "-O3", "-Os", "-Oz", "-Og", "-Ofast"]]
141+
if len(opt_flags) > 1:
142+
contradictions_found = True
143+
print(f"Found {len(opt_flags)} conflicting optimization level flags:")
144+
for flag in opt_flags:
145+
print(f" {flag}")
146+
print()
147+
148+
# Check for conflicting debug flags
149+
if "-g" in compile_options and "-g0" in compile_options:
150+
contradictions_found = True
151+
print("Found conflicting debug flags:")
152+
print(" -g (enable debug info)")
153+
print(" -g0 (disable debug info)")
154+
print()
155+
156+
# Check for conflicting warning flags
157+
warning_contradictions = []
158+
for i, opt1 in enumerate(compile_options):
159+
if opt1.startswith("-W") and not opt1.startswith("-Wl,"):
160+
# Check if there's a negating flag
161+
if opt1.startswith("-Wno-"):
162+
positive_flag = "-W" + opt1[5:] # Remove "no-" to get positive version
163+
if positive_flag in compile_options:
164+
warning_contradictions.append((positive_flag, opt1))
165+
else:
166+
negative_flag = opt1[:2] + "no-" + opt1[2:] # Add "no-"
167+
if negative_flag in compile_options:
168+
warning_contradictions.append((opt1, negative_flag))
169+
170+
# Remove duplicates by converting to set
171+
warning_contradictions = list(set(warning_contradictions))
172+
173+
if warning_contradictions:
174+
contradictions_found = True
175+
print(f"Found {len(warning_contradictions)} conflicting warning flag pair(s):")
176+
for pos_flag, neg_flag in warning_contradictions:
177+
print(f" {pos_flag} <-> {neg_flag}")
178+
print()
179+
180+
if not contradictions_found:
181+
print("No contradicting compile options found.")
182+
183+
return 0
184+
185+
186+
if __name__ == "__main__":
187+
sys.exit(main())

0 commit comments

Comments
 (0)