-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathbuild.py
More file actions
executable file
·166 lines (145 loc) · 6.01 KB
/
build.py
File metadata and controls
executable file
·166 lines (145 loc) · 6.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#!/usr/bin/env python3
# TODO: move this file into ivl/
from pathlib import Path
import shutil
import sys
import subprocess
import os
from dataclasses import dataclass
repo_root = Path(__file__).parent.resolve()
build_dir = repo_root / "build"
src = build_dir / "source_copy"
build_prep = repo_root / "ivl/build_system/generate_build_sources"
assert build_prep.with_suffix(".cpp").exists(), build_prep
if not build_prep.exists():
print(f"Build prep binary {build_prep} not found, building it ...")
subprocess.run(["g++", build_prep.with_suffix(".cpp"), "-O3", "-std=c++23", "-o", build_prep], check=True)
if build_prep.with_suffix(".cpp").stat().st_mtime > build_prep.stat().st_mtime:
print(f"Build prep binary {build_prep} older than sources, rebuilding it ...")
subprocess.run(["g++", build_prep.with_suffix(".cpp"), "-O3", "-std=c++23", "-o", build_prep], check=True)
subprocess.run([build_prep], check=True)
all_targets = dict()
@dataclass
class TargetState:
path: Path
added_compiler_flags: list
added_compiler_flags_tail: list
# building this requires these to also be built,
# but not strictly before
unordered_dependencies: set
# TODO: revert when build is caching
common_test_dependencies = set() # {Path("/build_system/run_test")}
def deduce_file_targets(path):
added_compiler_flags = []
added_compiler_flags_tail = []
unordered_dependencies = set()
unordered_test_dependencies = set()
file_has_reg_variant = path.suffix == ".cpp"
file_has_test_variant = False
ivl_main_handler = True
def add_compiler_flags(arg):
nonlocal added_compiler_flags
added_compiler_flags += arg.split()
def add_compiler_flags_tail(arg):
nonlocal added_compiler_flags_tail
added_compiler_flags_tail += arg.split()
def add_dependencies(arg):
nonlocal unordered_dependencies
unordered_dependencies |= set(arg.split())
def add_test_dependencies(arg):
nonlocal unordered_test_dependencies
unordered_test_dependencies |= set(arg.split())
def test_only():
nonlocal file_has_reg_variant
nonlocal file_has_test_variant
assert path.suffix == ".cpp", path
file_has_reg_variant = False
file_has_test_variant = True
def has_test_variant():
nonlocal file_has_test_variant
file_has_test_variant = True
def disable_ivl_main_handler():
nonlocal ivl_main_handler
ivl_main_handler = False
with path.open() as f:
x = "// IVL "
ivl_directives = [l.removeprefix(x)[:-1] for l in f.readlines() if l.startswith(x)]
for d in ivl_directives:
eval(d)
# TODO: mayhaps don't strip out the ivl , when you add submodules
if path.name == "default.hpp":
name = "/" / path.parent.relative_to(src / "ivl")
else:
name = "/" / path.relative_to(src / "ivl").with_suffix('')
if file_has_test_variant:
all_targets[name.parent / f"{name.name}@test"] = TargetState(path, added_compiler_flags, added_compiler_flags_tail + ["-include", "ivl/reflection/test_runner"], unordered_dependencies | unordered_test_dependencies | common_test_dependencies)
if file_has_reg_variant:
all_targets[name] = TargetState(path, added_compiler_flags, added_compiler_flags_tail + (["-include", "ivl/reflection/ivl_main_handler"] if ivl_main_handler else []), unordered_dependencies)
for dirpath, _, filenames in src.walk():
for filename in filenames:
filepath = dirpath / filename
if filepath.suffix == ".cpp" or filepath.suffix == ".hpp":
deduce_file_targets(filepath)
# print(*all_targets.keys(), sep="\n")
unprocessed_targets = set()
for x in sys.argv[1:]:
y = repo_root / "ivl" / ("."+x) if x.startswith("/") else Path.cwd() / x
z = "/" / y.relative_to(repo_root / "ivl")
assert y.is_dir() or z in all_targets, z
if z in all_targets:
unprocessed_targets.add(z)
continue
for target in all_targets.keys():
if z in target.parents:
unprocessed_targets.add(target)
targets = set()
while unprocessed_targets:
target = unprocessed_targets.pop()
targets.add(target)
for dep in all_targets[target].unordered_dependencies:
if dep not in targets:
unprocessed_targets.add(dep)
print(targets)
# cxxinc = [f"-I{x}" for x in (build_dir / "include_dirs").iterdir()]
cxxinc = [f"@{build_dir / "include_dirs/args.rsp"}"]
# cxxfmap = [f"-ffile-prefix-map={x}=" for x in [src] + list((build_dir / "include_dirs").iterdir())]
cxxfmap = [f"-ffile-prefix-map={repo_root}/="]
# TODO: add gcc repo as submodule, build it, default to using it
# UPDT: use the reflection repo: https://forge.sourceware.org/marek/gcc.git
# UPDT: reflection merged upstream, also submodules/build-gcc.sh installs it to /opt/GCC
cxx = os.getenv("CXX", "g++")
cxxpre = os.getenv("CXXPRE", "")
cxxrpath = os.getenv("CXXRPATH", [f"-Wl,-rpath={Path(shutil.which(cxx)).parent.parent / "lib64"}"])
cxxver = os.getenv("CXXVER", "26")
cxxpost = os.getenv("CXXPOST", "")
for target in targets:
path = all_targets[target].path
cxxadded = all_targets[target].added_compiler_flags
cxxaddedpost = all_targets[target].added_compiler_flags_tail
args = ([cxx] +
cxxpre.split() +
cxxrpath +
cxxadded +
cxxinc +
cxxfmap +
["-DIVL_LOCAL",
f"-DIVL_FILE=\"{path.relative_to(src)}\"",
# "-static",
"-O3",
# "-g1",
f"-std=c++{cxxver}",
# f"-I{include.parent.resolve()}",
# f"-I{default_include.parent.resolve()}",
# "-include",
# "ivl/reflection/test_attribute",
"-freflection",
"-fcontracts",
"-include",
path,
"-xc++",
"/dev/null",
"-o",
repo_root / "ivl" / target.relative_to('/')] +
cxxpost.split() + cxxaddedpost)
print(" ".join([str(x) for x in args]))
subprocess.run(args, check=True)