clang-tool-chain 1.0.45__py3-none-any.whl → 1.1.0__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.
- clang_tool_chain/__version__.py +1 -1
- clang_tool_chain/deployment/libdeploy.py +287 -0
- clang_tool_chain/deployment/so_deployer.py +15 -0
- clang_tool_chain/env_utils.py +1 -0
- clang_tool_chain/execution/arg_transformers.py +112 -20
- clang_tool_chain/linker/lld.py +42 -12
- {clang_tool_chain-1.0.45.dist-info → clang_tool_chain-1.1.0.dist-info}/METADATA +167 -18
- {clang_tool_chain-1.0.45.dist-info → clang_tool_chain-1.1.0.dist-info}/RECORD +11 -10
- {clang_tool_chain-1.0.45.dist-info → clang_tool_chain-1.1.0.dist-info}/entry_points.txt +1 -0
- {clang_tool_chain-1.0.45.dist-info → clang_tool_chain-1.1.0.dist-info}/WHEEL +0 -0
- {clang_tool_chain-1.0.45.dist-info → clang_tool_chain-1.1.0.dist-info}/licenses/LICENSE +0 -0
clang_tool_chain/__version__.py
CHANGED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Library deployment CLI for deploying runtime dependencies after the fact.
|
|
3
|
+
|
|
4
|
+
This module provides a command-line interface to deploy library dependencies
|
|
5
|
+
for already-built executables and shared libraries. It supports:
|
|
6
|
+
- Windows: .exe and .dll files (MinGW runtime DLLs)
|
|
7
|
+
- Linux: executables and .so files (libc++, libunwind, etc.)
|
|
8
|
+
- macOS: executables and .dylib files (libc++, libunwind, etc.)
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
clang-tool-chain-libdeploy myprogram.exe
|
|
12
|
+
clang-tool-chain-libdeploy mylib.dll
|
|
13
|
+
clang-tool-chain-libdeploy myprogram
|
|
14
|
+
clang-tool-chain-libdeploy mylib.so
|
|
15
|
+
clang-tool-chain-libdeploy mylib.dylib
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import logging
|
|
20
|
+
import sys
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
from clang_tool_chain.interrupt_utils import handle_keyboard_interrupt_properly
|
|
24
|
+
|
|
25
|
+
logger = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _setup_logging(verbose: bool) -> None:
|
|
29
|
+
"""Configure logging based on verbosity."""
|
|
30
|
+
level = logging.DEBUG if verbose else logging.INFO
|
|
31
|
+
logging.basicConfig(
|
|
32
|
+
level=level,
|
|
33
|
+
format="%(message)s",
|
|
34
|
+
stream=sys.stderr,
|
|
35
|
+
)
|
|
36
|
+
# Also set the deployment module loggers
|
|
37
|
+
logging.getLogger("clang_tool_chain.deployment").setLevel(level)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _detect_binary_type(binary_path: Path) -> tuple[str, str]:
|
|
41
|
+
"""
|
|
42
|
+
Detect the binary type and platform from file extension and magic bytes.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
binary_path: Path to the binary file
|
|
46
|
+
|
|
47
|
+
Returns:
|
|
48
|
+
Tuple of (platform, binary_type) where:
|
|
49
|
+
- platform: "windows", "linux", or "darwin"
|
|
50
|
+
- binary_type: "executable" or "shared_library"
|
|
51
|
+
|
|
52
|
+
Raises:
|
|
53
|
+
ValueError: If binary type cannot be determined
|
|
54
|
+
"""
|
|
55
|
+
suffix = binary_path.suffix.lower()
|
|
56
|
+
|
|
57
|
+
# Windows binaries
|
|
58
|
+
if suffix == ".exe":
|
|
59
|
+
return ("windows", "executable")
|
|
60
|
+
if suffix == ".dll":
|
|
61
|
+
return ("windows", "shared_library")
|
|
62
|
+
|
|
63
|
+
# macOS binaries
|
|
64
|
+
if suffix == ".dylib":
|
|
65
|
+
return ("darwin", "shared_library")
|
|
66
|
+
|
|
67
|
+
# Linux shared libraries (including versioned: .so.1, .so.1.2.3)
|
|
68
|
+
if suffix == ".so" or ".so." in binary_path.name:
|
|
69
|
+
return ("linux", "shared_library")
|
|
70
|
+
|
|
71
|
+
# No extension - could be Linux/macOS executable or a .so with version
|
|
72
|
+
# Try to detect from magic bytes
|
|
73
|
+
if binary_path.exists() and binary_path.is_file():
|
|
74
|
+
try:
|
|
75
|
+
with open(binary_path, "rb") as f:
|
|
76
|
+
magic = f.read(4)
|
|
77
|
+
|
|
78
|
+
# ELF magic: 0x7f 'E' 'L' 'F'
|
|
79
|
+
if magic[:4] == b"\x7fELF":
|
|
80
|
+
return ("linux", "executable")
|
|
81
|
+
|
|
82
|
+
# Mach-O magic numbers
|
|
83
|
+
# MH_MAGIC (32-bit): 0xfeedface
|
|
84
|
+
# MH_MAGIC_64 (64-bit): 0xfeedfacf
|
|
85
|
+
# Fat binary: 0xcafebabe
|
|
86
|
+
if magic[:4] in (b"\xfe\xed\xfa\xce", b"\xfe\xed\xfa\xcf", b"\xcf\xfa\xed\xfe", b"\xce\xfa\xed\xfe"):
|
|
87
|
+
return ("darwin", "executable")
|
|
88
|
+
if magic[:4] == b"\xca\xfe\xba\xbe":
|
|
89
|
+
return ("darwin", "executable")
|
|
90
|
+
|
|
91
|
+
# PE magic: 'MZ'
|
|
92
|
+
if magic[:2] == b"MZ":
|
|
93
|
+
return ("windows", "executable")
|
|
94
|
+
|
|
95
|
+
except (OSError, PermissionError) as e:
|
|
96
|
+
logger.debug(f"Could not read magic bytes: {e}")
|
|
97
|
+
|
|
98
|
+
raise ValueError(
|
|
99
|
+
f"Cannot determine binary type for: {binary_path}\n"
|
|
100
|
+
"Supported formats: .exe, .dll (Windows), .so (Linux), .dylib (macOS), "
|
|
101
|
+
"or ELF/Mach-O executables without extension"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def deploy_dependencies(
|
|
106
|
+
binary_path: Path,
|
|
107
|
+
platform_override: str | None = None,
|
|
108
|
+
arch: str | None = None,
|
|
109
|
+
verbose: bool = False,
|
|
110
|
+
dry_run: bool = False,
|
|
111
|
+
) -> int:
|
|
112
|
+
"""
|
|
113
|
+
Deploy library dependencies for a binary.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
binary_path: Path to executable or shared library
|
|
117
|
+
platform_override: Override auto-detected platform ("windows", "linux", "darwin")
|
|
118
|
+
arch: Target architecture (default: auto-detect from current platform)
|
|
119
|
+
verbose: Enable verbose output
|
|
120
|
+
dry_run: If True, only show what would be deployed without actually copying
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
Number of libraries deployed, or -1 on error
|
|
124
|
+
"""
|
|
125
|
+
from clang_tool_chain.deployment.factory import create_deployer
|
|
126
|
+
from clang_tool_chain.platform.detection import get_platform_info
|
|
127
|
+
|
|
128
|
+
# Get architecture if not specified
|
|
129
|
+
if arch is None:
|
|
130
|
+
_, arch = get_platform_info()
|
|
131
|
+
|
|
132
|
+
# Detect or use override for platform
|
|
133
|
+
if platform_override:
|
|
134
|
+
platform = platform_override.lower()
|
|
135
|
+
if platform not in ("windows", "linux", "darwin", "win", "win32", "macos"):
|
|
136
|
+
logger.error(f"Invalid platform: {platform_override}")
|
|
137
|
+
return -1
|
|
138
|
+
# Normalize platform names
|
|
139
|
+
if platform in ("win", "win32"):
|
|
140
|
+
platform = "windows"
|
|
141
|
+
elif platform == "macos":
|
|
142
|
+
platform = "darwin"
|
|
143
|
+
else:
|
|
144
|
+
try:
|
|
145
|
+
platform, _ = _detect_binary_type(binary_path)
|
|
146
|
+
except ValueError as e:
|
|
147
|
+
logger.error(str(e))
|
|
148
|
+
return -1
|
|
149
|
+
|
|
150
|
+
# Validate binary exists
|
|
151
|
+
if not binary_path.exists():
|
|
152
|
+
logger.error(f"Binary not found: {binary_path}")
|
|
153
|
+
return -1
|
|
154
|
+
|
|
155
|
+
if not binary_path.is_file():
|
|
156
|
+
logger.error(f"Not a file: {binary_path}")
|
|
157
|
+
return -1
|
|
158
|
+
|
|
159
|
+
# Create appropriate deployer
|
|
160
|
+
deployer = create_deployer(platform, arch)
|
|
161
|
+
if deployer is None:
|
|
162
|
+
logger.error(f"No deployer available for platform: {platform}")
|
|
163
|
+
return -1
|
|
164
|
+
|
|
165
|
+
if verbose:
|
|
166
|
+
logger.info(f"Deploying dependencies for: {binary_path}")
|
|
167
|
+
logger.info(f"Platform: {platform}, Architecture: {arch}")
|
|
168
|
+
|
|
169
|
+
if dry_run:
|
|
170
|
+
# Dry run - just show what would be deployed
|
|
171
|
+
dependencies = deployer.detect_all_dependencies(binary_path, recursive=True)
|
|
172
|
+
if not dependencies:
|
|
173
|
+
logger.info("No deployable dependencies found")
|
|
174
|
+
return 0
|
|
175
|
+
|
|
176
|
+
logger.info(f"Would deploy {len(dependencies)} libraries:")
|
|
177
|
+
for dep in sorted(dependencies):
|
|
178
|
+
src = deployer.find_library_in_toolchain(dep)
|
|
179
|
+
if src:
|
|
180
|
+
logger.info(f" {dep} <- {src}")
|
|
181
|
+
else:
|
|
182
|
+
logger.info(f" {dep} (source not found)")
|
|
183
|
+
return len(dependencies)
|
|
184
|
+
|
|
185
|
+
# Actually deploy
|
|
186
|
+
try:
|
|
187
|
+
deployed_count = deployer.deploy_all(binary_path)
|
|
188
|
+
if deployed_count == 0 and verbose:
|
|
189
|
+
logger.info("No libraries needed deployment (all up-to-date or none required)")
|
|
190
|
+
return deployed_count
|
|
191
|
+
except Exception as e:
|
|
192
|
+
logger.error(f"Deployment failed: {e}")
|
|
193
|
+
return -1
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def main() -> int:
|
|
197
|
+
"""
|
|
198
|
+
Main entry point for clang-tool-chain-libdeploy.
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Exit code (0 for success, non-zero for failure)
|
|
202
|
+
"""
|
|
203
|
+
parser = argparse.ArgumentParser(
|
|
204
|
+
prog="clang-tool-chain-libdeploy",
|
|
205
|
+
description="Deploy runtime library dependencies for executables and shared libraries",
|
|
206
|
+
epilog="""
|
|
207
|
+
Examples:
|
|
208
|
+
clang-tool-chain-libdeploy myprogram.exe # Windows executable
|
|
209
|
+
clang-tool-chain-libdeploy mylib.dll # Windows DLL
|
|
210
|
+
clang-tool-chain-libdeploy myprogram # Linux/macOS executable
|
|
211
|
+
clang-tool-chain-libdeploy mylib.so # Linux shared library
|
|
212
|
+
clang-tool-chain-libdeploy mylib.dylib # macOS dynamic library
|
|
213
|
+
clang-tool-chain-libdeploy --dry-run myprogram # Show what would be deployed
|
|
214
|
+
|
|
215
|
+
Supported platforms:
|
|
216
|
+
Windows: Deploys MinGW runtime DLLs (libwinpthread, libgcc_s, libstdc++, etc.)
|
|
217
|
+
Linux: Deploys libc++, libunwind, sanitizer runtimes
|
|
218
|
+
macOS: Deploys libc++, libunwind, sanitizer runtimes
|
|
219
|
+
""",
|
|
220
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
parser.add_argument(
|
|
224
|
+
"binary",
|
|
225
|
+
type=Path,
|
|
226
|
+
help="Path to executable (.exe) or shared library (.dll, .so, .dylib)",
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
parser.add_argument(
|
|
230
|
+
"-v",
|
|
231
|
+
"--verbose",
|
|
232
|
+
action="store_true",
|
|
233
|
+
help="Enable verbose output",
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
parser.add_argument(
|
|
237
|
+
"-n",
|
|
238
|
+
"--dry-run",
|
|
239
|
+
action="store_true",
|
|
240
|
+
help="Show what would be deployed without copying files",
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
parser.add_argument(
|
|
244
|
+
"-p",
|
|
245
|
+
"--platform",
|
|
246
|
+
choices=["windows", "linux", "darwin"],
|
|
247
|
+
help="Override auto-detected platform",
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
parser.add_argument(
|
|
251
|
+
"-a",
|
|
252
|
+
"--arch",
|
|
253
|
+
help="Target architecture (default: auto-detect)",
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
args = parser.parse_args()
|
|
257
|
+
|
|
258
|
+
# Setup logging
|
|
259
|
+
_setup_logging(args.verbose)
|
|
260
|
+
|
|
261
|
+
try:
|
|
262
|
+
result = deploy_dependencies(
|
|
263
|
+
binary_path=args.binary.resolve(),
|
|
264
|
+
platform_override=args.platform,
|
|
265
|
+
arch=args.arch,
|
|
266
|
+
verbose=args.verbose,
|
|
267
|
+
dry_run=args.dry_run,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
if result < 0:
|
|
271
|
+
return 1
|
|
272
|
+
|
|
273
|
+
if result == 0 and not args.dry_run:
|
|
274
|
+
# No libraries deployed is not necessarily an error
|
|
275
|
+
return 0
|
|
276
|
+
|
|
277
|
+
return 0
|
|
278
|
+
|
|
279
|
+
except KeyboardInterrupt as ke:
|
|
280
|
+
handle_keyboard_interrupt_properly(ke) # NoReturn - re-raises
|
|
281
|
+
except Exception as e:
|
|
282
|
+
logger.error(f"Error: {e}")
|
|
283
|
+
return 1
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
if __name__ == "__main__":
|
|
287
|
+
sys.exit(main())
|
|
@@ -36,6 +36,8 @@ class SoDeployer(BaseLibraryDeployer):
|
|
|
36
36
|
r"libc\+\+\.so[.\d]*",
|
|
37
37
|
r"libc\+\+abi\.so[.\d]*",
|
|
38
38
|
r"libunwind\.so[.\d]*",
|
|
39
|
+
r"libunwind-x86_64\.so[.\d]*", # Platform-specific libunwind (bundled)
|
|
40
|
+
r"libunwind-aarch64\.so[.\d]*", # Platform-specific libunwind (bundled)
|
|
39
41
|
r"libclang_rt\..*\.so", # Sanitizer runtimes
|
|
40
42
|
]
|
|
41
43
|
|
|
@@ -206,6 +208,19 @@ class SoDeployer(BaseLibraryDeployer):
|
|
|
206
208
|
if resolved.exists():
|
|
207
209
|
return resolved
|
|
208
210
|
|
|
211
|
+
# For sanitizer runtimes, try architecture-suffixed variants
|
|
212
|
+
# e.g., libclang_rt.asan.so -> libclang_rt.asan-x86_64.so
|
|
213
|
+
if lib_name.startswith("libclang_rt.") and lib_name.endswith(".so"):
|
|
214
|
+
base_name = lib_name[:-3] # Remove .so
|
|
215
|
+
arch_suffixes = ["-x86_64", "-aarch64", "-arm64"]
|
|
216
|
+
for suffix in arch_suffixes:
|
|
217
|
+
arch_lib_path = search_dir / f"{base_name}{suffix}.so"
|
|
218
|
+
if arch_lib_path.exists():
|
|
219
|
+
resolved = arch_lib_path.resolve()
|
|
220
|
+
if resolved.exists():
|
|
221
|
+
self.logger.debug(f"Found architecture-suffixed variant: {arch_lib_path}")
|
|
222
|
+
return resolved
|
|
223
|
+
|
|
209
224
|
return None
|
|
210
225
|
|
|
211
226
|
except KeyboardInterrupt as ke:
|
clang_tool_chain/env_utils.py
CHANGED
|
@@ -26,6 +26,7 @@ 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",
|
|
29
30
|
"RPATH": "Automatic rpath injection for library loading",
|
|
30
31
|
"SYSROOT": "Automatic macOS SDK detection (-isysroot)",
|
|
31
32
|
"DEPLOY_LIBS": "Cross-platform library deployment (all outputs)",
|
|
@@ -14,9 +14,12 @@ The Chain of Responsibility pattern allows:
|
|
|
14
14
|
|
|
15
15
|
Architecture:
|
|
16
16
|
ArgumentTransformer (ABC)
|
|
17
|
-
├── MacOSSDKTransformer (priority=100)
|
|
18
17
|
├── DirectivesTransformer (priority=50)
|
|
18
|
+
├── MacOSSDKTransformer (priority=100)
|
|
19
|
+
├── LinuxUnwindTransformer (priority=150)
|
|
19
20
|
├── LLDLinkerTransformer (priority=200)
|
|
21
|
+
├── ASANRuntimeTransformer (priority=250)
|
|
22
|
+
├── RPathTransformer (priority=275)
|
|
20
23
|
├── GNUABITransformer (priority=300)
|
|
21
24
|
└── MSVCABITransformer (priority=300)
|
|
22
25
|
|
|
@@ -205,6 +208,86 @@ class MacOSSDKTransformer(ArgumentTransformer):
|
|
|
205
208
|
return _add_macos_sysroot_if_needed(args)
|
|
206
209
|
|
|
207
210
|
|
|
211
|
+
class LinuxUnwindTransformer(ArgumentTransformer):
|
|
212
|
+
"""
|
|
213
|
+
Transformer for adding bundled libunwind include/library paths on Linux.
|
|
214
|
+
|
|
215
|
+
Priority: 150 (runs after SDK but before linker)
|
|
216
|
+
|
|
217
|
+
This transformer adds include and library paths for the bundled libunwind
|
|
218
|
+
headers and libraries on Linux. This allows compilation of code that uses
|
|
219
|
+
libunwind without requiring system libunwind-dev to be installed.
|
|
220
|
+
|
|
221
|
+
When libunwind.h exists in the clang toolchain's include directory:
|
|
222
|
+
- Adds -I<clang_root>/include for header discovery
|
|
223
|
+
- Adds -L<clang_root>/lib for library discovery
|
|
224
|
+
- Adds -Wl,-rpath,<clang_root>/lib for runtime library discovery
|
|
225
|
+
|
|
226
|
+
Environment Variables:
|
|
227
|
+
CLANG_TOOL_CHAIN_NO_BUNDLED_UNWIND: Set to '1' to disable bundled libunwind
|
|
228
|
+
CLANG_TOOL_CHAIN_NO_AUTO: Set to '1' to disable all automatic features
|
|
229
|
+
"""
|
|
230
|
+
|
|
231
|
+
def priority(self) -> int:
|
|
232
|
+
return 150
|
|
233
|
+
|
|
234
|
+
def transform(self, args: list[str], context: ToolContext) -> list[str]:
|
|
235
|
+
"""Add bundled libunwind paths if available on Linux."""
|
|
236
|
+
# Only applies to Linux clang/clang++
|
|
237
|
+
if context.platform_name != "linux" or context.tool_name not in ("clang", "clang++"):
|
|
238
|
+
return args
|
|
239
|
+
|
|
240
|
+
# Check if disabled (via NO_BUNDLED_UNWIND or NO_AUTO)
|
|
241
|
+
if is_feature_disabled("BUNDLED_UNWIND"):
|
|
242
|
+
return args
|
|
243
|
+
|
|
244
|
+
# Check if compile-only (no linking)
|
|
245
|
+
is_compile_only = "-c" in args
|
|
246
|
+
|
|
247
|
+
try:
|
|
248
|
+
from clang_tool_chain.platform.detection import get_platform_binary_dir
|
|
249
|
+
|
|
250
|
+
clang_bin = get_platform_binary_dir()
|
|
251
|
+
clang_root = clang_bin.parent
|
|
252
|
+
|
|
253
|
+
# Check if bundled libunwind.h exists
|
|
254
|
+
libunwind_header = clang_root / "include" / "libunwind.h"
|
|
255
|
+
if not libunwind_header.exists():
|
|
256
|
+
logger.debug("Bundled libunwind.h not found, skipping LinuxUnwindTransformer")
|
|
257
|
+
return args
|
|
258
|
+
|
|
259
|
+
result = list(args)
|
|
260
|
+
include_dir = clang_root / "include"
|
|
261
|
+
lib_dir = clang_root / "lib"
|
|
262
|
+
|
|
263
|
+
# Add include path (always needed for compilation)
|
|
264
|
+
include_flag = f"-I{include_dir}"
|
|
265
|
+
if include_flag not in args:
|
|
266
|
+
result = [include_flag] + result
|
|
267
|
+
logger.debug(f"Adding bundled libunwind include path: {include_flag}")
|
|
268
|
+
|
|
269
|
+
# Add library path and rpath (only for linking)
|
|
270
|
+
if not is_compile_only:
|
|
271
|
+
lib_flag = f"-L{lib_dir}"
|
|
272
|
+
if lib_flag not in args:
|
|
273
|
+
result = [lib_flag] + result
|
|
274
|
+
logger.debug(f"Adding bundled libunwind library path: {lib_flag}")
|
|
275
|
+
|
|
276
|
+
# Add rpath so runtime can find libunwind.so
|
|
277
|
+
rpath_flag = f"-Wl,-rpath,{lib_dir}"
|
|
278
|
+
# Check if any rpath to our lib dir already exists
|
|
279
|
+
has_our_rpath = any(str(lib_dir) in arg and "-rpath" in arg for arg in args)
|
|
280
|
+
if not has_our_rpath:
|
|
281
|
+
result = [rpath_flag] + result
|
|
282
|
+
logger.debug(f"Adding bundled libunwind rpath: {rpath_flag}")
|
|
283
|
+
|
|
284
|
+
return result
|
|
285
|
+
|
|
286
|
+
except Exception as e:
|
|
287
|
+
logger.debug(f"LinuxUnwindTransformer error: {e}")
|
|
288
|
+
return args
|
|
289
|
+
|
|
290
|
+
|
|
208
291
|
class LLDLinkerTransformer(ArgumentTransformer):
|
|
209
292
|
"""
|
|
210
293
|
Transformer for forcing LLVM's lld linker on macOS and Linux.
|
|
@@ -293,21 +376,25 @@ class ASANRuntimeTransformer(ArgumentTransformer):
|
|
|
293
376
|
|
|
294
377
|
Priority: 250 (runs after linker but before ABI)
|
|
295
378
|
|
|
296
|
-
This transformer ensures proper ASAN runtime linking on Linux:
|
|
379
|
+
This transformer ensures proper ASAN runtime linking on Linux and Windows:
|
|
297
380
|
- Detects -fsanitize=address flag
|
|
298
381
|
- Adds -shared-libasan to use shared runtime library
|
|
299
|
-
- Adds -Wl,--allow-shlib-undefined when building shared libraries with ASAN
|
|
382
|
+
- Adds -Wl,--allow-shlib-undefined when building shared libraries with ASAN (Linux only)
|
|
300
383
|
- Prevents undefined symbol errors during linking
|
|
301
384
|
|
|
302
|
-
The shared runtime library (libclang_rt.asan.so
|
|
303
|
-
ASAN implementation, while the static wrapper library
|
|
385
|
+
The shared runtime library (libclang_rt.asan.so on Linux, libclang_rt.asan_dynamic.dll
|
|
386
|
+
on Windows) contains the full ASAN implementation, while the static wrapper library
|
|
387
|
+
only contains stubs.
|
|
304
388
|
|
|
305
389
|
When building shared libraries with sanitizers, the library may have undefined
|
|
306
390
|
symbols that will be provided by the sanitizer runtime when loaded. LLD by
|
|
307
391
|
default enforces no undefined symbols, so we need to allow them explicitly.
|
|
308
392
|
|
|
393
|
+
Note: macOS uses a different ASAN runtime mechanism and is not affected.
|
|
394
|
+
|
|
309
395
|
Environment Variables:
|
|
310
396
|
CLANG_TOOL_CHAIN_NO_SHARED_ASAN: Set to '1' to disable shared ASAN
|
|
397
|
+
CLANG_TOOL_CHAIN_NO_SANITIZER_NOTE: Set to '1' to suppress the injection note
|
|
311
398
|
CLANG_TOOL_CHAIN_NO_AUTO: Set to '1' to disable all automatic features
|
|
312
399
|
"""
|
|
313
400
|
|
|
@@ -315,11 +402,12 @@ class ASANRuntimeTransformer(ArgumentTransformer):
|
|
|
315
402
|
return 250
|
|
316
403
|
|
|
317
404
|
def transform(self, args: list[str], context: ToolContext) -> list[str]:
|
|
318
|
-
"""Add -shared-libasan and --allow-shlib-undefined when using ASAN on Linux."""
|
|
405
|
+
"""Add -shared-libasan and --allow-shlib-undefined when using ASAN on Linux/Windows."""
|
|
319
406
|
import sys
|
|
320
407
|
|
|
321
|
-
# Only applies to Linux clang/clang++
|
|
322
|
-
|
|
408
|
+
# Only applies to Linux and Windows (GNU ABI) clang/clang++
|
|
409
|
+
# macOS uses a different ASAN runtime mechanism
|
|
410
|
+
if context.platform_name not in ("linux", "win") or context.tool_name not in ("clang", "clang++"):
|
|
323
411
|
return args
|
|
324
412
|
|
|
325
413
|
# Check if ASAN is enabled
|
|
@@ -339,11 +427,12 @@ class ASANRuntimeTransformer(ArgumentTransformer):
|
|
|
339
427
|
result = ["-shared-libasan"] + result
|
|
340
428
|
injected_flags.append("-shared-libasan")
|
|
341
429
|
|
|
342
|
-
# Check if building a shared library with ASAN
|
|
430
|
+
# Check if building a shared library with ASAN on Linux
|
|
343
431
|
# Shared libraries need to allow undefined symbols that will be provided
|
|
344
432
|
# by the sanitizer runtime when the runner loads them
|
|
433
|
+
# Note: --allow-shlib-undefined is a Linux ELF linker flag, not supported on Windows
|
|
345
434
|
is_shared_lib = "-shared" in args
|
|
346
|
-
if is_shared_lib:
|
|
435
|
+
if is_shared_lib and context.platform_name == "linux":
|
|
347
436
|
# Check if --allow-shlib-undefined already present
|
|
348
437
|
has_allow_shlib_undefined = any("--allow-shlib-undefined" in arg for arg in args)
|
|
349
438
|
if not has_allow_shlib_undefined:
|
|
@@ -351,10 +440,11 @@ class ASANRuntimeTransformer(ArgumentTransformer):
|
|
|
351
440
|
result = ["-Wl,--allow-shlib-undefined"] + result
|
|
352
441
|
injected_flags.append("-Wl,--allow-shlib-undefined")
|
|
353
442
|
|
|
354
|
-
# Warn on stderr if we injected flags
|
|
355
|
-
if injected_flags:
|
|
443
|
+
# Warn on stderr if we injected flags (unless disabled)
|
|
444
|
+
if injected_flags and not is_feature_disabled("SANITIZER_NOTE"):
|
|
356
445
|
print(
|
|
357
|
-
f"clang-tool-chain: note: automatically injected sanitizer flags: {' '.join(injected_flags)}"
|
|
446
|
+
f"clang-tool-chain: note: automatically injected sanitizer flags: {' '.join(injected_flags)} "
|
|
447
|
+
"(disable with CLANG_TOOL_CHAIN_NO_SANITIZER_NOTE=1)",
|
|
358
448
|
file=sys.stderr,
|
|
359
449
|
)
|
|
360
450
|
|
|
@@ -406,9 +496,9 @@ class RPathTransformer(ArgumentTransformer):
|
|
|
406
496
|
if is_feature_disabled("RPATH"):
|
|
407
497
|
return args
|
|
408
498
|
|
|
409
|
-
# Check if rpath already present
|
|
499
|
+
# Check if $ORIGIN rpath already present (don't skip for other rpaths)
|
|
410
500
|
for arg in args:
|
|
411
|
-
if "
|
|
501
|
+
if "$ORIGIN" in arg:
|
|
412
502
|
return args
|
|
413
503
|
|
|
414
504
|
# Add rpath to look in executable's directory first
|
|
@@ -528,11 +618,12 @@ def create_default_pipeline() -> ArgumentPipeline:
|
|
|
528
618
|
This includes all standard transformers in their default priority order:
|
|
529
619
|
1. DirectivesTransformer (priority=50)
|
|
530
620
|
2. MacOSSDKTransformer (priority=100)
|
|
531
|
-
3.
|
|
532
|
-
4.
|
|
533
|
-
5.
|
|
534
|
-
6.
|
|
535
|
-
7.
|
|
621
|
+
3. LinuxUnwindTransformer (priority=150)
|
|
622
|
+
4. LLDLinkerTransformer (priority=200)
|
|
623
|
+
5. ASANRuntimeTransformer (priority=250)
|
|
624
|
+
6. RPathTransformer (priority=275)
|
|
625
|
+
7. GNUABITransformer (priority=300)
|
|
626
|
+
8. MSVCABITransformer (priority=300)
|
|
536
627
|
|
|
537
628
|
Returns:
|
|
538
629
|
Configured ArgumentPipeline ready for use
|
|
@@ -541,6 +632,7 @@ def create_default_pipeline() -> ArgumentPipeline:
|
|
|
541
632
|
[
|
|
542
633
|
DirectivesTransformer(),
|
|
543
634
|
MacOSSDKTransformer(),
|
|
635
|
+
LinuxUnwindTransformer(),
|
|
544
636
|
LLDLinkerTransformer(),
|
|
545
637
|
ASANRuntimeTransformer(),
|
|
546
638
|
RPathTransformer(),
|
clang_tool_chain/linker/lld.py
CHANGED
|
@@ -12,6 +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
16
|
from clang_tool_chain.interrupt_utils import handle_keyboard_interrupt_properly
|
|
16
17
|
from clang_tool_chain.llvm_versions import get_llvm_version_tuple, supports_ld64_lld_flag
|
|
17
18
|
|
|
@@ -187,13 +188,16 @@ def _translate_linker_flags_for_macos_lld(args: list[str]) -> list[str]:
|
|
|
187
188
|
Translate GNU ld linker flags to ld64.lld equivalents for macOS.
|
|
188
189
|
|
|
189
190
|
When using lld on macOS (ld64.lld), certain GNU ld flags need to be
|
|
190
|
-
translated to their Mach-O equivalents:
|
|
191
|
+
translated to their Mach-O equivalents or removed:
|
|
191
192
|
- --no-undefined -> -undefined error
|
|
192
193
|
- --fatal-warnings -> -fatal_warnings
|
|
193
|
-
-
|
|
194
|
+
- --allow-shlib-undefined -> (removed, ld64 allows undefined symbols by default)
|
|
194
195
|
|
|
195
196
|
This function processes both direct linker flags and flags passed via -Wl,
|
|
196
197
|
|
|
198
|
+
A warning is printed to stderr when flags are removed, unless silenced via
|
|
199
|
+
CLANG_TOOL_CHAIN_NO_LINKER_COMPAT_NOTE=1.
|
|
200
|
+
|
|
197
201
|
Args:
|
|
198
202
|
args: Original compiler arguments
|
|
199
203
|
|
|
@@ -201,12 +205,19 @@ def _translate_linker_flags_for_macos_lld(args: list[str]) -> list[str]:
|
|
|
201
205
|
Modified arguments with translated linker flags
|
|
202
206
|
"""
|
|
203
207
|
# Map of GNU ld flags to ld64.lld equivalents
|
|
204
|
-
|
|
208
|
+
# None means the flag should be removed (no equivalent needed)
|
|
209
|
+
flag_translations: dict[str, str | None] = {
|
|
205
210
|
"--no-undefined": "-undefined error",
|
|
206
211
|
"--fatal-warnings": "-fatal_warnings",
|
|
212
|
+
# --allow-shlib-undefined: ld64 allows undefined symbols in dylibs by default,
|
|
213
|
+
# so this flag is a no-op on macOS. We remove it entirely.
|
|
214
|
+
"--allow-shlib-undefined": None,
|
|
207
215
|
# Add more translations as needed
|
|
208
216
|
}
|
|
209
217
|
|
|
218
|
+
# Track removed flags for warning
|
|
219
|
+
removed_flags: list[str] = []
|
|
220
|
+
|
|
210
221
|
result = []
|
|
211
222
|
i = 0
|
|
212
223
|
while i < len(args):
|
|
@@ -221,14 +232,18 @@ def _translate_linker_flags_for_macos_lld(args: list[str]) -> list[str]:
|
|
|
221
232
|
for flag in linker_flags:
|
|
222
233
|
# Check if this flag needs translation
|
|
223
234
|
if flag in flag_translations:
|
|
224
|
-
# Translate the flag (may result in multiple flags)
|
|
225
235
|
translated = flag_translations[flag]
|
|
226
|
-
if
|
|
236
|
+
if translated is None:
|
|
237
|
+
# Flag should be removed entirely (no equivalent on macOS)
|
|
238
|
+
removed_flags.append(flag)
|
|
239
|
+
logger.debug(f"Removed linker flag (no macOS equivalent): {flag}")
|
|
240
|
+
elif " " in translated:
|
|
227
241
|
# Multiple flags (e.g., "-undefined error")
|
|
228
242
|
translated_flags.extend(translated.split())
|
|
243
|
+
logger.debug(f"Translated linker flag: {flag} -> {translated}")
|
|
229
244
|
else:
|
|
230
245
|
translated_flags.append(translated)
|
|
231
|
-
|
|
246
|
+
logger.debug(f"Translated linker flag: {flag} -> {translated}")
|
|
232
247
|
else:
|
|
233
248
|
translated_flags.append(flag)
|
|
234
249
|
|
|
@@ -239,19 +254,34 @@ def _translate_linker_flags_for_macos_lld(args: list[str]) -> list[str]:
|
|
|
239
254
|
# Handle standalone linker flags passed directly
|
|
240
255
|
elif arg in flag_translations:
|
|
241
256
|
translated = flag_translations[arg]
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
result.append("-Wl," + ",".join(translated.split()))
|
|
257
|
+
if translated is None:
|
|
258
|
+
# Flag should be removed entirely (no equivalent on macOS)
|
|
259
|
+
removed_flags.append(arg)
|
|
260
|
+
logger.debug(f"Removed linker flag (no macOS equivalent): {arg}")
|
|
247
261
|
else:
|
|
248
|
-
|
|
262
|
+
logger.debug(f"Translated linker flag: {arg} -> {translated}")
|
|
263
|
+
# Add via -Wl, to pass to linker
|
|
264
|
+
if " " in translated:
|
|
265
|
+
# Multiple flags
|
|
266
|
+
result.append("-Wl," + ",".join(translated.split()))
|
|
267
|
+
else:
|
|
268
|
+
result.append("-Wl," + translated)
|
|
249
269
|
|
|
250
270
|
else:
|
|
251
271
|
result.append(arg)
|
|
252
272
|
|
|
253
273
|
i += 1
|
|
254
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
|
+
|
|
279
|
+
print(
|
|
280
|
+
f"clang-tool-chain: note: removed GNU linker flags not supported by ld64.lld: "
|
|
281
|
+
f"{', '.join(removed_flags)} (disable with CLANG_TOOL_CHAIN_NO_LINKER_COMPAT_NOTE=1)",
|
|
282
|
+
file=sys.stderr,
|
|
283
|
+
)
|
|
284
|
+
|
|
255
285
|
return result
|
|
256
286
|
|
|
257
287
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: clang-tool-chain
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
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
|
|
@@ -117,12 +117,13 @@ Comprehensive test coverage across all platforms and tool categories ensures rel
|
|
|
117
117
|
| **lldb** | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lldb-win.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lldb-linux-x86.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lldb-linux-arm.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lldb-macos-x86.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lldb-macos-arm.yml) |
|
|
118
118
|
| **cosmocc** | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-cosmocc-win.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-cosmocc-linux-x86.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-cosmocc-linux-arm.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-cosmocc-macos-x86.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-cosmocc-macos-arm.yml) |
|
|
119
119
|
| **lib-deploy** | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lib-deploy-win.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lib-deploy-linux-x86.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lib-deploy-linux-arm.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lib-deploy-macos-x86.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-lib-deploy-macos-arm.yml) |
|
|
120
|
+
| **libunwind** | N/A | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-libunwind-linux-x86.yml) | [](https://github.com/zackees/clang-tool-chain/actions/workflows/test-libunwind-linux-arm.yml) | N/A | N/A |
|
|
120
121
|
|
|
121
122
|
**📖 [Complete Test Matrix Documentation](docs/TEST_MATRIX.md)** - Tool category descriptions, test organization, running tests locally.
|
|
122
123
|
|
|
123
124
|
---
|
|
124
125
|
|
|
125
|
-
## 📋 All Commands (
|
|
126
|
+
## 📋 All Commands (42 Total)
|
|
126
127
|
|
|
127
128
|
Comprehensive reference of all available commands organized by category.
|
|
128
129
|
|
|
@@ -203,7 +204,7 @@ Comprehensive reference of all available commands organized by category.
|
|
|
203
204
|
| `clang-tool-chain-sccache-emcc` | Cached Emscripten C compiler |
|
|
204
205
|
| `clang-tool-chain-sccache-empp` | Cached Emscripten C++ compiler |
|
|
205
206
|
|
|
206
|
-
### Management & Diagnostics (
|
|
207
|
+
### Management & Diagnostics (5)
|
|
207
208
|
|
|
208
209
|
| Command | Description |
|
|
209
210
|
|---------|-------------|
|
|
@@ -211,8 +212,9 @@ Comprehensive reference of all available commands organized by category.
|
|
|
211
212
|
| `clang-tool-chain-test` | Run diagnostic tests (7 checks) |
|
|
212
213
|
| `clang-tool-chain-fetch` | Download toolchain components |
|
|
213
214
|
| `clang-tool-chain-paths` | Display installation paths |
|
|
215
|
+
| `clang-tool-chain-libdeploy` | Deploy runtime library dependencies after the fact |
|
|
214
216
|
|
|
215
|
-
**Total:
|
|
217
|
+
**Total: 42 commands** providing complete C/C++/WebAssembly toolchain capabilities.
|
|
216
218
|
|
|
217
219
|
---
|
|
218
220
|
|
|
@@ -241,6 +243,7 @@ Comprehensive reference of all available commands organized by category.
|
|
|
241
243
|
- [Executable C++ Scripts](#-executable-c-scripts-shebang-support)
|
|
242
244
|
- [Windows DLL Deployment](#-windows-dll-deployment)
|
|
243
245
|
- [Address Sanitizer (ASAN)](#️-address-sanitizer-asan-support)
|
|
246
|
+
- [Bundled libunwind (Linux)](#-bundled-libunwind-linux)
|
|
244
247
|
- [sccache Integration](#-sccache-integration)
|
|
245
248
|
|
|
246
249
|
### Platform & Configuration
|
|
@@ -275,13 +278,13 @@ Comprehensive reference of all available commands organized by category.
|
|
|
275
278
|
|
|
276
279
|
### Platform & Version Matrix
|
|
277
280
|
|
|
278
|
-
| Platform | Architecture | LLVM Version | Archive Size | Linker | Status |
|
|
279
|
-
|
|
280
|
-
| Windows | x86_64 | 21.1.5 | ~71-90 MB | lld | ✅ Stable |
|
|
281
|
-
| Linux | x86_64 | 21.1.5 | ~87 MB | lld | ✅ Stable |
|
|
282
|
-
| Linux | ARM64 | 21.1.5 | ~91 MB | lld | ✅ Stable |
|
|
283
|
-
| macOS | x86_64 | 21.1.6 | ~77 MB | ld64.lld | ✅ Stable |
|
|
284
|
-
| macOS | ARM64 | 21.1.6 | ~71 MB | ld64.lld | ✅ Stable |
|
|
281
|
+
| Platform | Architecture | LLVM Version | Archive Size | Linker | Extras | Status |
|
|
282
|
+
|----------|--------------|--------------|--------------|--------|--------|--------|
|
|
283
|
+
| Windows | x86_64 | 21.1.5 | ~71-90 MB | lld | MinGW sysroot | ✅ Stable |
|
|
284
|
+
| Linux | x86_64 | 21.1.5 | ~87 MB | lld | libunwind (bundled) | ✅ Stable |
|
|
285
|
+
| Linux | ARM64 | 21.1.5 | ~91 MB | lld | libunwind (bundled) | ✅ Stable |
|
|
286
|
+
| macOS | x86_64 | 21.1.6 | ~77 MB | ld64.lld | - | ✅ Stable |
|
|
287
|
+
| macOS | ARM64 | 21.1.6 | ~71 MB | ld64.lld | - | ✅ Stable |
|
|
285
288
|
|
|
286
289
|
### Windows ABI Selection
|
|
287
290
|
|
|
@@ -743,6 +746,70 @@ clang-tool-chain-cpp main.cpp -o program --deploy-dependencies
|
|
|
743
746
|
|
|
744
747
|
---
|
|
745
748
|
|
|
749
|
+
## 📦 Post-Build Library Deployment (clang-tool-chain-libdeploy)
|
|
750
|
+
|
|
751
|
+
**Deploy runtime dependencies after compilation** - useful when you've compiled without `--deploy-dependencies` or when using external build systems.
|
|
752
|
+
|
|
753
|
+
### Quick Examples
|
|
754
|
+
|
|
755
|
+
```bash
|
|
756
|
+
# Deploy dependencies for a Windows executable
|
|
757
|
+
clang-tool-chain-libdeploy myprogram.exe
|
|
758
|
+
# Output: Deployed 3 MinGW DLL(s) for myprogram.exe
|
|
759
|
+
|
|
760
|
+
# Deploy dependencies for a Linux shared library
|
|
761
|
+
clang-tool-chain-libdeploy mylib.so
|
|
762
|
+
|
|
763
|
+
# Deploy dependencies for a macOS executable
|
|
764
|
+
clang-tool-chain-libdeploy myprogram
|
|
765
|
+
|
|
766
|
+
# Dry run - see what would be deployed without copying
|
|
767
|
+
clang-tool-chain-libdeploy --dry-run myprogram.exe
|
|
768
|
+
# Output:
|
|
769
|
+
# Would deploy 3 libraries:
|
|
770
|
+
# libwinpthread-1.dll <- /path/to/toolchain/lib/libwinpthread-1.dll
|
|
771
|
+
# libgcc_s_seh-1.dll <- /path/to/toolchain/lib/libgcc_s_seh-1.dll
|
|
772
|
+
# libstdc++-6.dll <- /path/to/toolchain/lib/libstdc++-6.dll
|
|
773
|
+
```
|
|
774
|
+
|
|
775
|
+
### Command Line Options
|
|
776
|
+
|
|
777
|
+
```bash
|
|
778
|
+
clang-tool-chain-libdeploy [options] <binary>
|
|
779
|
+
|
|
780
|
+
Options:
|
|
781
|
+
-h, --help Show help message
|
|
782
|
+
-v, --verbose Enable verbose output
|
|
783
|
+
-n, --dry-run Show what would be deployed without copying
|
|
784
|
+
-p, --platform Override auto-detected platform (windows, linux, darwin)
|
|
785
|
+
-a, --arch Target architecture (default: auto-detect)
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
### Use Cases
|
|
789
|
+
|
|
790
|
+
1. **External build systems**: When using CMake, Make, or other build systems that don't use clang-tool-chain wrappers directly
|
|
791
|
+
2. **Third-party binaries**: Deploy dependencies for pre-built executables compiled with clang-tool-chain
|
|
792
|
+
3. **CI/CD pipelines**: Add deployment as a separate step after compilation
|
|
793
|
+
4. **Debugging**: Use `--dry-run` to inspect dependencies without modifying files
|
|
794
|
+
|
|
795
|
+
### Supported Formats
|
|
796
|
+
|
|
797
|
+
| Platform | File Types | Dependencies Deployed |
|
|
798
|
+
|----------|------------|----------------------|
|
|
799
|
+
| Windows | `.exe`, `.dll` | MinGW runtime DLLs (libwinpthread, libgcc_s, libstdc++, etc.) |
|
|
800
|
+
| Linux | executables, `.so` | libc++, libunwind, sanitizer runtimes |
|
|
801
|
+
| macOS | executables, `.dylib` | libc++, libunwind, sanitizer runtimes |
|
|
802
|
+
|
|
803
|
+
### Binary Type Detection
|
|
804
|
+
|
|
805
|
+
The tool automatically detects binary type from:
|
|
806
|
+
1. **File extension**: `.exe`, `.dll`, `.so`, `.dylib`
|
|
807
|
+
2. **Magic bytes**: ELF (Linux), Mach-O (macOS), PE (Windows)
|
|
808
|
+
|
|
809
|
+
For executables without extensions (common on Linux/macOS), magic bytes are used for detection.
|
|
810
|
+
|
|
811
|
+
---
|
|
812
|
+
|
|
746
813
|
## 🚀 CI/CD Integration
|
|
747
814
|
|
|
748
815
|
```yaml
|
|
@@ -769,13 +836,13 @@ jobs:
|
|
|
769
836
|
|
|
770
837
|
## 🌍 Platform Support Matrix
|
|
771
838
|
|
|
772
|
-
| Platform | Architecture | LLVM Version | Archive Size | Status |
|
|
773
|
-
|
|
774
|
-
| Windows | x86_64 | 21.1.5 | ~71-90 MB | ✅ Stable |
|
|
775
|
-
| Linux | x86_64 | 21.1.5 | ~87 MB | ✅ Stable |
|
|
776
|
-
| Linux | ARM64 | 21.1.5 | ~91 MB | ✅ Stable |
|
|
777
|
-
| macOS | x86_64 | 19.1.7 | ~77 MB | ✅ Stable |
|
|
778
|
-
| macOS | ARM64 | 21.1.6 | ~71 MB | ✅ Stable |
|
|
839
|
+
| Platform | Architecture | LLVM Version | Archive Size | Bundled Extras | Status |
|
|
840
|
+
|----------|--------------|--------------|--------------|----------------|--------|
|
|
841
|
+
| Windows | x86_64 | 21.1.5 | ~71-90 MB | MinGW sysroot | ✅ Stable |
|
|
842
|
+
| Linux | x86_64 | 21.1.5 | ~87 MB | libunwind | ✅ Stable |
|
|
843
|
+
| Linux | ARM64 | 21.1.5 | ~91 MB | libunwind | ✅ Stable |
|
|
844
|
+
| macOS | x86_64 | 19.1.7 | ~77 MB | - | ✅ Stable |
|
|
845
|
+
| macOS | ARM64 | 21.1.6 | ~71 MB | - | ✅ Stable |
|
|
779
846
|
|
|
780
847
|
**Requirements:** Python 3.10+, ~100-400 MB disk space
|
|
781
848
|
|
|
@@ -792,6 +859,7 @@ jobs:
|
|
|
792
859
|
- `CLANG_TOOL_CHAIN_LIB_DEPLOY_VERBOSE` - Enable verbose library deployment logging
|
|
793
860
|
- `CLANG_TOOL_CHAIN_USE_SYSTEM_LD` - Use system linker instead of LLD
|
|
794
861
|
- `CLANG_TOOL_CHAIN_NO_DIRECTIVES` - Disable inlined build directives
|
|
862
|
+
- `CLANG_TOOL_CHAIN_NO_BUNDLED_UNWIND` - Disable bundled libunwind on Linux (use system version)
|
|
795
863
|
- `CLANG_TOOL_CHAIN_NO_SANITIZER_ENV` - Disable automatic ASAN/LSAN options injection at runtime
|
|
796
864
|
- `SDKROOT` - Custom macOS SDK path (auto-detected by default)
|
|
797
865
|
|
|
@@ -904,6 +972,9 @@ export CLANG_TOOL_CHAIN_NO_SANITIZER_ENV=1
|
|
|
904
972
|
|
|
905
973
|
# Disable automatic -shared-libasan on Linux (use static ASAN)
|
|
906
974
|
export CLANG_TOOL_CHAIN_NO_SHARED_ASAN=1
|
|
975
|
+
|
|
976
|
+
# Suppress the "automatically injected sanitizer flags" note
|
|
977
|
+
export CLANG_TOOL_CHAIN_NO_SANITIZER_NOTE=1
|
|
907
978
|
```
|
|
908
979
|
|
|
909
980
|
**Platform Notes:**
|
|
@@ -938,6 +1009,83 @@ See: https://github.com/google/sanitizers/issues/899
|
|
|
938
1009
|
|
|
939
1010
|
---
|
|
940
1011
|
|
|
1012
|
+
## 📚 Bundled libunwind (Linux)
|
|
1013
|
+
|
|
1014
|
+
**Self-contained stack unwinding - no system packages required**
|
|
1015
|
+
|
|
1016
|
+
On Linux, clang-tool-chain bundles libunwind headers and shared libraries, providing a complete solution for stack unwinding without requiring system packages like `libunwind-dev`.
|
|
1017
|
+
|
|
1018
|
+
### What's Bundled
|
|
1019
|
+
|
|
1020
|
+
| Component | Files | Size |
|
|
1021
|
+
|-----------|-------|------|
|
|
1022
|
+
| Headers | `libunwind.h`, `libunwind-common.h`, `libunwind-x86_64.h`/`libunwind-aarch64.h`, `unwind.h` | ~20 KB |
|
|
1023
|
+
| Libraries | `libunwind.so.*`, `libunwind-x86_64.so.*` (or `aarch64`) | ~300 KB |
|
|
1024
|
+
|
|
1025
|
+
### How It Works
|
|
1026
|
+
|
|
1027
|
+
When compiling on Linux, clang-tool-chain **automatically**:
|
|
1028
|
+
1. Adds `-I<clang_root>/include` for bundled libunwind headers
|
|
1029
|
+
2. Adds `-L<clang_root>/lib` for bundled libunwind libraries
|
|
1030
|
+
3. Adds `-Wl,-rpath,<clang_root>/lib` so executables find libunwind at runtime
|
|
1031
|
+
|
|
1032
|
+
This means `#include <libunwind.h>` and `-lunwind` work out of the box.
|
|
1033
|
+
|
|
1034
|
+
### Usage Example
|
|
1035
|
+
|
|
1036
|
+
```c
|
|
1037
|
+
// backtrace.c - Print a stack trace using libunwind
|
|
1038
|
+
#include <stdio.h>
|
|
1039
|
+
#include <libunwind.h>
|
|
1040
|
+
|
|
1041
|
+
void print_backtrace() {
|
|
1042
|
+
unw_cursor_t cursor;
|
|
1043
|
+
unw_context_t context;
|
|
1044
|
+
unw_getcontext(&context);
|
|
1045
|
+
unw_init_local(&cursor, &context);
|
|
1046
|
+
|
|
1047
|
+
while (unw_step(&cursor) > 0) {
|
|
1048
|
+
char name[256];
|
|
1049
|
+
unw_word_t offset;
|
|
1050
|
+
unw_get_proc_name(&cursor, name, sizeof(name), &offset);
|
|
1051
|
+
printf(" %s+0x%lx\n", name, (unsigned long)offset);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
int main() {
|
|
1056
|
+
print_backtrace();
|
|
1057
|
+
return 0;
|
|
1058
|
+
}
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
```bash
|
|
1062
|
+
# Compile and link with bundled libunwind - no apt-get install needed!
|
|
1063
|
+
clang-tool-chain-c backtrace.c -lunwind -o backtrace
|
|
1064
|
+
|
|
1065
|
+
# Run without LD_LIBRARY_PATH - works due to embedded rpath
|
|
1066
|
+
./backtrace
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
### Configuration
|
|
1070
|
+
|
|
1071
|
+
**Disable bundled libunwind** (use system version instead):
|
|
1072
|
+
```bash
|
|
1073
|
+
export CLANG_TOOL_CHAIN_NO_BUNDLED_UNWIND=1
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
### Platform Support
|
|
1077
|
+
|
|
1078
|
+
| Platform | Headers | Libraries | Status |
|
|
1079
|
+
|----------|---------|-----------|--------|
|
|
1080
|
+
| Linux x86_64 | ✅ Bundled | ✅ Bundled | ✅ Full |
|
|
1081
|
+
| Linux ARM64 | ✅ Bundled | ✅ Bundled | ✅ Full |
|
|
1082
|
+
| Windows | MinGW sysroot | MinGW sysroot | N/A (different API) |
|
|
1083
|
+
| macOS | System | System | N/A (uses system) |
|
|
1084
|
+
|
|
1085
|
+
**📖 [Complete Documentation](docs/LIBUNWIND.md)** - Detailed usage, API reference, integration with ASAN, advanced examples.
|
|
1086
|
+
|
|
1087
|
+
---
|
|
1088
|
+
|
|
941
1089
|
## 🔧 How It Works
|
|
942
1090
|
|
|
943
1091
|
Auto-downloads on first use (~71-91 MB, 10-60 seconds). Subsequent uses are instant.
|
|
@@ -1047,6 +1195,7 @@ For in-depth information on specific topics, see the documentation in the `docs/
|
|
|
1047
1195
|
| **[Cosmopolitan Libc](docs/COSMOCC.md)** | Actually Portable Executables (APE) |
|
|
1048
1196
|
| **[sccache Integration](docs/SCCACHE.md)** | Compilation caching (2-10x speedup) |
|
|
1049
1197
|
| **[Inlined Build Directives](docs/DIRECTIVES.md)** | Self-contained source files |
|
|
1198
|
+
| **[Bundled libunwind](docs/LIBUNWIND.md)** | Linux stack unwinding (headers + libraries) |
|
|
1050
1199
|
|
|
1051
1200
|
### Setup & Configuration
|
|
1052
1201
|
| Document | Description |
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
clang_tool_chain/__init__.py,sha256=u-qgOuQxh5W2g7n8BgUtBnUWsK66rM4N6LJXY9PiEx0,880
|
|
2
|
-
clang_tool_chain/__version__.py,sha256=
|
|
2
|
+
clang_tool_chain/__version__.py,sha256=6CB4WX5utk2VKYGwXj_5nRzglWK1ken81ARqHoarPF4,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=
|
|
12
|
+
clang_tool_chain/env_utils.py,sha256=5ovnV9cQ_-g5yBlvG8OyaH0fJ-gYasCwvEn_nKYiw_4,4234
|
|
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
|
|
@@ -34,11 +34,12 @@ clang_tool_chain/deployment/dll_deployer.py,sha256=x3_hXsPgyQMkp1orzZV4lAZa4NMP2
|
|
|
34
34
|
clang_tool_chain/deployment/dll_detector.py,sha256=Zf2NAjAg6bEg6uvb7dFkj0qvk8Mvzj4sjyPIoxNVvJE,8629
|
|
35
35
|
clang_tool_chain/deployment/dylib_deployer.py,sha256=6GLn_CMLYUAdQZgwcTMx0XXo_AxGvUKUFYt04v2Kip0,19315
|
|
36
36
|
clang_tool_chain/deployment/factory.py,sha256=Mq6cMMUctoYBZ81I16_hXUmDLQGSAngCmBzPlu_0iaU,6205
|
|
37
|
-
clang_tool_chain/deployment/
|
|
37
|
+
clang_tool_chain/deployment/libdeploy.py,sha256=cfyDFmbuUmimss5fv7exO7NOulDnw7agrKGFgbSK7BM,9050
|
|
38
|
+
clang_tool_chain/deployment/so_deployer.py,sha256=eAygmGojioi1iz5cHeqmKjJ5fI-5XooG9Ro-5TIA0gw,12867
|
|
38
39
|
clang_tool_chain/directives/__init__.py,sha256=MJDNYL_MD2MF0HFsrTsSTX645bYo6vtjq2pOTtfykaU,198
|
|
39
40
|
clang_tool_chain/directives/parser.py,sha256=6J7mO1JtvuHkkKS0Xges5b_jT9b3uTF6ULI0ZiwGAdw,11179
|
|
40
41
|
clang_tool_chain/execution/__init__.py,sha256=fFQEW9VejCdbBvt4quNJ2X8udh_PKgewTfzUXHmXzyc,940
|
|
41
|
-
clang_tool_chain/execution/arg_transformers.py,sha256=
|
|
42
|
+
clang_tool_chain/execution/arg_transformers.py,sha256=j73CZg8jen7bSymAoiNgqvAQka-e-RMyKkYbh28qy0o,23899
|
|
42
43
|
clang_tool_chain/execution/build.py,sha256=YHS1BJTZg5pBS9czVko41mBdfswSPad5hxfitMoLvsI,13275
|
|
43
44
|
clang_tool_chain/execution/build_pipeline.py,sha256=ORJEJ8WYp8c7bhWAa-e3w_ySXwenpUczlmXgoGByToY,17823
|
|
44
45
|
clang_tool_chain/execution/core.py,sha256=7CJ0azznC5lq5bw8amk2kwCIN2I_OnDiKytpapkvrdY,25273
|
|
@@ -58,7 +59,7 @@ clang_tool_chain/installers/iwyu.py,sha256=9aAhdGtOTY6BrLuPtladY8Y2mz1i7FjgbMxZf
|
|
|
58
59
|
clang_tool_chain/installers/lldb.py,sha256=FpG8NMNQk8PoNfg6aeU_plmSQrVET7zo-pTvoK8z838,2261
|
|
59
60
|
clang_tool_chain/installers/nodejs.py,sha256=5N07rotgmCfUaDm1uJfBlIAFKC1iTpgZT0HBRuoYwKI,9343
|
|
60
61
|
clang_tool_chain/linker/__init__.py,sha256=ghzDFpZ2-gPmdDO6K05C7yNbY6pZLANPuUks9TaQwVY,537
|
|
61
|
-
clang_tool_chain/linker/lld.py,sha256=
|
|
62
|
+
clang_tool_chain/linker/lld.py,sha256=OQLmCLNbj2BU0l5HxtHegHvXvblPITg8Gkm_EvJorKw,15381
|
|
62
63
|
clang_tool_chain/platform/__init__.py,sha256=WkV9Y25ua0mtzEGcsIxF-qExtroSTAMKkcElWuQF2BE,342
|
|
63
64
|
clang_tool_chain/platform/detection.py,sha256=PLHyUfmQ5xuohhpz0KSXJWK3d0u0fCsjx1DbM8f1CxQ,5470
|
|
64
65
|
clang_tool_chain/platform/paths.py,sha256=K0IjeVwbmgPlAWQO8mS3r1WS4C2dN6IYrSqPpckeT5c,6088
|
|
@@ -68,8 +69,8 @@ clang_tool_chain/sdk/windows.py,sha256=8zMLAoFz2OKMz-w6Kqxr3A-6Cofto2VWZvCvRi7kn
|
|
|
68
69
|
clang_tool_chain/testing/__init__.py,sha256=-sYqOOCuTV_u-MkmExrD4uKdTHG4RmMwR3D1kIG281Q,208
|
|
69
70
|
clang_tool_chain/testing/diagnostic_runner.py,sha256=mnmFUEOQulY3-Ggu6hKVGZwjrKQNmV6kY80PRTUu2qU,5293
|
|
70
71
|
clang_tool_chain/testing/diagnostic_tests.py,sha256=GmtKWrDcddZTpx9_yIKfhRAy6YOde8dj7SksCWVEME4,6019
|
|
71
|
-
clang_tool_chain-1.0.
|
|
72
|
-
clang_tool_chain-1.0.
|
|
73
|
-
clang_tool_chain-1.0.
|
|
74
|
-
clang_tool_chain-1.0.
|
|
75
|
-
clang_tool_chain-1.0.
|
|
72
|
+
clang_tool_chain-1.1.0.dist-info/METADATA,sha256=FU9mvPYq7qfmEGqYBb6ucjrrX3jCDIbJoKb1c9BSIic,57944
|
|
73
|
+
clang_tool_chain-1.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
74
|
+
clang_tool_chain-1.1.0.dist-info/entry_points.txt,sha256=N0a0OVPkCFbf6BisRkHj-m2TcZ-f1mqxfXxAHQxfrQg,2800
|
|
75
|
+
clang_tool_chain-1.1.0.dist-info/licenses/LICENSE,sha256=51FO1oc2pZbQNI0v0_THnznnZIF4iFgawG1xnQ58kKo,10997
|
|
76
|
+
clang_tool_chain-1.1.0.dist-info/RECORD,,
|
|
@@ -20,6 +20,7 @@ clang-tool-chain-format = clang_tool_chain.wrapper:clang_format_main
|
|
|
20
20
|
clang-tool-chain-iwyu = clang_tool_chain.wrapper:iwyu_main
|
|
21
21
|
clang-tool-chain-iwyu-tool = clang_tool_chain.wrapper:iwyu_tool_main
|
|
22
22
|
clang-tool-chain-ld = clang_tool_chain.wrapper:lld_main
|
|
23
|
+
clang-tool-chain-libdeploy = clang_tool_chain.deployment.libdeploy:main
|
|
23
24
|
clang-tool-chain-lldb = clang_tool_chain.wrapper:lldb_main
|
|
24
25
|
clang-tool-chain-lldb-check-python = clang_tool_chain.wrapper:lldb_check_python_main
|
|
25
26
|
clang-tool-chain-meson = clang_tool_chain.wrapper:meson_main
|
|
File without changes
|
|
File without changes
|