|
9 | 9 | import platform |
10 | 10 | import shutil |
11 | 11 | import subprocess |
| 12 | +import sys |
12 | 13 | from pathlib import Path |
13 | 14 | from typing import Optional, Sequence, Union |
14 | 15 |
|
15 | 16 | logger = logging.getLogger(__name__) |
16 | 17 |
|
17 | 18 |
|
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++.") |
24 | 45 |
|
25 | 46 |
|
26 | 47 | def _get_shared_lib_extension() -> str: |
@@ -199,36 +220,76 @@ def build_cxxrtl( |
199 | 220 | cxxrtl_include = _get_cxxrtl_include_path() |
200 | 221 | logger.debug(f"Using CXXRTL headers from {cxxrtl_include}") |
201 | 222 |
|
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"]) |
229 | 261 |
|
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}") |
232 | 293 |
|
233 | 294 | logger.info(f"Built CXXRTL library: {lib_path}") |
234 | 295 | return lib_path |
@@ -308,29 +369,70 @@ def build_cxxrtl_from_amaranth( |
308 | 369 |
|
309 | 370 | # Find CXXRTL headers and compile |
310 | 371 | cxxrtl_include = _get_cxxrtl_include_path() |
311 | | - compiler = _find_cxx_compiler() |
312 | 372 | optimization = kwargs.pop("optimization", "-O2") |
313 | 373 |
|
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}") |
334 | 436 |
|
335 | 437 | logger.info(f"Built CXXRTL library: {lib_path}") |
336 | 438 | return lib_path |
0 commit comments