Skip to content

Commit 3ed88ae

Browse files
committed
feat(sim): use zig for CXXRTL C++ compilation
Use the ziglang package for consistent cross-platform C++ compilation when building CXXRTL shared libraries. Due to zig 0.11.0 having issues with -shared flag (missing std library files), we use a two-step approach: 1. Compile to object file with zig c++ 2. Link with system linker (c++/g++/clang++) Falls back to system compiler if zig is not available. Co-developed-by: Claude Code v2.1.9 (claude-opus-4-5-20250929)
1 parent 0313f65 commit 3ed88ae

1 file changed

Lines changed: 158 additions & 56 deletions

File tree

chipflow/sim/build.py

Lines changed: 158 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,39 @@
99
import platform
1010
import shutil
1111
import subprocess
12+
import sys
1213
from pathlib import Path
1314
from typing import Optional, Sequence, Union
1415

1516
logger = logging.getLogger(__name__)
1617

1718

18-
def _find_cxx_compiler() -> str:
19-
"""Find a C++ compiler."""
20-
for compiler in ["c++", "g++", "clang++"]:
21-
if shutil.which(compiler):
22-
return compiler
23-
raise RuntimeError("No C++ compiler found. Install g++ or clang++.")
19+
def _find_zig_cxx() -> Optional[list[str]]:
20+
"""Find zig C++ compiler.
21+
22+
Returns command list for zig c++, or None if not available.
23+
"""
24+
# Prefer zig via ziglang package (consistent cross-platform builds)
25+
try:
26+
import ziglang # noqa: F401
27+
28+
return [sys.executable, "-m", "ziglang", "c++"]
29+
except ImportError:
30+
pass
31+
32+
# Fall back to system zig
33+
if shutil.which("zig"):
34+
return ["zig", "c++"]
35+
36+
return None
37+
38+
39+
def _find_system_linker() -> list[str]:
40+
"""Find a system linker for creating shared libraries."""
41+
for linker in ["c++", "g++", "clang++"]:
42+
if shutil.which(linker):
43+
return [linker]
44+
raise RuntimeError("No C++ linker found. Install g++ or clang++.")
2445

2546

