Get path to librt built from the repository, building and caching if necessary. Uses build/librt-cache/ under the repo root (gitignored). The cache is keyed by a hash of sources and build environment, so it auto-invalidates when relevant factors change. Safe to call from multiple p
(experimental: bool = True, opt_level: str = "0")
| 138 | |
| 139 | |
| 140 | def get_librt_path(experimental: bool = True, opt_level: str = "0") -> str: |
| 141 | """Get path to librt built from the repository, building and caching if necessary. |
| 142 | |
| 143 | Uses build/librt-cache/ under the repo root (gitignored). The cache is |
| 144 | keyed by a hash of sources and build environment, so it auto-invalidates |
| 145 | when relevant factors change. |
| 146 | |
| 147 | Safe to call from multiple parallel pytest workers - uses file locking. |
| 148 | |
| 149 | Args: |
| 150 | experimental: Whether to enable experimental features. |
| 151 | opt_level: Optimization level ("0".."3") used when building librt. |
| 152 | |
| 153 | Returns: |
| 154 | Path to directory containing built librt modules. |
| 155 | """ |
| 156 | # Use build/librt-cache/ under the repo root (gitignored) |
| 157 | cache_root = os.path.join(PREFIX, "build", "librt-cache") |
| 158 | build_hash = _librt_build_hash(experimental, opt_level) |
| 159 | build_dir = os.path.join(cache_root, f"librt-{build_hash}") |
| 160 | lock_file = os.path.join(cache_root, f"librt-{build_hash}.lock") |
| 161 | marker = os.path.join(build_dir, ".complete") |
| 162 | |
| 163 | os.makedirs(cache_root, exist_ok=True) |
| 164 | |
| 165 | with filelock.FileLock(lock_file, timeout=300): # 5 min timeout |
| 166 | if os.path.exists(marker): |
| 167 | return build_dir |
| 168 | |
| 169 | # Clean up any partial build |
| 170 | if os.path.exists(build_dir): |
| 171 | shutil.rmtree(build_dir) |
| 172 | |
| 173 | os.makedirs(build_dir) |
| 174 | |
| 175 | # Create librt package directory for --inplace to copy .so files into |
| 176 | librt_pkg = os.path.join(build_dir, "librt") |
| 177 | os.makedirs(librt_pkg) |
| 178 | with open(os.path.join(librt_pkg, "__init__.py"), "w") as f: |
| 179 | pass |
| 180 | |
| 181 | # Copy build_setup.py for per-file SIMD compiler flags |
| 182 | build_setup_src = os.path.join( |
| 183 | os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "build_setup.py" |
| 184 | ) |
| 185 | build_setup_dst = os.path.join(build_dir, "build_setup.py") |
| 186 | shutil.copy(build_setup_src, build_setup_dst) |
| 187 | |
| 188 | # Write setup.py |
| 189 | setup_py = os.path.join(build_dir, "setup.py") |
| 190 | with open(setup_py, "w") as f: |
| 191 | f.write(_generate_setup_py(build_dir, experimental, opt_level)) |
| 192 | |
| 193 | # Build (parallel builds don't work well because multiple extensions |
| 194 | # share the same runtime C files, causing race conditions) |
| 195 | result = subprocess.run( |
| 196 | [sys.executable, setup_py, "build_ext", "--inplace"], |
| 197 | cwd=build_dir, |
searching dependent graphs…