IncludeCPP 4.3.0__py3-none-any.whl → 4.6.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.
- includecpp/CHANGELOG.md +22 -0
- includecpp/__init__.py +1 -1
- includecpp/__init__.pyi +1 -4
- includecpp/cli/commands.py +1218 -25
- includecpp/core/cpp_api_extensions.pyi +204 -200
- includecpp/core/cssl/__init__.py +317 -0
- includecpp/core/cssl/cpp/build/api.pyd +0 -0
- includecpp/core/cssl/cpp/build/cssl_core.pyi +323 -0
- includecpp/core/cssl/cpp/build/libgcc_s_seh-1.dll +0 -0
- includecpp/core/cssl/cpp/build/libstdc++-6.dll +0 -0
- includecpp/core/cssl/cpp/build/libwinpthread-1.dll +0 -0
- includecpp/core/cssl/cpp/cssl_core.cp +108 -0
- includecpp/core/cssl/cpp/cssl_lexer.hpp +280 -0
- includecpp/core/cssl/cssl_builtins.py +142 -27
- includecpp/core/cssl/cssl_compiler.py +448 -0
- includecpp/core/cssl/cssl_optimizer.py +833 -0
- includecpp/core/cssl/cssl_parser.py +433 -38
- includecpp/core/cssl/cssl_runtime.py +294 -15
- includecpp/core/cssl/cssl_syntax.py +17 -0
- includecpp/core/cssl/cssl_types.py +143 -11
- includecpp/core/cssl_bridge.py +39 -2
- includecpp/generator/parser.cpp +38 -14
- includecpp/vscode/cssl/package.json +15 -0
- includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +96 -0
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/METADATA +1 -1
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/RECORD +30 -21
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/WHEEL +0 -0
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/entry_points.txt +0 -0
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/licenses/LICENSE +0 -0
- {includecpp-4.3.0.dist-info → includecpp-4.6.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CSSL Compiler Configuration - Special handling for CSSL C++ acceleration.
|
|
3
|
+
|
|
4
|
+
CSSL is a special case in IncludeCPP:
|
|
5
|
+
- Pre-built modules are bundled in the PyPI package for instant use
|
|
6
|
+
- If bundled module doesn't match user's platform, it rebuilds ONCE
|
|
7
|
+
- Global compiler/platform info stored in %AppData%/IncludeCPP/general.json
|
|
8
|
+
- IncludeCPP works normally for everything else
|
|
9
|
+
|
|
10
|
+
This module handles:
|
|
11
|
+
- Global compiler detection and caching
|
|
12
|
+
- Platform detection for module matching
|
|
13
|
+
- Auto-rebuild to bundled folder if needed
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import sys
|
|
18
|
+
import json
|
|
19
|
+
import platform
|
|
20
|
+
import subprocess
|
|
21
|
+
import shutil
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Optional, Dict, Any, List
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# =============================================================================
|
|
27
|
+
# Global IncludeCPP Config (shared across all projects)
|
|
28
|
+
# =============================================================================
|
|
29
|
+
|
|
30
|
+
def get_includecpp_config_dir() -> Path:
|
|
31
|
+
"""
|
|
32
|
+
Get global IncludeCPP config directory.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
Windows: %APPDATA%/IncludeCPP/
|
|
36
|
+
Linux/macOS: ~/.config/IncludeCPP/
|
|
37
|
+
"""
|
|
38
|
+
if sys.platform == 'win32':
|
|
39
|
+
base = Path(os.environ.get('APPDATA', Path.home() / 'AppData' / 'Roaming'))
|
|
40
|
+
else:
|
|
41
|
+
base = Path.home() / '.config'
|
|
42
|
+
|
|
43
|
+
config_dir = base / 'IncludeCPP'
|
|
44
|
+
config_dir.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
return config_dir
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_global_config_path() -> Path:
|
|
49
|
+
"""Get path to global IncludeCPP config file."""
|
|
50
|
+
return get_includecpp_config_dir() / 'general.json'
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_cssl_bundled_dir() -> Path:
|
|
54
|
+
"""
|
|
55
|
+
Get the bundled output directory for CSSL modules.
|
|
56
|
+
This is inside the PyPI package so users get pre-built modules.
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Path to includecpp/core/cssl/cpp/build/
|
|
60
|
+
"""
|
|
61
|
+
cssl_dir = Path(__file__).parent
|
|
62
|
+
build_dir = cssl_dir / 'cpp' / 'build'
|
|
63
|
+
build_dir.mkdir(parents=True, exist_ok=True)
|
|
64
|
+
return build_dir
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# Legacy function for compatibility
|
|
68
|
+
def get_cssl_config_dir() -> Path:
|
|
69
|
+
"""Legacy: Get CSSL config directory. Now uses global config."""
|
|
70
|
+
return get_includecpp_config_dir()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_cssl_config_path() -> Path:
|
|
74
|
+
"""Legacy: Get CSSL config path. Now uses global config."""
|
|
75
|
+
return get_global_config_path()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def get_cssl_build_dir() -> Path:
|
|
79
|
+
"""
|
|
80
|
+
Get build directory for CSSL modules.
|
|
81
|
+
CSSL is special: builds go to the PyPI bundled folder.
|
|
82
|
+
"""
|
|
83
|
+
return get_cssl_bundled_dir()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# =============================================================================
|
|
87
|
+
# Global Config Manager
|
|
88
|
+
# =============================================================================
|
|
89
|
+
|
|
90
|
+
class GlobalConfig:
|
|
91
|
+
"""
|
|
92
|
+
Global IncludeCPP configuration.
|
|
93
|
+
|
|
94
|
+
Stores compiler, platform info in %AppData%/IncludeCPP/general.json
|
|
95
|
+
Shared across all IncludeCPP projects.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
_instance = None
|
|
99
|
+
_config = None
|
|
100
|
+
|
|
101
|
+
def __new__(cls):
|
|
102
|
+
if cls._instance is None:
|
|
103
|
+
cls._instance = super().__new__(cls)
|
|
104
|
+
return cls._instance
|
|
105
|
+
|
|
106
|
+
def __init__(self):
|
|
107
|
+
if GlobalConfig._config is None:
|
|
108
|
+
self.config_path = get_global_config_path()
|
|
109
|
+
GlobalConfig._config = self._load_config()
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def config(self) -> Dict[str, Any]:
|
|
113
|
+
return GlobalConfig._config
|
|
114
|
+
|
|
115
|
+
@config.setter
|
|
116
|
+
def config(self, value: Dict[str, Any]):
|
|
117
|
+
GlobalConfig._config = value
|
|
118
|
+
|
|
119
|
+
def _load_config(self) -> Dict[str, Any]:
|
|
120
|
+
"""Load config from file, or return empty dict if not exists."""
|
|
121
|
+
if self.config_path.exists():
|
|
122
|
+
try:
|
|
123
|
+
return json.loads(self.config_path.read_text(encoding='utf-8'))
|
|
124
|
+
except (json.JSONDecodeError, OSError):
|
|
125
|
+
pass
|
|
126
|
+
return {}
|
|
127
|
+
|
|
128
|
+
def _save_config(self):
|
|
129
|
+
"""Save config to file."""
|
|
130
|
+
try:
|
|
131
|
+
self.config_path.write_text(
|
|
132
|
+
json.dumps(self.config, indent=2),
|
|
133
|
+
encoding='utf-8'
|
|
134
|
+
)
|
|
135
|
+
except OSError:
|
|
136
|
+
pass
|
|
137
|
+
|
|
138
|
+
def detect_compiler(self) -> Optional[str]:
|
|
139
|
+
"""
|
|
140
|
+
Detect available C++ compiler.
|
|
141
|
+
Checks: g++, clang++, cl (MSVC on Windows)
|
|
142
|
+
"""
|
|
143
|
+
compilers = ['g++', 'clang++']
|
|
144
|
+
if sys.platform == 'win32':
|
|
145
|
+
compilers.append('cl')
|
|
146
|
+
|
|
147
|
+
for compiler in compilers:
|
|
148
|
+
if shutil.which(compiler):
|
|
149
|
+
try:
|
|
150
|
+
result = subprocess.run(
|
|
151
|
+
[compiler, '--version'],
|
|
152
|
+
capture_output=True,
|
|
153
|
+
timeout=5
|
|
154
|
+
)
|
|
155
|
+
if result.returncode == 0:
|
|
156
|
+
return compiler
|
|
157
|
+
except (subprocess.SubprocessError, OSError):
|
|
158
|
+
continue
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
def detect_compiler_version(self, compiler: str) -> Optional[str]:
|
|
162
|
+
"""Get compiler version string."""
|
|
163
|
+
try:
|
|
164
|
+
result = subprocess.run(
|
|
165
|
+
[compiler, '--version'],
|
|
166
|
+
capture_output=True,
|
|
167
|
+
text=True,
|
|
168
|
+
timeout=5
|
|
169
|
+
)
|
|
170
|
+
if result.returncode == 0:
|
|
171
|
+
return result.stdout.split('\n')[0].strip()
|
|
172
|
+
except (subprocess.SubprocessError, OSError):
|
|
173
|
+
pass
|
|
174
|
+
return None
|
|
175
|
+
|
|
176
|
+
def detect_platform(self) -> Dict[str, str]:
|
|
177
|
+
"""Detect platform info for module matching."""
|
|
178
|
+
return {
|
|
179
|
+
'system': platform.system(),
|
|
180
|
+
'machine': platform.machine(),
|
|
181
|
+
'python_version': f"{sys.version_info.major}{sys.version_info.minor}",
|
|
182
|
+
'python_full_version': platform.python_version(),
|
|
183
|
+
'platform': sys.platform,
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
def get_module_suffix(self) -> str:
|
|
187
|
+
"""Get expected module suffix for current platform."""
|
|
188
|
+
info = self.detect_platform()
|
|
189
|
+
py_ver = info['python_version']
|
|
190
|
+
|
|
191
|
+
if info['platform'] == 'win32':
|
|
192
|
+
return f".cp{py_ver}-win_amd64.pyd"
|
|
193
|
+
elif info['platform'] == 'linux':
|
|
194
|
+
return f".cpython-{py_ver}-x86_64-linux-gnu.so"
|
|
195
|
+
elif info['platform'] == 'darwin':
|
|
196
|
+
arch = 'arm64' if info['machine'] == 'arm64' else 'x86_64'
|
|
197
|
+
return f".cpython-{py_ver}-{arch}-darwin.so"
|
|
198
|
+
return ".pyd" if info['platform'] == 'win32' else ".so"
|
|
199
|
+
|
|
200
|
+
def setup(self) -> Dict[str, Any]:
|
|
201
|
+
"""
|
|
202
|
+
First-run setup - detect and store compiler/platform info.
|
|
203
|
+
Called automatically on first import.
|
|
204
|
+
"""
|
|
205
|
+
if self.config.get('initialized'):
|
|
206
|
+
return self.config
|
|
207
|
+
|
|
208
|
+
compiler = self.detect_compiler()
|
|
209
|
+
compiler_version = self.detect_compiler_version(compiler) if compiler else None
|
|
210
|
+
platform_info = self.detect_platform()
|
|
211
|
+
|
|
212
|
+
self.config = {
|
|
213
|
+
'initialized': True,
|
|
214
|
+
'compiler': compiler,
|
|
215
|
+
'compiler_version': compiler_version,
|
|
216
|
+
'platform': platform_info,
|
|
217
|
+
'module_suffix': self.get_module_suffix(),
|
|
218
|
+
'can_compile': compiler is not None,
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
self._save_config()
|
|
222
|
+
return self.config
|
|
223
|
+
|
|
224
|
+
def refresh(self) -> Dict[str, Any]:
|
|
225
|
+
"""Force refresh of compiler/platform detection."""
|
|
226
|
+
self.config['initialized'] = False
|
|
227
|
+
return self.setup()
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# =============================================================================
|
|
231
|
+
# CSSL-Specific Compiler Config (wraps GlobalConfig)
|
|
232
|
+
# =============================================================================
|
|
233
|
+
|
|
234
|
+
class CSSLCompilerConfig:
|
|
235
|
+
"""
|
|
236
|
+
CSSL-specific compiler configuration.
|
|
237
|
+
|
|
238
|
+
CSSL is special:
|
|
239
|
+
- Uses global config from %AppData%/IncludeCPP/general.json
|
|
240
|
+
- Builds output to PyPI bundled folder (includecpp/core/cssl/cpp/build/)
|
|
241
|
+
- Auto-rebuilds if bundled module doesn't match platform
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
def __init__(self):
|
|
245
|
+
self.global_config = GlobalConfig()
|
|
246
|
+
self.config_path = get_global_config_path()
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
def config(self) -> Dict[str, Any]:
|
|
250
|
+
return self.global_config.config
|
|
251
|
+
|
|
252
|
+
def _load_config(self) -> Dict[str, Any]:
|
|
253
|
+
return self.global_config._load_config()
|
|
254
|
+
|
|
255
|
+
def _save_config(self):
|
|
256
|
+
self.global_config._save_config()
|
|
257
|
+
|
|
258
|
+
def detect_compiler(self) -> Optional[str]:
|
|
259
|
+
return self.global_config.detect_compiler()
|
|
260
|
+
|
|
261
|
+
def detect_compiler_version(self, compiler: str) -> Optional[str]:
|
|
262
|
+
return self.global_config.detect_compiler_version(compiler)
|
|
263
|
+
|
|
264
|
+
def detect_platform(self) -> Dict[str, str]:
|
|
265
|
+
return self.global_config.detect_platform()
|
|
266
|
+
|
|
267
|
+
def get_prebuilt_suffix(self) -> str:
|
|
268
|
+
return self.global_config.get_module_suffix()
|
|
269
|
+
|
|
270
|
+
def get_all_possible_suffixes(self) -> List[str]:
|
|
271
|
+
"""Get all possible module suffixes for current platform."""
|
|
272
|
+
info = self.detect_platform()
|
|
273
|
+
py_ver = info['python_version']
|
|
274
|
+
|
|
275
|
+
suffixes = [self.get_prebuilt_suffix()]
|
|
276
|
+
|
|
277
|
+
if info['platform'] == 'win32':
|
|
278
|
+
suffixes.extend(['.pyd', f'.cp{py_ver}-win32.pyd'])
|
|
279
|
+
elif info['platform'] == 'linux':
|
|
280
|
+
suffixes.extend(['.so', f'.cpython-{py_ver}-linux-gnu.so'])
|
|
281
|
+
elif info['platform'] == 'darwin':
|
|
282
|
+
suffixes.extend(['.so', '.dylib'])
|
|
283
|
+
|
|
284
|
+
return suffixes
|
|
285
|
+
|
|
286
|
+
def setup_first_run(self) -> Dict[str, Any]:
|
|
287
|
+
"""Setup global config on first run."""
|
|
288
|
+
return self.global_config.setup()
|
|
289
|
+
|
|
290
|
+
def refresh(self) -> Dict[str, Any]:
|
|
291
|
+
"""Force refresh of config."""
|
|
292
|
+
return self.global_config.refresh()
|
|
293
|
+
|
|
294
|
+
def can_compile(self) -> bool:
|
|
295
|
+
"""Check if compilation is possible."""
|
|
296
|
+
if not self.config.get('initialized'):
|
|
297
|
+
self.setup_first_run()
|
|
298
|
+
return self.config.get('can_compile', False)
|
|
299
|
+
|
|
300
|
+
def get_compiler(self) -> Optional[str]:
|
|
301
|
+
"""Get configured compiler."""
|
|
302
|
+
if not self.config.get('initialized'):
|
|
303
|
+
self.setup_first_run()
|
|
304
|
+
return self.config.get('compiler')
|
|
305
|
+
|
|
306
|
+
def get_platform_info(self) -> Dict[str, str]:
|
|
307
|
+
"""Get stored platform info."""
|
|
308
|
+
if not self.config.get('initialized'):
|
|
309
|
+
self.setup_first_run()
|
|
310
|
+
return self.config.get('platform', self.detect_platform())
|
|
311
|
+
|
|
312
|
+
def get_build_dir(self) -> Path:
|
|
313
|
+
"""Get CSSL build directory (bundled in PyPI folder)."""
|
|
314
|
+
return get_cssl_bundled_dir()
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
# =============================================================================
|
|
318
|
+
# CSSL Module Compilation
|
|
319
|
+
# =============================================================================
|
|
320
|
+
|
|
321
|
+
def compile_cssl_core(force: bool = False) -> Optional[Path]:
|
|
322
|
+
"""
|
|
323
|
+
Compile cssl_core module to the bundled PyPI folder.
|
|
324
|
+
|
|
325
|
+
CSSL builds go directly to includecpp/core/cssl/cpp/build/
|
|
326
|
+
so they're bundled with the package for other users.
|
|
327
|
+
|
|
328
|
+
Args:
|
|
329
|
+
force: If True, rebuild even if module exists
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
Path to compiled module, or None if failed
|
|
333
|
+
"""
|
|
334
|
+
config = CSSLCompilerConfig()
|
|
335
|
+
config.setup_first_run()
|
|
336
|
+
|
|
337
|
+
if not config.can_compile():
|
|
338
|
+
return None
|
|
339
|
+
|
|
340
|
+
# Output to bundled folder
|
|
341
|
+
build_dir = get_cssl_bundled_dir()
|
|
342
|
+
suffix = config.get_prebuilt_suffix()
|
|
343
|
+
output_path = build_dir / f'cssl_core{suffix}'
|
|
344
|
+
|
|
345
|
+
# Check if already built
|
|
346
|
+
if output_path.exists() and not force:
|
|
347
|
+
return output_path
|
|
348
|
+
|
|
349
|
+
# Get source directory
|
|
350
|
+
cssl_dir = Path(__file__).parent
|
|
351
|
+
cpp_dir = cssl_dir / 'cpp'
|
|
352
|
+
|
|
353
|
+
if not (cpp_dir / 'cpp.proj').exists():
|
|
354
|
+
return None
|
|
355
|
+
|
|
356
|
+
# Build using includecpp with output to bundled folder
|
|
357
|
+
try:
|
|
358
|
+
# IncludeCPP builds to AppData by default, so we build then copy
|
|
359
|
+
result = subprocess.run(
|
|
360
|
+
[sys.executable, '-m', 'includecpp', 'rebuild', '--clean'],
|
|
361
|
+
cwd=cpp_dir,
|
|
362
|
+
capture_output=True,
|
|
363
|
+
text=True,
|
|
364
|
+
timeout=300
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
if result.returncode == 0:
|
|
368
|
+
# Find built module and copy to bundled folder
|
|
369
|
+
appdata = Path(os.environ.get('APPDATA', ''))
|
|
370
|
+
icpp_build = appdata / 'cssl_core-g-build-proj' / 'bindings'
|
|
371
|
+
|
|
372
|
+
# Copy api.pyd to bundled folder
|
|
373
|
+
api_path = icpp_build / 'api.pyd'
|
|
374
|
+
if not api_path.exists():
|
|
375
|
+
api_path = icpp_build / 'api.so'
|
|
376
|
+
|
|
377
|
+
if api_path.exists():
|
|
378
|
+
# Copy as api.pyd (IncludeCPP format)
|
|
379
|
+
dest = build_dir / api_path.name
|
|
380
|
+
shutil.copy2(api_path, dest)
|
|
381
|
+
|
|
382
|
+
# Also copy as cssl_core.{suffix} for direct loading
|
|
383
|
+
shutil.copy2(api_path, output_path)
|
|
384
|
+
return output_path
|
|
385
|
+
|
|
386
|
+
except (subprocess.SubprocessError, OSError):
|
|
387
|
+
pass
|
|
388
|
+
|
|
389
|
+
return None
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
def get_cssl_core_path() -> Optional[Path]:
|
|
393
|
+
"""
|
|
394
|
+
Get path to cssl_core module.
|
|
395
|
+
|
|
396
|
+
CSSL special handling:
|
|
397
|
+
1. Check bundled folder in PyPI package
|
|
398
|
+
2. If not found and can compile, rebuild to bundled folder
|
|
399
|
+
|
|
400
|
+
Returns:
|
|
401
|
+
Path to module, or None if not found
|
|
402
|
+
"""
|
|
403
|
+
config = CSSLCompilerConfig()
|
|
404
|
+
config.setup_first_run()
|
|
405
|
+
|
|
406
|
+
suffixes = config.get_all_possible_suffixes()
|
|
407
|
+
build_dir = get_cssl_bundled_dir()
|
|
408
|
+
|
|
409
|
+
# Check for cssl_core.{suffix}
|
|
410
|
+
for suffix in suffixes:
|
|
411
|
+
module_path = build_dir / f'cssl_core{suffix}'
|
|
412
|
+
if module_path.exists():
|
|
413
|
+
return module_path
|
|
414
|
+
|
|
415
|
+
# Check for api.pyd (IncludeCPP format)
|
|
416
|
+
api_path = build_dir / 'api.pyd'
|
|
417
|
+
if not api_path.exists():
|
|
418
|
+
api_path = build_dir / 'api.so'
|
|
419
|
+
if api_path.exists():
|
|
420
|
+
return api_path
|
|
421
|
+
|
|
422
|
+
return None
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def ensure_cssl_module() -> Optional[Path]:
|
|
426
|
+
"""
|
|
427
|
+
Ensure CSSL C++ module is available.
|
|
428
|
+
|
|
429
|
+
If bundled module doesn't exist or doesn't match platform,
|
|
430
|
+
automatically rebuild to the bundled folder (ONCE).
|
|
431
|
+
|
|
432
|
+
Returns:
|
|
433
|
+
Path to module, or None if unavailable
|
|
434
|
+
"""
|
|
435
|
+
# Check if bundled module exists
|
|
436
|
+
module_path = get_cssl_core_path()
|
|
437
|
+
if module_path:
|
|
438
|
+
return module_path
|
|
439
|
+
|
|
440
|
+
# No bundled module - try to compile
|
|
441
|
+
config = CSSLCompilerConfig()
|
|
442
|
+
config.setup_first_run()
|
|
443
|
+
|
|
444
|
+
if config.can_compile():
|
|
445
|
+
# Rebuild to bundled folder
|
|
446
|
+
return compile_cssl_core(force=True)
|
|
447
|
+
|
|
448
|
+
return None
|