2647
def _get_shared_lib_extension() -> str:
@@ -199,36 +220,76 @@ def build_cxxrtl(
199220
cxxrtl_include = _get_cxxrtl_include_path()
200221
logger.debug(f"Using CXXRTL headers from {cxxrtl_include}")
201222

202-
# Compile to shared library
203-
compiler = _find_cxx_compiler()
204-
compile_cmd = [
205-
compiler,
206-
"-std=c++17",
207-
optimization,
208-
"-shared",
209-
"-fPIC",
210-
f"-I{cxxrtl_include}",
211-
f"-I{output_dir}", # For finding the generated CXXRTL code
212-
"-DCXXRTL_INCLUDE_CAPI_IMPL", # Include C API implementation
213-
"-o", str(lib_path),
214-
str(wrapper_path), # Compile wrapper which includes the generated code
215-
]
216-
217-
# Platform-specific flags
218-
if platform.system() == "Darwin":
219-
compile_cmd.extend(["-undefined", "dynamic_lookup"])
220-
221-
logger.info(f"Compiling CXXRTL library: {lib_path}")
222-
logger.debug(f"Compile command: {' '.join(compile_cmd)}")
223-
224-
result = subprocess.run(
225-
compile_cmd,
226-
capture_output=True,
227-
text=True,
228-
)
223+
# Compile to shared library using zig for compilation, system linker for linking
224+
# (zig 0.11.0 has issues with -shared on some platforms)
225+
zig_cxx = _find_zig_cxx()
226+
obj_path = output_dir / f"{output_name}_capi_wrapper.o"
227+
228+
if zig_cxx:
229+
# Step 1: Compile to object file with zig
230+
compile_cmd = [
231+
*zig_cxx,
232+
"-std=c++17",
233+
optimization,
234+
"-fPIC",
235+
"-c",
236+
f"-I{cxxrtl_include}",
237+
f"-I{output_dir}",
238+
"-DCXXRTL_INCLUDE_CAPI_IMPL",
239+
"-o", str(obj_path),
240+
str(wrapper_path),
241+
]
242+
243+
logger.info(f"Compiling CXXRTL with zig: {obj_path}")
244+
logger.debug(f"Compile command: {' '.join(compile_cmd)}")
245+
246+
result = subprocess.run(compile_cmd, capture_output=True, text=True)
247+
if result.returncode != 0:
248+
raise RuntimeError(f"C++ compilation failed: {result.stderr}")
249+
250+
# Step 2: Link with system linker
251+
linker = _find_system_linker()
252+
link_cmd = [
253+
*linker,
254+
"-shared",
255+
"-o", str(lib_path),
256+
str(obj_path),
257+
]
258+
259+
if platform.system() == "Darwin":
260+
link_cmd.extend(["-undefined", "dynamic_lookup"])
229261

230-
if result.returncode != 0:
231-
raise RuntimeError(f"C++ compilation failed: {result.stderr}")
262+
logger.info(f"Linking CXXRTL library: {lib_path}")
263+
logger.debug(f"Link command: {' '.join(link_cmd)}")
264+
265+
result = subprocess.run(link_cmd, capture_output=True, text=True)
266+
if result.returncode != 0:
267+
raise RuntimeError(f"Linking failed: {result.stderr}")
268+
else:
269+
# Fall back to system compiler for everything
270+
linker = _find_system_linker()
271+
compile_cmd = [
272+
*linker,
273+
"-std=c++17",
274+
optimization,
275+
"-shared",
276+
"-fPIC",
277+
f"-I{cxxrtl_include}",
278+
f"-I{output_dir}",
279+
"-DCXXRTL_INCLUDE_CAPI_IMPL",
280+
"-o", str(lib_path),
281+
str(wrapper_path),
282+
]
283+
284+
if platform.system() == "Darwin":
285+
compile_cmd.extend(["-undefined", "dynamic_lookup"])
286+
287+
logger.info(f"Compiling CXXRTL library: {lib_path}")
288+
logger.debug(f"Compile command: {' '.join(compile_cmd)}")
289+
290+
result = subprocess.run(compile_cmd, capture_output=True, text=True)
291+
if result.returncode != 0:
292+
raise RuntimeError(f"C++ compilation failed: {result.stderr}")
232293

233294
logger.info(f"Built CXXRTL library: {lib_path}")
234295
return lib_path
@@ -308,29 +369,70 @@ def build_cxxrtl_from_amaranth(
308369

309370
# Find CXXRTL headers and compile
310371
cxxrtl_include = _get_cxxrtl_include_path()
311-
compiler = _find_cxx_compiler()
312372
optimization = kwargs.pop("optimization", "-O2")
313373

314-
compile_cmd = [
315-
compiler,
316-
"-std=c++17",
317-
optimization,
318-
"-shared",
319-
"-fPIC",
320-
f"-I{cxxrtl_include}",
321-
"-DCXXRTL_INCLUDE_CAPI_IMPL",
322-
"-o", str(lib_path),
323-
str(cc_path),
324-
]
325-
326-
if platform.system() == "Darwin":
327-
compile_cmd.extend(["-undefined", "dynamic_lookup"])
328-
329-
logger.info(f"Compiling CXXRTL library: {lib_path}")
330-
result = subprocess.run(compile_cmd, capture_output=True, text=True)
331-
332-
if result.returncode != 0:
333-
raise RuntimeError(f"C++ compilation failed: {result.stderr}")
374+
# Compile using zig for compilation, system linker for linking
375+
# (zig 0.11.0 has issues with -shared on some platforms)
376+
zig_cxx = _find_zig_cxx()
377+
obj_path = output_dir / f"{output_name}_cxxrtl.o"
378+
379+
if zig_cxx:
380+
# Step 1: Compile to object file with zig
381+
compile_cmd = [
382+
*zig_cxx,
383+
"-std=c++17",
384+
optimization,
385+
"-fPIC",
386+
"-c",
387+
f"-I{cxxrtl_include}",
388+
"-DCXXRTL_INCLUDE_CAPI_IMPL",
389+
"-o", str(obj_path),
390+
str(cc_path),
391+
]
392+
393+
logger.info(f"Compiling CXXRTL with zig: {obj_path}")
394+
result = subprocess.run(compile_cmd, capture_output=True, text=True)
395+
if result.returncode != 0:
396+
raise RuntimeError(f"C++ compilation failed: {result.stderr}")
397+
398+
# Step 2: Link with system linker
399+
linker = _find_system_linker()
400+
link_cmd = [
401+
*linker,
402+
"-shared",
403+
"-o", str(lib_path),
404+
str(obj_path),
405+
]
406+
407+
if platform.system() == "Darwin":
408+
link_cmd.extend(["-undefined", "dynamic_lookup"])
409+
410+
logger.info(f"Linking CXXRTL library: {lib_path}")
411+
result = subprocess.run(link_cmd, capture_output=True, text=True)
412+
if result.returncode != 0:
413+
raise RuntimeError(f"Linking failed: {result.stderr}")
414+
else:
415+
# Fall back to system compiler for everything
416+
linker = _find_system_linker()
417+
compile_cmd = [
418+
*linker,
419+
"-std=c++17",
420+
optimization,
421+
"-shared",
422+
"-fPIC",
423+
f"-I{cxxrtl_include}",
424+
"-DCXXRTL_INCLUDE_CAPI_IMPL",
425+
"-o", str(lib_path),
426+
str(cc_path),
427+
]
428+
429+
if platform.system() == "Darwin":
430+
compile_cmd.extend(["-undefined", "dynamic_lookup"])
431+
432+
logger.info(f"Compiling CXXRTL library: {lib_path}")
433+
result = subprocess.run(compile_cmd, capture_output=True, text=True)
434+
if result.returncode != 0:
435+
raise RuntimeError(f"C++ compilation failed: {result.stderr}")
334436

335437
logger.info(f"Built CXXRTL library: {lib_path}")
336438
return lib_path

0 commit comments

Comments
 (0)