clang-tool-chain 1.1.5__py3-none-any.whl → 1.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- __version__ = "1.0.30"
1
+ __version__ = "1.1.7"
2
2
 
3
3
  # Re-export commonly used functions for convenient access
4
4
  from clang_tool_chain.env_utils import (
@@ -9,6 +9,9 @@ from clang_tool_chain.env_utils import (
9
9
  )
10
10
  from clang_tool_chain.execution.sanitizer_env import (
11
11
  detect_sanitizers_from_flags,
12
+ get_all_sanitizer_runtime_dlls,
13
+ get_asan_runtime_dll,
14
+ get_default_asan_options,
12
15
  get_runtime_dll_paths,
13
16
  get_symbolizer_path,
14
17
  prepare_sanitizer_environment,
@@ -31,4 +34,7 @@ __all__ = [
31
34
  "get_runtime_dll_paths",
32
35
  "get_symbolizer_path",
33
36
  "detect_sanitizers_from_flags",
37
+ "get_asan_runtime_dll",
38
+ "get_all_sanitizer_runtime_dlls",
39
+ "get_default_asan_options",
34
40
  ]
@@ -1,3 +1,3 @@
1
1
  """Version information for clang-tool-chain."""
2
2
 
3
- __version__ = "1.1.5"
3
+ __version__ = "1.1.7"
@@ -30,11 +30,47 @@ logger = logging.getLogger(__name__)
30
30
  # Default options to inject for optimal stack traces
31
31
  # fast_unwind_on_malloc=0: Use slow but accurate unwinding (fixes <unknown module>)
32
32
  # symbolize=1: Enable symbolization for readable stack traces
33
- # detect_leaks=1: Enable leak detection (ASAN only)
34
- DEFAULT_ASAN_OPTIONS = "fast_unwind_on_malloc=0:symbolize=1:detect_leaks=1"
33
+ # detect_leaks=1: Enable leak detection (ASAN only, NOT on Windows - LSAN unsupported)
34
+ #
35
+ # LeakSanitizer (LSAN) is NOT supported on Windows. Only Linux, macOS, Android,
36
+ # Fuchsia, and NetBSD are supported. See: https://clang.llvm.org/docs/LeakSanitizer.html
37
+ #
38
+ # On Windows, setting detect_leaks=1 causes immediate failure with:
39
+ # "AddressSanitizer: detect_leaks is not supported on this platform."
40
+ _BASE_ASAN_OPTIONS = "fast_unwind_on_malloc=0:symbolize=1"
35
41
  DEFAULT_LSAN_OPTIONS = "fast_unwind_on_malloc=0:symbolize=1"
36
42
 
37
43
 
44
+ def get_default_asan_options() -> str:
45
+ """
46
+ Get platform-appropriate default ASAN options.
47
+
48
+ Returns options string with detect_leaks=1 only on platforms where
49
+ LeakSanitizer is supported (Linux, macOS). Windows does not support
50
+ LSAN, so detect_leaks is omitted to prevent runtime failures.
51
+
52
+ Returns:
53
+ ASAN options string appropriate for the current platform.
54
+
55
+ Example:
56
+ >>> get_default_asan_options() # On Linux/macOS
57
+ 'fast_unwind_on_malloc=0:symbolize=1:detect_leaks=1'
58
+ >>> get_default_asan_options() # On Windows
59
+ 'fast_unwind_on_malloc=0:symbolize=1'
60
+ """
61
+ if platform.system() == "Windows":
62
+ # LSAN (LeakSanitizer) is not supported on Windows
63
+ # See: https://clang.llvm.org/docs/LeakSanitizer.html
64
+ return _BASE_ASAN_OPTIONS
65
+ # Linux, macOS, and other platforms support LSAN
66
+ return f"{_BASE_ASAN_OPTIONS}:detect_leaks=1"
67
+
68
+
69
+ # For backward compatibility - this is now dynamically computed
70
+ # Code that imports DEFAULT_ASAN_OPTIONS directly will get the platform-appropriate value
71
+ DEFAULT_ASAN_OPTIONS = get_default_asan_options()
72
+
73
+
38
74
  def get_symbolizer_path() -> str | None:
39
75
  """
40
76
  Get the path to llvm-symbolizer from the clang-tool-chain installation.
@@ -131,6 +167,168 @@ def get_runtime_dll_paths() -> list[str]:
131
167
  return paths
132
168
 
133
169
 
170
+ def get_asan_runtime_dll() -> Path | None:
171
+ """
172
+ Get the full path to the ASAN runtime DLL (Windows only).
173
+
174
+ This function locates the shared ASAN runtime DLL used when compiling
175
+ with -fsanitize=address -shared-libasan. The DLL must be accessible
176
+ at runtime for ASAN-instrumented executables to run.
177
+
178
+ This is particularly useful when running tests via build systems like
179
+ Meson that reset PATH and don't inherit ASAN DLL directories. By getting
180
+ the DLL path, consuming projects can copy it to their build directory
181
+ where the build system will automatically discover it.
182
+
183
+ Returns:
184
+ Path to libclang_rt.asan_dynamic-x86_64.dll (or ARM64 equivalent),
185
+ or None if not found or not on Windows.
186
+
187
+ Example:
188
+ >>> dll_path = get_asan_runtime_dll()
189
+ >>> if dll_path:
190
+ ... shutil.copy(dll_path, build_dir / dll_path.name)
191
+ ... # Now Meson tests will find the ASAN DLL in build_dir
192
+
193
+ Note:
194
+ This function ensures the toolchain is downloaded before searching.
195
+ The DLL is typically located in the MinGW sysroot bin directory:
196
+ ~/.clang-tool-chain/clang/win/x86_64/x86_64-w64-mingw32/bin/
197
+
198
+ See Also:
199
+ get_runtime_dll_paths: Returns directories containing runtime DLLs
200
+ prepare_sanitizer_environment: Adds DLL paths to PATH
201
+ """
202
+ if platform.system() != "Windows":
203
+ logger.debug("get_asan_runtime_dll: Not on Windows, returning None")
204
+ return None
205
+
206
+ try:
207
+ from clang_tool_chain.platform.detection import get_platform_binary_dir, get_platform_info
208
+
209
+ # Get platform info for sysroot lookup
210
+ _platform_name, arch = get_platform_info()
211
+
212
+ # Get the clang root directory
213
+ clang_bin_dir = get_platform_binary_dir()
214
+ clang_root = clang_bin_dir.parent
215
+
216
+ # Determine sysroot and DLL name based on architecture
217
+ if arch == "x86_64":
218
+ sysroot_name = "x86_64-w64-mingw32"
219
+ dll_name = "libclang_rt.asan_dynamic-x86_64.dll"
220
+ elif arch == "arm64":
221
+ sysroot_name = "aarch64-w64-mingw32"
222
+ dll_name = "libclang_rt.asan_dynamic-aarch64.dll"
223
+ else:
224
+ logger.debug(f"get_asan_runtime_dll: Unsupported architecture {arch}")
225
+ return None
226
+
227
+ # Check MinGW sysroot bin directory first (primary location)
228
+ sysroot_bin = clang_root / sysroot_name / "bin"
229
+ dll_path = sysroot_bin / dll_name
230
+ if dll_path.exists():
231
+ logger.debug(f"Found ASAN runtime DLL: {dll_path}")
232
+ return dll_path
233
+
234
+ # Fallback: check clang bin directory
235
+ dll_path = clang_bin_dir / dll_name
236
+ if dll_path.exists():
237
+ logger.debug(f"Found ASAN runtime DLL (fallback): {dll_path}")
238
+ return dll_path
239
+
240
+ # Try glob pattern for any ASAN DLL (version may vary)
241
+ for search_dir in [sysroot_bin, clang_bin_dir]:
242
+ if search_dir.exists():
243
+ for dll_file in search_dir.glob("libclang_rt.asan*.dll"):
244
+ logger.debug(f"Found ASAN runtime DLL (glob): {dll_file}")
245
+ return dll_file
246
+
247
+ logger.debug(f"ASAN runtime DLL not found in {sysroot_bin} or {clang_bin_dir}")
248
+ return None
249
+
250
+ except (ImportError, RuntimeError) as e:
251
+ logger.debug(f"Could not get ASAN runtime DLL path: {e}")
252
+ return None
253
+
254
+
255
+ def get_all_sanitizer_runtime_dlls() -> list[Path]:
256
+ """
257
+ Get all sanitizer runtime DLLs (Windows only).
258
+
259
+ This function locates all shared sanitizer runtime DLLs, including:
260
+ - Address Sanitizer (ASAN)
261
+ - Undefined Behavior Sanitizer (UBSAN)
262
+ - Thread Sanitizer (TSAN) - if available
263
+
264
+ This is useful for projects that want to copy all sanitizer DLLs to
265
+ their build directory to ensure all instrumented code can run.
266
+
267
+ Returns:
268
+ List of Paths to sanitizer runtime DLLs, or empty list if not
269
+ found or not on Windows.
270
+
271
+ Example:
272
+ >>> dlls = get_all_sanitizer_runtime_dlls()
273
+ >>> for dll in dlls:
274
+ ... shutil.copy(dll, build_dir / dll.name)
275
+
276
+ See Also:
277
+ get_asan_runtime_dll: Returns just the ASAN DLL path
278
+ """
279
+ if platform.system() != "Windows":
280
+ return []
281
+
282
+ dlls: list[Path] = []
283
+
284
+ try:
285
+ from clang_tool_chain.platform.detection import get_platform_binary_dir, get_platform_info
286
+
287
+ # Get platform info for sysroot lookup
288
+ _platform_name, arch = get_platform_info()
289
+
290
+ # Get the clang root directory
291
+ clang_bin_dir = get_platform_binary_dir()
292
+ clang_root = clang_bin_dir.parent
293
+
294
+ # Determine sysroot based on architecture
295
+ if arch == "x86_64":
296
+ sysroot_name = "x86_64-w64-mingw32"
297
+ elif arch == "arm64":
298
+ sysroot_name = "aarch64-w64-mingw32"
299
+ else:
300
+ return []
301
+
302
+ # Search directories
303
+ search_dirs = [
304
+ clang_root / sysroot_name / "bin",
305
+ clang_bin_dir,
306
+ ]
307
+
308
+ # Patterns for sanitizer DLLs
309
+ patterns = [
310
+ "libclang_rt.asan*.dll", # Address Sanitizer
311
+ "libclang_rt.ubsan*.dll", # Undefined Behavior Sanitizer
312
+ "libclang_rt.tsan*.dll", # Thread Sanitizer
313
+ "libclang_rt.lsan*.dll", # Leak Sanitizer (standalone)
314
+ ]
315
+
316
+ seen_names: set[str] = set()
317
+ for search_dir in search_dirs:
318
+ if search_dir.exists():
319
+ for pattern in patterns:
320
+ for dll_file in search_dir.glob(pattern):
321
+ if dll_file.name not in seen_names:
322
+ dlls.append(dll_file)
323
+ seen_names.add(dll_file.name)
324
+ logger.debug(f"Found sanitizer DLL: {dll_file}")
325
+
326
+ except (ImportError, RuntimeError) as e:
327
+ logger.debug(f"Could not get sanitizer runtime DLLs: {e}")
328
+
329
+ return dlls
330
+
331
+
134
332
  def detect_sanitizers_from_flags(compiler_flags: list[str]) -> tuple[bool, bool]:
135
333
  """
136
334
  Detect which sanitizers are enabled from compiler flags.
@@ -263,8 +461,9 @@ def prepare_sanitizer_environment(
263
461
 
264
462
  # Inject ASAN_OPTIONS if ASAN is enabled and not already set by user
265
463
  if asan_enabled and "ASAN_OPTIONS" not in env:
266
- env["ASAN_OPTIONS"] = DEFAULT_ASAN_OPTIONS
267
- logger.info(f"Injecting ASAN_OPTIONS={DEFAULT_ASAN_OPTIONS}")
464
+ asan_options = get_default_asan_options()
465
+ env["ASAN_OPTIONS"] = asan_options
466
+ logger.info(f"Injecting ASAN_OPTIONS={asan_options}")
268
467
 
269
468
  # Inject LSAN_OPTIONS if LSAN is enabled and not already set by user
270
469
  if lsan_enabled and "LSAN_OPTIONS" not in env:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clang-tool-chain
3
- Version: 1.1.5
3
+ Version: 1.1.7
4
4
  Summary: Clang Tool Chain - C/C++ compilation toolchain utilities
5
5
  Project-URL: Homepage, https://github.com/zackees/clang-tool-chain
6
6
  Project-URL: Repository, https://github.com/zackees/clang-tool-chain
@@ -1,5 +1,5 @@
1
- clang_tool_chain/__init__.py,sha256=nLK5yA3seauLHvtQN3Qfe8_XLfbs8b-noek_3baRRZc,936
2
- clang_tool_chain/__version__.py,sha256=jG7OiD1U-R4k5RPrITUrVwY2AnwCm3EQkm__FP_IjMI,71
1
+ clang_tool_chain/__init__.py,sha256=Ac2qUqz9rzFHvXLkH6kqf63m-1JywYcJckKrbLft2ag,1125
2
+ clang_tool_chain/__version__.py,sha256=gVI5QWADLkUhsYHs8TuVovVei5SJ_bx5saZRIWgkOTU,71
3
3
  clang_tool_chain/archive.py,sha256=t3reh7cm5XP2rhTqfRIDAQZv5XQq7SsstyiROYg8wFA,27697
4
4
  clang_tool_chain/archive_cache.py,sha256=5ZmlwXIJZDcrDFkTbdgBQYN9sulGn0WyI6qwWqC4HEU,6806
5
5
  clang_tool_chain/checksums.py,sha256=KFXeAeDz5ZlcZVOxsHDpNDCrm9UDoJ8bMA4PeNhuzdA,9868
@@ -49,7 +49,7 @@ clang_tool_chain/execution/iwyu.py,sha256=bmP0d_PZObA1JfmFYp3qIOKCb7y32AWPm2_ReF
49
49
  clang_tool_chain/execution/lldb.py,sha256=VpxkWTPS6PsyskaKTALeziR5Z5NLwarW174Fm1SMX9k,20718
50
50
  clang_tool_chain/execution/nodejs_resolver.py,sha256=8QsJWvIfmt5mBDV7n0ypSjsPyXS-eZTizhBli937I-g,11172
51
51
  clang_tool_chain/execution/platform_executor.py,sha256=sF4GyW0ujy2EewG8y2Eo1gUWGzss5G5iIkv02w7-2_o,14362
52
- clang_tool_chain/execution/sanitizer_env.py,sha256=OE00wOEaLm-HIWL1fdjhQWEZ9D1hVN3bYfMxUEo8ZiQ,13364
52
+ clang_tool_chain/execution/sanitizer_env.py,sha256=IHxmeAzbbdrIAz38c2U3erunTVjHjePx7BytVBzluB4,20766
53
53
  clang_tool_chain/installers/__init__.py,sha256=NAV5woPCEDKSbFr1UmfQsrg4Ua5UdghN4q7H3ymvRsg,279
54
54
  clang_tool_chain/installers/base.py,sha256=OS78bau9zoYPitmhla7pKsfCPEj-zLY0DkvVzjE31Tw,15437
55
55
  clang_tool_chain/installers/clang.py,sha256=rUtheVRF7mq_1YdmQ3XzIybrJqsHbm2Xf0cbhRbH7RQ,16994
@@ -71,8 +71,8 @@ clang_tool_chain/symbolizer/unwind_windows.h,sha256=XTWhJDv13AAMUPAzWCfRN7tO6EbN
71
71
  clang_tool_chain/testing/__init__.py,sha256=-sYqOOCuTV_u-MkmExrD4uKdTHG4RmMwR3D1kIG281Q,208
72
72
  clang_tool_chain/testing/diagnostic_runner.py,sha256=mnmFUEOQulY3-Ggu6hKVGZwjrKQNmV6kY80PRTUu2qU,5293
73
73
  clang_tool_chain/testing/diagnostic_tests.py,sha256=GmtKWrDcddZTpx9_yIKfhRAy6YOde8dj7SksCWVEME4,6019
74
- clang_tool_chain-1.1.5.dist-info/METADATA,sha256=V3_teL2iXVtyGp-CJKBjeYgC2UhYj0KlTXc2d9pWZtQ,60267
75
- clang_tool_chain-1.1.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
76
- clang_tool_chain-1.1.5.dist-info/entry_points.txt,sha256=N0a0OVPkCFbf6BisRkHj-m2TcZ-f1mqxfXxAHQxfrQg,2800
77
- clang_tool_chain-1.1.5.dist-info/licenses/LICENSE,sha256=51FO1oc2pZbQNI0v0_THnznnZIF4iFgawG1xnQ58kKo,10997
78
- clang_tool_chain-1.1.5.dist-info/RECORD,,
74
+ clang_tool_chain-1.1.7.dist-info/METADATA,sha256=m33JQp6EzIWtJsAFjwat9lcI-kGIXmh902VQZ2IQwb8,60267
75
+ clang_tool_chain-1.1.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
76
+ clang_tool_chain-1.1.7.dist-info/entry_points.txt,sha256=N0a0OVPkCFbf6BisRkHj-m2TcZ-f1mqxfXxAHQxfrQg,2800
77
+ clang_tool_chain-1.1.7.dist-info/licenses/LICENSE,sha256=51FO1oc2pZbQNI0v0_THnznnZIF4iFgawG1xnQ58kKo,10997
78
+ clang_tool_chain-1.1.7.dist-info/RECORD,,