clang-tool-chain 1.1.2__py3-none-any.whl → 1.1.4__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,3 +1,3 @@
1
1
  """Version information for clang-tool-chain."""
2
2
 
3
- __version__ = "1.1.2"
3
+ __version__ = "1.1.4"
@@ -26,13 +26,20 @@ CONTROLLABLE_FEATURES = {
26
26
  "DIRECTIVES": "Inlined build directives (@link, @std, @cflags)",
27
27
  "SHARED_ASAN": "Automatic -shared-libasan injection (Linux)",
28
28
  "SANITIZER_ENV": "Automatic ASAN_OPTIONS/LSAN_OPTIONS injection",
29
- "SANITIZER_NOTE": "Sanitizer flag injection note to stderr",
30
29
  "RPATH": "Automatic rpath injection for library loading",
31
30
  "SYSROOT": "Automatic macOS SDK detection (-isysroot)",
32
31
  "DEPLOY_LIBS": "Cross-platform library deployment (all outputs)",
33
32
  "DEPLOY_SHARED_LIB": "Library deployment for shared library outputs only (.dll, .so, .dylib)",
34
33
  "BUNDLED_UNWIND": "Bundled libunwind paths on Linux",
35
34
  "MACOS_UNWIND_FIX": "Automatic -lunwind removal on macOS (libunwind in libSystem)",
35
+ # Sanitizer notes (hierarchical)
36
+ "SANITIZER_NOTE": "All sanitizer-related notes (category master)",
37
+ "SHARED_ASAN_NOTE": "-shared-libasan injection note",
38
+ "ALLOW_SHLIB_UNDEFINED_NOTE": "-Wl,--allow-shlib-undefined injection note",
39
+ # Linker notes (hierarchical)
40
+ "LINKER_NOTE": "All linker-related notes (category master)",
41
+ "LINKER_COMPAT_NOTE": "Removed GNU linker flags note",
42
+ "LD64_LLD_CONVERT_NOTE": "-fuse-ld=ld64.lld conversion note",
36
43
  }
37
44
 
38
45
 
@@ -137,3 +144,54 @@ def log_disabled_features_summary() -> None:
137
144
  logger.info("All automatic features disabled via CLANG_TOOL_CHAIN_NO_AUTO=1")
138
145
  else:
139
146
  logger.info(f"Disabled features: {', '.join(disabled)}")
147
+
148
+
149
+ def is_note_disabled(specific: str, category: str | None = None) -> bool:
150
+ """
151
+ Check if a specific note is disabled using hierarchical suppression.
152
+
153
+ A note is disabled if ANY of:
154
+ 1. CLANG_TOOL_CHAIN_NO_AUTO=1 (global master)
155
+ 2. CLANG_TOOL_CHAIN_NO_{category}=1 (category master, if provided)
156
+ 3. CLANG_TOOL_CHAIN_NO_{specific}=1 (specific note)
157
+
158
+ This allows users to:
159
+ - Disable all automatic features with NO_AUTO=1
160
+ - Disable a category of notes (e.g., all sanitizer notes) with NO_SANITIZER_NOTE=1
161
+ - Disable a specific note with its dedicated variable (e.g., NO_SHARED_ASAN_NOTE=1)
162
+
163
+ Args:
164
+ specific: The specific note name (e.g., "SHARED_ASAN_NOTE")
165
+ category: Optional category master (e.g., "SANITIZER_NOTE")
166
+
167
+ Returns:
168
+ True if the note should be suppressed
169
+
170
+ Example:
171
+ >>> os.environ["CLANG_TOOL_CHAIN_NO_SANITIZER_NOTE"] = "1"
172
+ >>> is_note_disabled("SHARED_ASAN_NOTE", "SANITIZER_NOTE")
173
+ True # Disabled via category
174
+
175
+ >>> os.environ["CLANG_TOOL_CHAIN_NO_SHARED_ASAN_NOTE"] = "1"
176
+ >>> is_note_disabled("SHARED_ASAN_NOTE", "SANITIZER_NOTE")
177
+ True # Disabled via specific variable
178
+ """
179
+ # Check the global master (NO_AUTO)
180
+ if is_auto_disabled():
181
+ logger.debug(f"Note {specific} disabled via CLANG_TOOL_CHAIN_NO_AUTO=1")
182
+ return True
183
+
184
+ # Check the category master (if provided)
185
+ if category:
186
+ var_name = f"CLANG_TOOL_CHAIN_NO_{category}"
187
+ if _is_truthy(os.environ.get(var_name)):
188
+ logger.debug(f"Note {specific} disabled via {var_name}=1 (category master)")
189
+ return True
190
+
191
+ # Check the specific note variable
192
+ var_name = f"CLANG_TOOL_CHAIN_NO_{specific}"
193
+ if _is_truthy(os.environ.get(var_name)):
194
+ logger.debug(f"Note {specific} disabled via {var_name}=1")
195
+ return True
196
+
197
+ return False
@@ -39,7 +39,7 @@ from dataclasses import dataclass
39
39
  from pathlib import Path
