2424import subprocess
2525import sys
2626from pathlib import Path
27-
28-
2927# ---------------------------------------------------------------------------
3028# Slang-root discovery
3129# ---------------------------------------------------------------------------
@@ -46,15 +44,11 @@ def _find_slang_root(hint: Path | None) -> Path:
4644 "error: cannot locate the Slang repo root.\n "
4745 "Run from inside the Slang source tree or pass --slang-root=<path>."
4846 )
49-
50-
5147# ---------------------------------------------------------------------------
5248# Demo binary discovery + auto-build
5349# ---------------------------------------------------------------------------
5450
5551_TARGET = "shader-coverage-bvh-traversal"
56-
57-
5852def _candidate_paths (slang_root : Path ) -> list :
5953 """All plausible output locations for the demo binary."""
6054 return [
@@ -70,8 +64,6 @@ def _candidate_paths(slang_root: Path) -> list:
7064 * (slang_root / "build" / "examples" / _TARGET / config / (_TARGET + ".exe" )
7165 for config in ("Release" , "Debug" , "RelWithDebInfo" )),
7266 ]
73-
74-
7567def _is_stale (binary : Path , slang_root : Path ) -> bool :
7668 """True if any source file in the demo directory is newer than the binary."""
7769 binary_mtime = binary .stat ().st_mtime
@@ -82,46 +74,19 @@ def _is_stale(binary: Path, slang_root: Path) -> bool:
8274 return True
8375 return False
8476
85-
86- def _slang_bin_dir (slang_root : Path , binary : Path ) -> Path | None :
87- """Return the directory holding the Slang runtime DLLs (slang.dll, gfx.dll, …).
88-
89- The demo exe is built into build/examples/<target>/<config>/, which does NOT
90- contain the runtime DLLs — those live in build/<config>/bin/. On Windows the
91- loader searches only the exe's own directory, so without this on the search
92- path the demo aborts at startup with STATUS_DLL_NOT_FOUND (0xC0000135). We
93- derive <config> from the binary's parent dir, then fall back to scanning the
94- usual locations for whichever one actually contains slang.dll.
95- """
96- dll = "slang.dll" if platform .system () == "Windows" else None
97- if dll is None :
98- return None # POSIX uses rpath / the linker's own search; nothing to do.
99- config = binary .parent .name # Release / Debug / RelWithDebInfo (or the target name for single-config layouts)
100- candidates = [
101- slang_root / "build" / config / "bin" ,
102- * (slang_root / "build" / c / "bin"
103- for c in ("Release" , "Debug" , "RelWithDebInfo" )),
104- slang_root / "build" / "bin" ,
105- ]
106- for c in candidates :
107- if (c / dll ).exists ():
108- return c
109- return None
110-
111-
11277def _ensure_demo_binary (slang_root : Path ) -> Path :
11378 """Return the demo binary path, building it first if necessary."""
11479 # Fast path: already built and up to date.
11580 for c in _candidate_paths (slang_root ):
11681 if c .exists ():
11782 if _is_stale (c , slang_root ):
118- print (f"[build] binary is stale (source newer than binary) -- rebuilding" )
83+ print (f"[build] binary is stale (source newer than binary) — rebuilding" )
11984 break
12085 return c
12186
12287 # Slow path: build only the demo target. Assumes Slang itself is already
12388 # built (cmake --build --preset release was run by the user).
124- print (f"[build] building target '{ _TARGET } ' ... " )
89+ print (f"[build] building target '{ _TARGET } ' … " )
12590 result = subprocess .run (
12691 [shutil .which ("cmake.exe" ) or "cmake" ,
12792 "--build" , "--preset" , "release" , "--target" , _TARGET ],
@@ -141,8 +106,6 @@ def _ensure_demo_binary(slang_root: Path) -> Path:
141106 f"error: build succeeded but '{ _TARGET } ' binary not found in expected paths.\n "
142107 f"Searched under: { slang_root / 'build' } "
143108 )
144-
145-
146109# ---------------------------------------------------------------------------
147110# Argument parsing
148111# ---------------------------------------------------------------------------
@@ -166,8 +129,6 @@ def _parse_args(argv):
166129
167130 known , demo_args = p .parse_known_args (argv )
168131 return known , demo_args
169-
170-
171132# ---------------------------------------------------------------------------
172133# Open browser cross-platform
173134# ---------------------------------------------------------------------------
@@ -181,8 +142,6 @@ def _open_browser(path: Path):
181142 os .startfile (str (path )) # type: ignore[attr-defined]
182143 else :
183144 subprocess .run (["xdg-open" , url ], check = False )
184-
185-
186145# ---------------------------------------------------------------------------
187146# Main
188147# ---------------------------------------------------------------------------
@@ -210,13 +169,14 @@ def main(argv=None):
210169 binary_cmd = [str (binary ), f"--mode={ mode } " ,
211170 f"--output-dir={ output_dir } " , * demo_args ]
212171 print (f"[1/3] running demo: { ' ' .join (str (a ) for a in binary_cmd )} " )
213- # The demo exe lives in build/examples/<target>/<config>/ but its runtime
214- # DLLs live in build/<config>/bin/. Put that dir on the child's PATH so the
215- # Windows loader can find slang.dll/gfx.dll (else: STATUS_DLL_NOT_FOUND).
172+ # On Windows, runtime DLLs (slang.dll etc.) live in
173+ # <build-root>/<config>/bin/, not next to the demo exe. Derive that
174+ # directory from the binary path and prepend it to PATH so the loader
175+ # finds them (otherwise the process aborts with STATUS_DLL_NOT_FOUND).
216176 demo_env = os .environ .copy ()
217- bin_dir = _slang_bin_dir ( slang_root , binary )
218- if bin_dir is not None :
219- demo_env ["PATH" ] = f" { bin_dir } { os .pathsep } { demo_env .get (' PATH' , '' ) } "
177+ if platform . system () == "Windows" and len ( binary . parents ) >= 4 :
178+ dll_dir = binary . parents [ 3 ] / binary . parent . name / "bin"
179+ demo_env ["PATH" ] = str ( dll_dir ) + os .pathsep + demo_env .get (" PATH" , "" )
220180 result = subprocess .run (binary_cmd , env = demo_env )
221181 if result .returncode != 0 :
222182 sys .exit (f"error: demo exited with code { result .returncode } " )
@@ -231,7 +191,7 @@ def main(argv=None):
231191 rich_lcov = output_dir / f"{ mode } .full.lcov"
232192
233193 if not manifest .exists ():
234- sys .exit (f"error: expected manifest at { manifest } -- was coverage disabled?" )
194+ sys .exit (f"error: expected manifest at { manifest } — was coverage disabled?" )
235195
236196 converter = slang_root / "tools" / "shader-coverage" / "slang-coverage-to-lcov.py"
237197 conv_cmd = [
@@ -257,7 +217,7 @@ def main(argv=None):
257217 "--title" , f"bvh-traversal { mode } " ,
258218 "--source-root" , str (slang_root ),
259219 ]
260- print (f"[3/3] rendering HTML report -> { html_dir } " )
220+ print (f"[3/3] rendering HTML report → { html_dir } " )
261221 result = subprocess .run (render_cmd )
262222 if result .returncode != 0 :
263223 sys .exit (f"error: renderer exited with code { result .returncode } " )
@@ -269,7 +229,5 @@ def main(argv=None):
269229 _open_browser (index )
270230
271231 return 0
272-
273-
274232if __name__ == "__main__" :
275233 sys .exit (main ())
0 commit comments