clang-tool-chain 1.0.3__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/__init__.py +0 -0
- clang_tool_chain/__version__.py +3 -0
- clang_tool_chain/checksums.py +270 -0
- clang_tool_chain/cli.py +572 -0
- clang_tool_chain/downloader.py +1325 -0
- clang_tool_chain/fetch.py +158 -0
- clang_tool_chain/paths.py +93 -0
- clang_tool_chain/sccache_runner.py +160 -0
- clang_tool_chain/wrapper.py +1589 -0
- clang_tool_chain-1.0.3.dist-info/METADATA +1815 -0
- clang_tool_chain-1.0.3.dist-info/RECORD +14 -0
- clang_tool_chain-1.0.3.dist-info/WHEEL +4 -0
- clang_tool_chain-1.0.3.dist-info/entry_points.txt +31 -0
- clang_tool_chain-1.0.3.dist-info/licenses/LICENSE +204 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI tool for fetching clang toolchain binaries.
|
|
3
|
+
|
|
4
|
+
This module provides a command-line interface for downloading and installing
|
|
5
|
+
the LLVM/Clang toolchain binaries.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import sys
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
|
|
12
|
+
from . import downloader, wrapper
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class FetchConfig:
|
|
17
|
+
"""Configuration for fetching toolchain binaries."""
|
|
18
|
+
|
|
19
|
+
platform: str | None
|
|
20
|
+
arch: str | None
|
|
21
|
+
output_dir: str | None
|
|
22
|
+
verbose: bool
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def parse_args() -> FetchConfig:
|
|
26
|
+
"""
|
|
27
|
+
Parse command-line arguments.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
FetchConfig dataclass with parsed arguments
|
|
31
|
+
"""
|
|
32
|
+
parser = argparse.ArgumentParser(
|
|
33
|
+
description="Fetch and install clang-tool-chain binaries",
|
|
34
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
35
|
+
epilog="""
|
|
36
|
+
Examples:
|
|
37
|
+
# Download for current platform
|
|
38
|
+
clang-tool-chain-fetch
|
|
39
|
+
|
|
40
|
+
# Download for specific platform (verbose)
|
|
41
|
+
clang-tool-chain-fetch --platform win --arch x86_64 --verbose
|
|
42
|
+
|
|
43
|
+
# Download to custom directory
|
|
44
|
+
clang-tool-chain-fetch --output-dir /custom/path --verbose
|
|
45
|
+
|
|
46
|
+
Environment Variables:
|
|
47
|
+
CLANG_TOOL_CHAIN_DOWNLOAD_PATH Override default download path (~/.clang-tool-chain)
|
|
48
|
+
""",
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
parser.add_argument(
|
|
52
|
+
"--platform",
|
|
53
|
+
choices=["win", "linux", "darwin"],
|
|
54
|
+
help="Target platform (default: current platform)",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
parser.add_argument(
|
|
58
|
+
"--arch",
|
|
59
|
+
choices=["x86_64", "arm64"],
|
|
60
|
+
help="Target architecture (required if --platform is specified, default: current arch)",
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
parser.add_argument(
|
|
64
|
+
"--output-dir",
|
|
65
|
+
metavar="PATH",
|
|
66
|
+
help="Output directory for downloads (overrides CLANG_TOOL_CHAIN_DOWNLOAD_PATH)",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
parser.add_argument(
|
|
70
|
+
"--verbose",
|
|
71
|
+
"-v",
|
|
72
|
+
action="store_true",
|
|
73
|
+
help="Show detailed progress information",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
args = parser.parse_args()
|
|
77
|
+
|
|
78
|
+
# Validate platform/arch combination
|
|
79
|
+
if args.platform and not args.arch:
|
|
80
|
+
parser.error("--arch is required when --platform is specified")
|
|
81
|
+
|
|
82
|
+
return FetchConfig(
|
|
83
|
+
platform=args.platform,
|
|
84
|
+
arch=args.arch,
|
|
85
|
+
output_dir=args.output_dir,
|
|
86
|
+
verbose=args.verbose,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def main() -> int:
|
|
91
|
+
"""
|
|
92
|
+
Main entry point for clang-tool-chain-fetch.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Exit code (0 for success, 1 for error)
|
|
96
|
+
"""
|
|
97
|
+
try:
|
|
98
|
+
config = parse_args()
|
|
99
|
+
|
|
100
|
+
# Determine platform and arch
|
|
101
|
+
if config.platform and config.arch:
|
|
102
|
+
platform = config.platform
|
|
103
|
+
arch = config.arch
|
|
104
|
+
else:
|
|
105
|
+
# Auto-detect current platform
|
|
106
|
+
platform, arch = wrapper.get_platform_info()
|
|
107
|
+
|
|
108
|
+
if config.verbose:
|
|
109
|
+
print(f"Platform: {platform}")
|
|
110
|
+
print(f"Architecture: {arch}")
|
|
111
|
+
|
|
112
|
+
# Set output directory if specified
|
|
113
|
+
if config.output_dir:
|
|
114
|
+
import os
|
|
115
|
+
|
|
116
|
+
os.environ["CLANG_TOOL_CHAIN_DOWNLOAD_PATH"] = config.output_dir
|
|
117
|
+
if config.verbose:
|
|
118
|
+
print(f"Output directory: {config.output_dir}")
|
|
119
|
+
|
|
120
|
+
# Download and install
|
|
121
|
+
downloader.ensure_toolchain(platform, arch)
|
|
122
|
+
|
|
123
|
+
# Check if download happened or was already installed
|
|
124
|
+
if downloader.is_toolchain_installed(platform, arch):
|
|
125
|
+
install_dir = downloader.get_install_dir(platform, arch)
|
|
126
|
+
bin_dir = install_dir / "bin"
|
|
127
|
+
|
|
128
|
+
if config.verbose or not downloader.is_toolchain_installed(platform, arch):
|
|
129
|
+
print("\nToolchain installed successfully!")
|
|
130
|
+
print(f"Install directory: {install_dir}")
|
|
131
|
+
print(f"Binary directory: {bin_dir}")
|
|
132
|
+
|
|
133
|
+
# Count binaries
|
|
134
|
+
if bin_dir.exists():
|
|
135
|
+
bin_count = len(list(bin_dir.iterdir()))
|
|
136
|
+
print(f"Binaries available: {bin_count}")
|
|
137
|
+
else:
|
|
138
|
+
print(f"Toolchain already installed at: {install_dir}")
|
|
139
|
+
|
|
140
|
+
return 0
|
|
141
|
+
else:
|
|
142
|
+
print("ERROR: Toolchain installation failed", file=sys.stderr)
|
|
143
|
+
return 1
|
|
144
|
+
|
|
145
|
+
except KeyboardInterrupt:
|
|
146
|
+
print("\nInterrupted by user", file=sys.stderr)
|
|
147
|
+
return 130
|
|
148
|
+
except Exception as e:
|
|
149
|
+
print(f"ERROR: {e}", file=sys.stderr)
|
|
150
|
+
if "--verbose" in sys.argv or "-v" in sys.argv:
|
|
151
|
+
import traceback
|
|
152
|
+
|
|
153
|
+
traceback.print_exc()
|
|
154
|
+
return 1
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if __name__ == "__main__":
|
|
158
|
+
sys.exit(main())
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CLI tool for displaying paths to installed toolchain binaries.
|
|
3
|
+
|
|
4
|
+
This module provides a command-line interface for listing all installed
|
|
5
|
+
toolchain binary paths in JSON format.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
from . import downloader, wrapper
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main() -> int:
|
|
15
|
+
"""
|
|
16
|
+
Main entry point for clang-tool-chain-paths.
|
|
17
|
+
|
|
18
|
+
Outputs JSON with paths to all installed tools.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Exit code (0 for success, 1 for error)
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
# Get current platform info
|
|
25
|
+
platform, arch = wrapper.get_platform_info()
|
|
26
|
+
|
|
27
|
+
# Check if toolchain is installed
|
|
28
|
+
if not downloader.is_toolchain_installed(platform, arch):
|
|
29
|
+
result = {
|
|
30
|
+
"error": "Toolchain not installed",
|
|
31
|
+
"platform": platform,
|
|
32
|
+
"arch": arch,
|
|
33
|
+
"installed": False,
|
|
34
|
+
"install_dir": None,
|
|
35
|
+
"bin_dir": None,
|
|
36
|
+
"tools": {},
|
|
37
|
+
}
|
|
38
|
+
print(json.dumps(result, indent=2))
|
|
39
|
+
return 1
|
|
40
|
+
|
|
41
|
+
# Get installation directories
|
|
42
|
+
install_dir = downloader.get_install_dir(platform, arch)
|
|
43
|
+
bin_dir = install_dir / "bin"
|
|
44
|
+
|
|
45
|
+
if not bin_dir.exists():
|
|
46
|
+
result = {
|
|
47
|
+
"error": "Binary directory not found",
|
|
48
|
+
"platform": platform,
|
|
49
|
+
"arch": arch,
|
|
50
|
+
"installed": True,
|
|
51
|
+
"install_dir": str(install_dir),
|
|
52
|
+
"bin_dir": str(bin_dir),
|
|
53
|
+
"tools": {},
|
|
54
|
+
}
|
|
55
|
+
print(json.dumps(result, indent=2))
|
|
56
|
+
return 1
|
|
57
|
+
|
|
58
|
+
# Enumerate all tools in bin directory
|
|
59
|
+
tools = {}
|
|
60
|
+
for binary_path in sorted(bin_dir.iterdir()):
|
|
61
|
+
if binary_path.is_file():
|
|
62
|
+
tool_name = binary_path.stem # Remove .exe on Windows
|
|
63
|
+
tools[tool_name] = str(binary_path)
|
|
64
|
+
|
|
65
|
+
# Build result
|
|
66
|
+
result = {
|
|
67
|
+
"platform": platform,
|
|
68
|
+
"arch": arch,
|
|
69
|
+
"installed": True,
|
|
70
|
+
"install_dir": str(install_dir),
|
|
71
|
+
"bin_dir": str(bin_dir),
|
|
72
|
+
"tool_count": len(tools),
|
|
73
|
+
"tools": tools,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# Output as JSON
|
|
77
|
+
print(json.dumps(result, indent=2))
|
|
78
|
+
return 0
|
|
79
|
+
|
|
80
|
+
except KeyboardInterrupt:
|
|
81
|
+
print("\nInterrupted by user", file=sys.stderr)
|
|
82
|
+
return 130
|
|
83
|
+
except Exception as e:
|
|
84
|
+
result = {
|
|
85
|
+
"error": str(e),
|
|
86
|
+
"installed": False,
|
|
87
|
+
}
|
|
88
|
+
print(json.dumps(result, indent=2))
|
|
89
|
+
return 1
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
sys.exit(main())
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""
|
|
2
|
+
sccache runner using iso-env for isolated execution.
|
|
3
|
+
|
|
4
|
+
This module provides fallback functionality to run sccache via iso-env
|
|
5
|
+
when sccache is not found in the system PATH.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import shutil
|
|
10
|
+
import subprocess
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_sccache_path() -> str | None:
|
|
16
|
+
"""
|
|
17
|
+
Get the path to sccache executable.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Path to sccache if found in PATH, None otherwise.
|
|
21
|
+
"""
|
|
22
|
+
return shutil.which("sccache")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_iso_env_cache_dir() -> Path:
|
|
26
|
+
"""
|
|
27
|
+
Get the cache directory for iso-env sccache installation.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
Path to the cache directory.
|
|
31
|
+
"""
|
|
32
|
+
# Use the same directory as clang-tool-chain for consistency
|
|
33
|
+
base_dir = os.environ.get("CLANG_TOOL_CHAIN_DOWNLOAD_PATH")
|
|
34
|
+
cache_dir = Path(base_dir) / "sccache-env" if base_dir else Path.home() / ".clang-tool-chain" / "sccache-env"
|
|
35
|
+
|
|
36
|
+
return cache_dir
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def run_sccache_via_isoenv(args: list[str]) -> int:
|
|
40
|
+
"""
|
|
41
|
+
Run sccache via iso-env in an isolated environment.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
args: Command-line arguments to pass to sccache
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
Exit code from sccache execution
|
|
48
|
+
"""
|
|
49
|
+
try:
|
|
50
|
+
from iso_env import IsoEnv, IsoEnvArgs, Requirements
|
|
51
|
+
except ImportError:
|
|
52
|
+
print("=" * 70, file=sys.stderr)
|
|
53
|
+
print("ERROR: iso-env package not found", file=sys.stderr)
|
|
54
|
+
print("=" * 70, file=sys.stderr)
|
|
55
|
+
print(file=sys.stderr)
|
|
56
|
+
print("iso-env is required as a fallback when sccache is not in PATH.", file=sys.stderr)
|
|
57
|
+
print("Please install it with:", file=sys.stderr)
|
|
58
|
+
print(" pip install clang-tool-chain", file=sys.stderr)
|
|
59
|
+
print(file=sys.stderr)
|
|
60
|
+
print("Or install sccache directly:", file=sys.stderr)
|
|
61
|
+
print(" pip install clang-tool-chain[sccache]", file=sys.stderr)
|
|
62
|
+
print(file=sys.stderr)
|
|
63
|
+
print("=" * 70, file=sys.stderr)
|
|
64
|
+
return 1
|
|
65
|
+
|
|
66
|
+
cache_dir = get_iso_env_cache_dir()
|
|
67
|
+
|
|
68
|
+
# Create iso-env configuration for sccache
|
|
69
|
+
try:
|
|
70
|
+
# First time setup - create the environment
|
|
71
|
+
print(f"Setting up isolated sccache environment at {cache_dir}...", file=sys.stderr)
|
|
72
|
+
|
|
73
|
+
# Create requirements for sccache
|
|
74
|
+
requirements_txt = "sccache>=0.7.0\n"
|
|
75
|
+
requirements = Requirements(requirements_txt)
|
|
76
|
+
|
|
77
|
+
# Create IsoEnvArgs
|
|
78
|
+
iso_args = IsoEnvArgs(venv_path=cache_dir, build_info=requirements)
|
|
79
|
+
|
|
80
|
+
# Create IsoEnv instance
|
|
81
|
+
env = IsoEnv(iso_args)
|
|
82
|
+
|
|
83
|
+
# Run sccache with the provided arguments
|
|
84
|
+
result = env.run(["sccache"] + args)
|
|
85
|
+
|
|
86
|
+
return result.returncode if result.returncode is not None else 0
|
|
87
|
+
|
|
88
|
+
except Exception as e:
|
|
89
|
+
print("=" * 70, file=sys.stderr)
|
|
90
|
+
print("ERROR: Failed to run sccache via iso-env", file=sys.stderr)
|
|
91
|
+
print("=" * 70, file=sys.stderr)
|
|
92
|
+
print(file=sys.stderr)
|
|
93
|
+
print(f"Error details: {e}", file=sys.stderr)
|
|
94
|
+
print(file=sys.stderr)
|
|
95
|
+
print("You may want to install sccache directly:", file=sys.stderr)
|
|
96
|
+
print(" pip install clang-tool-chain[sccache]", file=sys.stderr)
|
|
97
|
+
print(" cargo install sccache", file=sys.stderr)
|
|
98
|
+
print(" # or use your system package manager", file=sys.stderr)
|
|
99
|
+
print(file=sys.stderr)
|
|
100
|
+
print("=" * 70, file=sys.stderr)
|
|
101
|
+
return 1
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def run_sccache(args: list[str]) -> int:
|
|
105
|
+
"""
|
|
106
|
+
Run sccache, using iso-env as fallback if not found in PATH.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
args: Command-line arguments to pass to sccache
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Exit code from sccache execution
|
|
113
|
+
"""
|
|
114
|
+
sccache_path = get_sccache_path()
|
|
115
|
+
|
|
116
|
+
if sccache_path:
|
|
117
|
+
# sccache found in PATH, use it directly
|
|
118
|
+
cmd = [sccache_path] + args
|
|
119
|
+
|
|
120
|
+
try:
|
|
121
|
+
result = subprocess.run(cmd)
|
|
122
|
+
return result.returncode
|
|
123
|
+
except Exception as e:
|
|
124
|
+
print(f"ERROR: Failed to execute sccache: {e}", file=sys.stderr)
|
|
125
|
+
return 1
|
|
126
|
+
else:
|
|
127
|
+
# sccache not found in PATH, use iso-env fallback
|
|
128
|
+
print("sccache not found in PATH, using isolated environment...", file=sys.stderr)
|
|
129
|
+
print(file=sys.stderr)
|
|
130
|
+
return run_sccache_via_isoenv(args)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def run_sccache_with_compiler(compiler_path: str, args: list[str]) -> int:
|
|
134
|
+
"""
|
|
135
|
+
Run sccache with a compiler, using iso-env as fallback if sccache not found in PATH.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
compiler_path: Path to the compiler executable
|
|
139
|
+
args: Command-line arguments to pass to the compiler
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Exit code from sccache execution
|
|
143
|
+
"""
|
|
144
|
+
sccache_path = get_sccache_path()
|
|
145
|
+
|
|
146
|
+
if sccache_path:
|
|
147
|
+
# sccache found in PATH, use it directly
|
|
148
|
+
cmd = [sccache_path, compiler_path] + args
|
|
149
|
+
|
|
150
|
+
try:
|
|
151
|
+
result = subprocess.run(cmd)
|
|
152
|
+
return result.returncode
|
|
153
|
+
except Exception as e:
|
|
154
|
+
print(f"ERROR: Failed to execute sccache: {e}", file=sys.stderr)
|
|
155
|
+
return 1
|
|
156
|
+
else:
|
|
157
|
+
# sccache not found in PATH, use iso-env fallback
|
|
158
|
+
print("sccache not found in PATH, using isolated environment...", file=sys.stderr)
|
|
159
|
+
print(file=sys.stderr)
|
|
160
|
+
return run_sccache_via_isoenv([compiler_path] + args)
|