40
40
  from typing import TYPE_CHECKING
41
41
 
42
- from clang_tool_chain.env_utils import is_feature_disabled
42
+ from clang_tool_chain.env_utils import is_feature_disabled, is_note_disabled
43
43
 
44
44
  if TYPE_CHECKING:
45
45
  from clang_tool_chain.directives.parser import ParsedDirectives
@@ -487,11 +487,20 @@ class ASANRuntimeTransformer(ArgumentTransformer):
487
487
  result = ["-Wl,--allow-shlib-undefined"] + result
488
488
  injected_flags.append("-Wl,--allow-shlib-undefined")
489
489
 
490
- # Warn on stderr if we injected flags (unless disabled)
491
- if injected_flags and not is_feature_disabled("SANITIZER_NOTE"):
490
+ # Emit individual notes for each injected flag (hierarchical suppression)
491
+ if "-shared-libasan" in injected_flags and not is_note_disabled("SHARED_ASAN_NOTE", "SANITIZER_NOTE"):
492
492
  print(
493
- f"clang-tool-chain: note: automatically injected sanitizer flags: {' '.join(injected_flags)} "
494
- "(disable with CLANG_TOOL_CHAIN_NO_SANITIZER_NOTE=1)",
493
+ "clang-tool-chain: note: automatically injected -shared-libasan for ASAN runtime linking "
494
+ "(disable with CLANG_TOOL_CHAIN_NO_SHARED_ASAN_NOTE=1)",
495
+ file=sys.stderr,
496
+ )
497
+
498
+ if "-Wl,--allow-shlib-undefined" in injected_flags and not is_note_disabled(
499
+ "ALLOW_SHLIB_UNDEFINED_NOTE", "SANITIZER_NOTE"
500
+ ):
501
+ print(
502
+ "clang-tool-chain: note: automatically injected -Wl,--allow-shlib-undefined for shared library ASAN "
503
+ "(disable with CLANG_TOOL_CHAIN_NO_ALLOW_SHLIB_UNDEFINED_NOTE=1)",
495
504
  file=sys.stderr,
496
505
  )
497
506
 
@@ -160,9 +160,10 @@ def prepare_sanitizer_environment(
160
160
  compiler_flags: List of compiler flags used to build the executable.
161
161
  Used to detect which sanitizers are enabled. If None, no options
162
162
  are injected (safe default).
163
- suppression_file: Optional path to custom LSan suppression file.
164
- If None, uses built-in platform-specific suppressions.
165
- Set to empty string "" to disable built-in suppressions.
163
+ suppression_file: Optional path to additional custom LSan suppression file.
164
+ If provided, this file is merged with built-in platform-specific
165
+ suppressions (built-in applied first, then custom).
166
+ Set to empty string "" to disable built-in suppressions entirely.
166
167
 
167
168
  Returns:
168
169
  Environment dictionary with sanitizer options injected as appropriate.
@@ -184,7 +185,7 @@ def prepare_sanitizer_environment(
184
185
  ... compiler_flags=["-fsanitize=address"],
185
186
  ... suppression_file="/path/to/custom.txt"
186
187
  ... )
187
- >>> # Uses custom suppression file instead of built-in
188
+ >>> # Uses BOTH built-in AND custom suppression files (merged)
188
189
  """
189
190
  env = base_env.copy() if base_env is not None else os.environ.copy()
190
191
 
@@ -225,22 +226,33 @@ def prepare_sanitizer_environment(
225
226
 
226
227
  # Add platform-specific LSan suppressions if LSAN is enabled
227
228
  if lsan_enabled:
228
- # Use built-in suppression file if no custom file specified
229
- if suppression_file is None:
230
- suppression_file = _get_builtin_suppression_file()
229
+ # Check if user explicitly disabled built-in suppressions with ""
230
+ disable_builtin = suppression_file == ""
231
231
 
232
- # Apply suppression file if it exists (unless explicitly disabled with "")
233
- if suppression_file and suppression_file != "" and Path(suppression_file).exists():
232
+ # Helper to append suppression file to LSAN_OPTIONS
233
+ def _append_suppression(file_path: Path) -> None:
234
234
  current_lsan = env.get("LSAN_OPTIONS", "")
235
- suppression_opt = f"suppressions={Path(suppression_file).absolute()}"
235
+ suppression_opt = f"suppressions={file_path.absolute()}"
236
236
 
237
237
  if current_lsan:
238
- # Append to existing options
239
238
  env["LSAN_OPTIONS"] = f"{current_lsan}:{suppression_opt}"
240
239
  else:
241
- # Set new options
242
240
  env["LSAN_OPTIONS"] = suppression_opt
243
241
 
244
- logger.info(f"Injecting LSan suppression file: {suppression_file}")
242
+ logger.info(f"Injecting LSan suppression file: {file_path}")
243
+
244
+ # First, apply built-in platform-specific suppressions (unless disabled)
245
+ if not disable_builtin:
246
+ builtin_file = _get_builtin_suppression_file()
247
+ if builtin_file and builtin_file.exists():
248
+ _append_suppression(builtin_file)
249
+
250
+ # Then, also apply custom suppression file if provided (merge behavior)
251
+ if suppression_file and suppression_file != "":
252
+ custom_path = Path(suppression_file)
253
+ if custom_path.exists():
254
+ _append_suppression(custom_path)
255
+ else:
256
+ logger.warning(f"Custom suppression file not found: {suppression_file}")
245
257
 
246
258
  return env
@@ -12,7 +12,7 @@ import logging
12
12
  import os
13
13
  import sys
14
14
 
15
- from clang_tool_chain.env_utils import is_feature_disabled
15
+ from clang_tool_chain.env_utils import is_note_disabled
16
16
  from clang_tool_chain.interrupt_utils import handle_keyboard_interrupt_properly
17
17
  from clang_tool_chain.llvm_versions import get_llvm_version_tuple, supports_ld64_lld_flag
18
18
 
@@ -272,10 +272,8 @@ def _translate_linker_flags_for_macos_lld(args: list[str]) -> list[str]:
272
272
 
273
273
  i += 1
274
274
 
275
- # Emit warning for removed flags (unless silenced)
276
- if removed_flags and not is_feature_disabled("LINKER_COMPAT_NOTE"):
277
- import sys
278
-
275
+ # Emit warning for removed flags (unless silenced via hierarchical suppression)
276
+ if removed_flags and not is_note_disabled("LINKER_COMPAT_NOTE", "LINKER_NOTE"):
279
277
  print(
280
278
  f"clang-tool-chain: note: removed GNU linker flags not supported by ld64.lld: "
281
279
  f"{', '.join(removed_flags)} (disable with CLANG_TOOL_CHAIN_NO_LINKER_COMPAT_NOTE=1)",
@@ -379,11 +377,13 @@ def _add_lld_linker_if_needed(platform_name: str, args: list[str]) -> list[str]:
379
377
  # Check if user specified -fuse-ld=ld64.lld (which is not a valid clang driver option)
380
378
  # and emit a warning about the auto-conversion to -fuse-ld=lld
381
379
  if _user_specified_ld64_lld(args):
382
- print(
383
- "[clang-tool-chain] Warning: -fuse-ld=ld64.lld is not a valid clang driver option. "
384
- "Auto-converting to -fuse-ld=lld (clang driver auto-dispatches to ld64.lld on Darwin).",
385
- file=sys.stderr,
386
- )
380
+ if not is_note_disabled("LD64_LLD_CONVERT_NOTE", "LINKER_NOTE"):
381
+ print(
382
+ "clang-tool-chain: warning: -fuse-ld=ld64.lld is not a valid clang driver option. "
383
+ "Auto-converting to -fuse-ld=lld (clang driver auto-dispatches to ld64.lld on Darwin). "
384
+ "(disable with CLANG_TOOL_CHAIN_NO_LD64_LLD_CONVERT_NOTE=1)",
385
+ file=sys.stderr,
386
+ )
387
387
  args = _convert_ld64_lld_to_lld(args)
388
388
 
389
389
  return _translate_linker_flags_for_macos_lld(args)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clang-tool-chain
3
- Version: 1.1.2
3
+ Version: 1.1.4
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
1
  clang_tool_chain/__init__.py,sha256=u-qgOuQxh5W2g7n8BgUtBnUWsK66rM4N6LJXY9PiEx0,880
2
- clang_tool_chain/__version__.py,sha256=QdDf2Y_Q6wfrydeJ6-C_vCqCore3Rs1Q1qnCfaTFRNQ,71
2
+ clang_tool_chain/__version__.py,sha256=OZTe0l-1KRXG_B5GhtooBTlUxPJy68FJ5pyGG4KC95U,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
@@ -9,7 +9,7 @@ clang_tool_chain/cli_parsers.py,sha256=cHVDyW75N_Kao1VYeAgw_L-1K65DjyvWUigQScTFi
9
9
  clang_tool_chain/component_db.py,sha256=ohtlycsrEokui83iZyPsTyxmvXgkD7_OpVwAn1Cq8gI,9096
10
10
  clang_tool_chain/downloader.py,sha256=fqErxTaI3oEYbloLZnrWXJ26j2iGOngPnl4i8kqOWNs,6041
11
11
  clang_tool_chain/env_breadcrumbs.py,sha256=bvPTz8xABILhzrXTEBzdGrSbpEXLf2YVgcYEe-IdhNY,2335
12
- clang_tool_chain/env_utils.py,sha256=DVyvoD2xqJwA2LYt7MqnvFSBJiTLOaicCDribFoHTg0,4380
12
+ clang_tool_chain/env_utils.py,sha256=XFcjc_tJWiHLb_o90D0G3t_mT42X2kVLP6rwaIxfOO0,6679
13
13
  clang_tool_chain/fetch.py,sha256=DwsNl5DZkNqEYXL-FbCTnp6IA2iCAa9pMl5oPjyuOS4,4696
14
14
  clang_tool_chain/installer.py,sha256=GuGeUvVcAw4HMj9jrub-I11ixmksw-vgtSOFrlupmPA,3323
15
15
  clang_tool_chain/interrupt_utils.py,sha256=7YvazvGzyItRVDZ_pzUSK6at8PCw-Dgih69HLSz0tT4,1153
@@ -39,7 +39,7 @@ clang_tool_chain/deployment/so_deployer.py,sha256=eAygmGojioi1iz5cHeqmKjJ5fI-5Xo
39
39
  clang_tool_chain/directives/__init__.py,sha256=MJDNYL_MD2MF0HFsrTsSTX645bYo6vtjq2pOTtfykaU,198
40
40
  clang_tool_chain/directives/parser.py,sha256=6J7mO1JtvuHkkKS0Xges5b_jT9b3uTF6ULI0ZiwGAdw,11179
41
41
  clang_tool_chain/execution/__init__.py,sha256=fFQEW9VejCdbBvt4quNJ2X8udh_PKgewTfzUXHmXzyc,940
42
- clang_tool_chain/execution/arg_transformers.py,sha256=NOuU3WheufJA2MVS79kWtStiL_db-LmdHXPm7GFKEqA,25773
42
+ clang_tool_chain/execution/arg_transformers.py,sha256=Vut8XHp4IHkEUhVRI-NSvFaX6EvrGDd3FCEHbDe9gHo,26268
43
43
  clang_tool_chain/execution/build.py,sha256=YHS1BJTZg5pBS9czVko41mBdfswSPad5hxfitMoLvsI,13275
44
44
  clang_tool_chain/execution/build_pipeline.py,sha256=ORJEJ8WYp8c7bhWAa-e3w_ySXwenpUczlmXgoGByToY,17823
45
45
  clang_tool_chain/execution/core.py,sha256=7CJ0azznC5lq5bw8amk2kwCIN2I_OnDiKytpapkvrdY,25273
@@ -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=-Gg852-n3YzPhq0D70YCds4BCCqoCjilWnAYRZzrx9k,10084
52
+ clang_tool_chain/execution/sanitizer_env.py,sha256=bLGUATKNnuB8WxWt1eopVgEh6bsZzkmpcpGxYOeRcHk,10642
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
@@ -59,7 +59,7 @@ clang_tool_chain/installers/iwyu.py,sha256=9aAhdGtOTY6BrLuPtladY8Y2mz1i7FjgbMxZf
59
59
  clang_tool_chain/installers/lldb.py,sha256=FpG8NMNQk8PoNfg6aeU_plmSQrVET7zo-pTvoK8z838,2261
60
60
  clang_tool_chain/installers/nodejs.py,sha256=5N07rotgmCfUaDm1uJfBlIAFKC1iTpgZT0HBRuoYwKI,9343
61
61
  clang_tool_chain/linker/__init__.py,sha256=ghzDFpZ2-gPmdDO6K05C7yNbY6pZLANPuUks9TaQwVY,537
62
- clang_tool_chain/linker/lld.py,sha256=OQLmCLNbj2BU0l5HxtHegHvXvblPITg8Gkm_EvJorKw,15381
62
+ clang_tool_chain/linker/lld.py,sha256=PaJ2tuo95t79BCaAIu3E_NPSrv1F24-4N0MJKwfrybo,15577
63
63
  clang_tool_chain/platform/__init__.py,sha256=WkV9Y25ua0mtzEGcsIxF-qExtroSTAMKkcElWuQF2BE,342
64
64
  clang_tool_chain/platform/detection.py,sha256=PLHyUfmQ5xuohhpz0KSXJWK3d0u0fCsjx1DbM8f1CxQ,5470
65
65
  clang_tool_chain/platform/paths.py,sha256=K0IjeVwbmgPlAWQO8mS3r1WS4C2dN6IYrSqPpckeT5c,6088
@@ -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.2.dist-info/METADATA,sha256=XvG34S1grw40mal9rG5dGnwlfnrALxatwQMzFwQkIio,60267
75
- clang_tool_chain-1.1.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
76
- clang_tool_chain-1.1.2.dist-info/entry_points.txt,sha256=N0a0OVPkCFbf6BisRkHj-m2TcZ-f1mqxfXxAHQxfrQg,2800
77
- clang_tool_chain-1.1.2.dist-info/licenses/LICENSE,sha256=51FO1oc2pZbQNI0v0_THnznnZIF4iFgawG1xnQ58kKo,10997
78
- clang_tool_chain-1.1.2.dist-info/RECORD,,
74
+ clang_tool_chain-1.1.4.dist-info/METADATA,sha256=EQviHfowQcUB26PHuj-VYtH5YfTNoE1b2D8DOXArOT8,60267
75
+ clang_tool_chain-1.1.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
76
+ clang_tool_chain-1.1.4.dist-info/entry_points.txt,sha256=N0a0OVPkCFbf6BisRkHj-m2TcZ-f1mqxfXxAHQxfrQg,2800
77
+ clang_tool_chain-1.1.4.dist-info/licenses/LICENSE,sha256=51FO1oc2pZbQNI0v0_THnznnZIF4iFgawG1xnQ58kKo,10997
78
+ clang_tool_chain-1.1.4.dist-info/RECORD,,