IncludeCPP 4.6.4__tar.gz → 4.6.6__tar.gz

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.
Files changed (76) hide show
  1. {includecpp-4.6.4 → includecpp-4.6.6}/IncludeCPP.egg-info/PKG-INFO +1 -1
  2. {includecpp-4.6.4 → includecpp-4.6.6}/PKG-INFO +1 -1
  3. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/CHANGELOG.md +19 -0
  4. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/__init__.py +1 -1
  5. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/__init__.pyi +1 -1
  6. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/cli/commands.py +142 -34
  7. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/build_manager.py +4 -2
  8. includecpp-4.6.6/includecpp/core/cpp_api_extensions.pyi +165 -0
  9. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_builtins.py +325 -0
  10. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_optimizer.py +12 -1
  11. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_parser.py +12 -0
  12. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_runtime.py +15 -2
  13. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_syntax.py +29 -1
  14. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl_bridge.py +370 -1
  15. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/error_catalog.py +2 -5
  16. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/generator/parser.cpp +203 -39
  17. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/generator/parser.h +15 -1
  18. {includecpp-4.6.4 → includecpp-4.6.6}/pyproject.toml +1 -1
  19. {includecpp-4.6.4 → includecpp-4.6.6}/setup.py +1 -1
  20. includecpp-4.6.4/includecpp/core/cpp_api_extensions.pyi +0 -354
  21. {includecpp-4.6.4 → includecpp-4.6.6}/IncludeCPP.egg-info/SOURCES.txt +0 -0
  22. {includecpp-4.6.4 → includecpp-4.6.6}/IncludeCPP.egg-info/dependency_links.txt +0 -0
  23. {includecpp-4.6.4 → includecpp-4.6.6}/IncludeCPP.egg-info/entry_points.txt +0 -0
  24. {includecpp-4.6.4 → includecpp-4.6.6}/IncludeCPP.egg-info/requires.txt +0 -0
  25. {includecpp-4.6.4 → includecpp-4.6.6}/IncludeCPP.egg-info/top_level.txt +0 -0
  26. {includecpp-4.6.4 → includecpp-4.6.6}/LICENSE +0 -0
  27. {includecpp-4.6.4 → includecpp-4.6.6}/MANIFEST.in +0 -0
  28. {includecpp-4.6.4 → includecpp-4.6.6}/README.md +0 -0
  29. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/DOCUMENTATION.md +0 -0
  30. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/__main__.py +0 -0
  31. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/cli/__init__.py +0 -0
  32. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/cli/config_parser.py +0 -0
  33. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/__init__.py +0 -0
  34. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/ai_integration.py +0 -0
  35. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cpp_api.py +0 -0
  36. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cpp_api.pyi +0 -0
  37. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cppy_converter.py +0 -0
  38. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/CSSL_DOCUMENTATION.md +0 -0
  39. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/CSSL_DOCUMENTATION_NEW.md +0 -0
  40. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/__init__.py +0 -0
  41. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cpp/build/api.pyd +0 -0
  42. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cpp/build/cssl_core.pyi +0 -0
  43. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cpp/build/libgcc_s_seh-1.dll +0 -0
  44. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cpp/build/libstdc++-6.dll +0 -0
  45. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cpp/build/libwinpthread-1.dll +0 -0
  46. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cpp/cssl_core.cp +0 -0
  47. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cpp/cssl_lexer.hpp +0 -0
  48. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_builtins.pyi +0 -0
  49. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_compiler.py +0 -0
  50. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_events.py +0 -0
  51. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_languages.py +0 -0
  52. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_modules.py +0 -0
  53. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl/cssl_types.py +0 -0
  54. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/cssl_bridge.pyi +0 -0
  55. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/error_formatter.py +0 -0
  56. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/exceptions.py +0 -0
  57. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/path_discovery.py +0 -0
  58. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/project_ui.py +0 -0
  59. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/core/settings_ui.py +0 -0
  60. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/generator/__init__.py +0 -0
  61. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/generator/type_resolver.cpp +0 -0
  62. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/generator/type_resolver.h +0 -0
  63. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/py.typed +0 -0
  64. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/templates/cpp.proj.template +0 -0
  65. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/__init__.py +0 -0
  66. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/cssl/__init__.py +0 -0
  67. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/cssl/extension.js +0 -0
  68. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/cssl/images/cssl.png +0 -0
  69. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/cssl/images/cssl_pl.png +0 -0
  70. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/cssl/language-configuration.json +0 -0
  71. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/cssl/package.json +0 -0
  72. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/cssl/snippets/cssl.snippets.json +0 -0
  73. {includecpp-4.6.4 → includecpp-4.6.6}/includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +0 -0
  74. {includecpp-4.6.4 → includecpp-4.6.6}/requirements.txt +0 -0
  75. {includecpp-4.6.4 → includecpp-4.6.6}/setup.cfg +0 -0
  76. {includecpp-4.6.4 → includecpp-4.6.6}/tests/test_multilang.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 4.6.4
3
+ Version: 4.6.6
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: IncludeCPP
3
- Version: 4.6.4
3
+ Version: 4.6.6
4
4
  Summary: Professional C++ Python bindings with type-generic templates, pystubs and native threading
5
5
  Home-page: https://github.com/liliassg/IncludeCPP
6
6
  Author: Lilias Hatterscheidt
@@ -1,5 +1,24 @@
1
1
  # IncludeCPP Changelog
2
2
 
3
+ ## v4.6.6 (2026-01-14)
4
+
5
+ ### New Features
6
+ - **ENUM support**: Expose C++ enums to Python via `ENUM(EnumName) CLASS { values... }` syntax
7
+ - **Multiple SOURCE support**: `SOURCE(file1) && SOURCE(file2)` in .cp files
8
+ - **FIELD_ARRAY support**: C-style arrays now properly bound as read-only `bytes` properties
9
+ - Automatic detection of array fields in plugin command
10
+
11
+ ### Bug Fixes
12
+ - Fixed signed/unsigned comparison warning from pybind11 enum bindings
13
+ - Removed SIGNED_UNSIGNED from error catalog (was a warning, not error)
14
+ - Fixed array fields causing `invalid array assignment` error
15
+ - Version display now shows X.X format in build output
16
+
17
+ ### Breaking Changes
18
+ - Array fields in structs are now read-only (accessible as `bytes`)
19
+
20
+ ---
21
+
3
22
  ## v4.3.2 (2026-01-08)
4
23
 
5
24
  ### New Features
@@ -2,7 +2,7 @@ from .core.cpp_api import CppApi
2
2
  from .core import cssl_bridge as CSSL
3
3
  import warnings
4
4
 
5
- __version__ = "4.6.4"
5
+ __version__ = "4.6.6"
6
6
  __all__ = ["CppApi", "CSSL"]
7
7
 
8
8
  # Module-level cache for C++ modules
@@ -147,7 +147,7 @@ __version__: str
147
147
  # Dynamic module access via: from includecpp import <module_name>
148
148
  # Auto-generated module declarations
149
149
  # These allow: from includecpp import <module_name>
150
- cssl_core: Cssl_coreModuleWrapper
150
+ stepcompiler: StepcompilerModuleWrapper
151
151
 
152
152
  def __dir__() -> List[str]:
153
153
  """List available modules including dynamically loaded C++ modules."""
@@ -868,6 +868,11 @@ def _check_for_updates_silent():
868
868
  def _parse_cp_sources(cp_path):
869
869
  """Parse SOURCE() and HEADER() paths from an existing .cp file.
870
870
 
871
+ Supports multiple formats:
872
+ - Single SOURCE with multiple files: SOURCE(file1.cpp file2.cpp)
873
+ - Multiple SOURCE declarations: SOURCE(file1.cpp) && SOURCE(file2.cpp)
874
+ - Same for HEADER()
875
+
871
876
  Returns:
872
877
  Tuple of (source_files, header_files) as lists of Path objects
873
878
  """
@@ -881,11 +886,10 @@ def _parse_cp_sources(cp_path):
881
886
  content = cp_path.read_text()
882
887
  project_root = cp_path.parent.parent # plugins/ -> project root
883
888
 
884
- # Find SOURCE(...) declarations
885
- source_match = re.search(r'SOURCE\s*\(\s*([^)]+)\s*\)', content)
886
- if source_match:
887
- sources_str = source_match.group(1)
888
- # Handle multiple files: SOURCE(file1.cpp file2.cpp) or SOURCE(file1.cpp, file2.cpp)
889
+ # Find ALL SOURCE(...) declarations (supports multiple SOURCE() && SOURCE())
890
+ source_matches = re.findall(r'SOURCE\s*\(\s*([^)]+)\s*\)', content)
891
+ for sources_str in source_matches:
892
+ # Handle multiple files within one SOURCE(): SOURCE(file1.cpp file2.cpp) or SOURCE(file1.cpp, file2.cpp)
889
893
  sources = re.split(r'[,\s]+', sources_str.strip())
890
894
  for src in sources:
891
895
  src = src.strip()
@@ -896,10 +900,9 @@ def _parse_cp_sources(cp_path):
896
900
  if p.exists():
897
901
  source_files.append(p)
898
902
 
899
- # Find HEADER(...) declarations
900
- header_match = re.search(r'HEADER\s*\(\s*([^)]+)\s*\)', content)
901
- if header_match:
902
- headers_str = header_match.group(1)
903
+ # Find ALL HEADER(...) declarations
904
+ header_matches = re.findall(r'HEADER\s*\(\s*([^)]+)\s*\)', content)
905
+ for headers_str in header_matches:
903
906
  headers = re.split(r'[,\s]+', headers_str.strip())
904
907
  for hdr in headers:
905
908
  hdr = hdr.strip()
@@ -943,10 +946,16 @@ def rebuild(clean, keep, verbose, no_incremental, incremental, parallel, jobs, m
943
946
  """Rebuild C++ modules with automatic generator updates."""
944
947
  from ..core.build_manager import BuildManager
945
948
  from ..core.error_formatter import BuildErrorFormatter, BuildSuccessFormatter
949
+ from .. import __version__
946
950
  import time
947
951
  import json
948
952
  from datetime import datetime
949
953
 
954
+ # Show version (X.X format)
955
+ short_version = '.'.join(__version__.split('.')[:2])
956
+ click.secho(f"[IncludeCPP v{short_version}] ", fg='cyan', nl=False)
957
+ click.echo("Build starting...")
958
+
950
959
  # Combine -m modules with positional arguments
951
960
  # Allows both: includecpp rebuild -m gamekit AND includecpp rebuild gamekit
952
961
  all_modules = list(modules) + list(module_args)
@@ -2488,6 +2497,7 @@ def plugin(plugin_name, files, private):
2488
2497
  classes = {}
2489
2498
  functions = set()
2490
2499
  template_functions = {} # v3.1.6: {name: set of types}
2500
+ enums = {} # v4.6.5: {name: {'is_class': bool, 'values': list}}
2491
2501
  namespaces = set()
2492
2502
 
2493
2503
  def find_matching_brace(text, start_pos):
@@ -2898,15 +2908,27 @@ def plugin(plugin_name, files, private):
2898
2908
  if '&' not in actual_type:
2899
2909
  actual_type += '&'
2900
2910
 
2901
- # Remove array brackets if present
2911
+ # v4.6.6: Detect array fields and capture size
2912
+ array_size = 0
2902
2913
  if '[' in name:
2903
- name = name[:name.find('[')]
2914
+ # Extract array size: "magic[4]" -> size=4, name="magic"
2915
+ bracket_idx = name.find('[')
2916
+ end_bracket = name.find(']')
2917
+ if end_bracket > bracket_idx:
2918
+ size_str = name[bracket_idx+1:end_bracket].strip()
2919
+ try:
2920
+ array_size = int(size_str) if size_str else 0
2921
+ except ValueError:
2922
+ array_size = 0 # Unknown/variable size
2923
+ name = name[:bracket_idx].strip()
2904
2924
 
2905
2925
  # Validate field name
2906
2926
  if name and re.match(r'^[a-zA-Z_]\w*$', name):
2907
2927
  # Skip if name is a keyword
2908
2928
  if name.lower() not in cpp_keywords:
2909
- fields.append((actual_type, name))
2929
+ # v4.6.6: Include array info (type, name, array_size)
2930
+ # array_size=0 means not an array
2931
+ fields.append((actual_type, name, array_size))
2910
2932
 
2911
2933
  return fields
2912
2934
 
@@ -2946,6 +2968,11 @@ def plugin(plugin_name, files, private):
2946
2968
  is_struct = keyword == 'struct'
2947
2969
  brace_start = match.end() - 1
2948
2970
 
2971
+ # v4.6.5: Skip "enum class" declarations - check if preceded by "enum"
2972
+ text_before_match = content[max(0, match.start()-10):match.start()]
2973
+ if re.search(r'\benum\s*$', text_before_match):
2974
+ continue
2975
+
2949
2976
  text_before = content[:match.start()]
2950
2977
  open_braces = text_before.count('{')
2951
2978
  close_braces = text_before.count('}')
@@ -3071,23 +3098,67 @@ def plugin(plugin_name, files, private):
3071
3098
  if func_name not in template_func_names:
3072
3099
  functions.add(func_name)
3073
3100
 
3101
+ # v4.6.5: Find enum declarations
3102
+ enum_pattern = re.compile(
3103
+ r'\benum\s+(class\s+)?(\w+)\s*\{([^}]*)\}',
3104
+ re.MULTILINE | re.DOTALL
3105
+ )
3106
+
3107
+ for match in enum_pattern.finditer(content):
3108
+ is_class_enum = bool(match.group(1))
3109
+ enum_name = match.group(2)
3110
+ enum_body = match.group(3)
3111
+
3112
+ # Parse enum values
3113
+ values = []
3114
+ # Split by comma and extract value names (ignoring assignments)
3115
+ for part in enum_body.split(','):
3116
+ part = part.strip()
3117
+ if not part:
3118
+ continue
3119
+ # Get the value name (before any = assignment)
3120
+ value_name = part.split('=')[0].strip()
3121
+ if value_name and re.match(r'^[a-zA-Z_]\w*$', value_name):
3122
+ values.append(value_name)
3123
+
3124
+ if enum_name not in enums and values:
3125
+ enums[enum_name] = {
3126
+ 'is_class': is_class_enum,
3127
+ 'values': values
3128
+ }
3129
+
3074
3130
  private_set = set(private) if private else set()
3075
3131
  public_functions = functions - private_set - set(classes.keys())
3076
3132
 
3077
3133
  cp_file = plugins_dir / f"{plugin_name}.cp"
3078
3134
 
3079
- cpp_sources = ' '.join(str(f.relative_to(project_root) if f.is_relative_to(project_root) else f).replace('\\', '/') for f in cpp_files)
3080
- h_headers = ' '.join(str(f.relative_to(project_root) if f.is_relative_to(project_root) else f).replace('\\', '/') for f in h_files) if h_files else None
3135
+ # Generate individual SOURCE() declarations for each file (cleaner format)
3136
+ cpp_paths = [str(f.relative_to(project_root) if f.is_relative_to(project_root) else f).replace('\\', '/') for f in cpp_files]
3137
+ h_paths = [str(f.relative_to(project_root) if f.is_relative_to(project_root) else f).replace('\\', '/') for f in h_files] if h_files else []
3081
3138
 
3082
3139
  with open(cp_file, 'w', encoding='utf-8') as f:
3083
- if h_headers:
3084
- f.write(f'SOURCE({cpp_sources}) && HEADER({h_headers}) {plugin_name}\n\n')
3085
- else:
3086
- f.write(f'SOURCE({cpp_sources}) {plugin_name}\n\n')
3140
+ # Build the declaration line: SOURCE(file1) && SOURCE(file2) && HEADER(h1) plugin_name
3141
+ parts = [f'SOURCE({p})' for p in cpp_paths]
3142
+ parts.extend([f'HEADER({p})' for p in h_paths])
3143
+ declaration = ' && '.join(parts) + f' {plugin_name}'
3144
+ f.write(declaration + '\n\n')
3087
3145
 
3088
- if classes or public_functions or template_functions:
3146
+ if classes or public_functions or template_functions or enums:
3089
3147
  f.write('PUBLIC(\n')
3090
3148
 
3149
+ # v4.6.5: Write enum bindings
3150
+ for enum_name in sorted(enums.keys()):
3151
+ enum_info = enums[enum_name]
3152
+ is_class = enum_info.get('is_class', False)
3153
+ values = enum_info.get('values', [])
3154
+
3155
+ class_kw = ' CLASS' if is_class else ''
3156
+ values_str = ' '.join(values)
3157
+ f.write(f' {plugin_name} ENUM({enum_name}){class_kw} {{ {values_str} }}\n')
3158
+
3159
+ if enums and classes:
3160
+ f.write('\n')
3161
+
3091
3162
  for cls_name in sorted(classes.keys()):
3092
3163
  cls_info = classes[cls_name]
3093
3164
  f.write(f' {plugin_name} CLASS({cls_name}) {{\n')
@@ -3128,10 +3199,22 @@ def plugin(plugin_name, files, private):
3128
3199
  for method in sorted(cls_info['methods']):
3129
3200
  f.write(f' METHOD({method})\n')
3130
3201
 
3131
- # v3.2.2: Write fields (name only, type not needed in .cp)
3202
+ # v3.2.2: Write fields
3203
+ # v4.6.6: Support array fields with FIELD_ARRAY(name, type, size)
3132
3204
  if cls_info.get('fields'):
3133
- for field_type, field_name in cls_info['fields']:
3134
- f.write(f' FIELD({field_name})\n')
3205
+ for field_info in cls_info['fields']:
3206
+ # Handle both old (type, name) and new (type, name, array_size) formats
3207
+ if len(field_info) >= 3:
3208
+ field_type, field_name, array_size = field_info
3209
+ else:
3210
+ field_type, field_name = field_info
3211
+ array_size = 0
3212
+
3213
+ if array_size > 0:
3214
+ # Array field: use FIELD_ARRAY with type info for proper binding
3215
+ f.write(f' FIELD_ARRAY({field_name}, {field_type}, {array_size})\n')
3216
+ else:
3217
+ f.write(f' FIELD({field_name})\n')
3135
3218
 
3136
3219
  f.write(f' }}\n')
3137
3220
 
@@ -3155,6 +3238,7 @@ def plugin(plugin_name, files, private):
3155
3238
  f.write(')\n')
3156
3239
 
3157
3240
  click.secho(f"Generated plugin: {cp_file}", fg='green', bold=True)
3241
+ click.echo(f"Enums found: {len(enums)}")
3158
3242
  click.echo(f"Classes found: {len(classes)}")
3159
3243
  total_fields = sum(len(c.get('fields', [])) for c in classes.values())
3160
3244
  if total_fields:
@@ -6439,21 +6523,45 @@ def cppy_convert(files, to_cpp, to_py, no_header, output, ns, verbose, use_ai, u
6439
6523
 
6440
6524
 
6441
6525
  def _resolve_cp_source(cp_file: Path, project_root: Path) -> Path:
6442
- """Resolve SOURCE() directive from .cp file to actual source file."""
6526
+ """Resolve SOURCE() directive from .cp file to actual source file.
6527
+
6528
+ Returns the first valid source file found. Supports:
6529
+ - Single file: SOURCE(file.cpp)
6530
+ - Multiple files in one SOURCE: SOURCE(file1.cpp file2.cpp)
6531
+ - Multiple SOURCE declarations: SOURCE(file1.cpp) && SOURCE(file2.cpp)
6532
+ """
6443
6533
  try:
6444
6534
  content = cp_file.read_text(encoding='utf-8', errors='replace')
6445
6535
  import re
6446
- source_match = re.search(r'SOURCE\s*\(\s*([^)]+)\s*\)', content)
6447
- if source_match:
6448
- source_name = source_match.group(1).strip().strip('"\'')
6449
- include_dir = project_root / "include"
6450
- for ext in ['.cpp', '.h', '.hpp', '.cc', '.cxx']:
6451
- candidate = include_dir / (source_name.replace('.cpp', '').replace('.h', '') + ext)
6452
- if candidate.exists():
6453
- return candidate
6454
- direct = include_dir / source_name
6455
- if direct.exists():
6456
- return direct
6536
+
6537
+ # Find all SOURCE() declarations
6538
+ source_matches = re.findall(r'SOURCE\s*\(\s*([^)]+)\s*\)', content)
6539
+ for sources_str in source_matches:
6540
+ # Handle multiple files within one SOURCE()
6541
+ sources = re.split(r'[,\s]+', sources_str.strip())
6542
+ for source_name in sources:
6543
+ source_name = source_name.strip().strip('"\'')
6544
+ if not source_name:
6545
+ continue
6546
+
6547
+ include_dir = project_root / "include"
6548
+
6549
+ # Try direct path first (relative to project root)
6550
+ direct_from_root = project_root / source_name
6551
+ if direct_from_root.exists():
6552
+ return direct_from_root
6553
+
6554
+ # Try in include directory
6555
+ direct = include_dir / source_name
6556
+ if direct.exists():
6557
+ return direct
6558
+
6559
+ # Try with different extensions
6560
+ for ext in ['.cpp', '.h', '.hpp', '.cc', '.cxx']:
6561
+ base_name = source_name.replace('.cpp', '').replace('.h', '').replace('.hpp', '')
6562
+ candidate = include_dir / (base_name + ext)
6563
+ if candidate.exists():
6564
+ return candidate
6457
6565
  except Exception:
6458
6566
  pass
6459
6567
  return None
@@ -387,9 +387,11 @@ target_include_directories(api PRIVATE
387
387
  )
388
388
 
389
389
  if(MSVC)
390
- target_compile_options(api PRIVATE /W3 /O2 /EHsc /MT)
390
+ # /wd4018: disable signed/unsigned comparison warning (pybind11 enum issue)
391
+ target_compile_options(api PRIVATE /W3 /O2 /EHsc /MT /wd4018 /wd4267)
391
392
  else()
392
- target_compile_options(api PRIVATE -Wall -O3 -pthread)
393
+ # -Wno-sign-compare: disable signed/unsigned comparison warning (pybind11 enum issue)
394
+ target_compile_options(api PRIVATE -Wall -O3 -pthread -Wno-sign-compare)
393
395
  # MinGW on Windows: static linking for MinGW runtime and pthread
394
396
  if(WIN32)
395
397
  target_link_options(api PRIVATE -static-libgcc -static-libstdc++ -Wl,-Bstatic -lpthread -Wl,-Bdynamic -lws2_32)
@@ -0,0 +1,165 @@
1
+ """Auto-generated type stubs for IncludeCPP module wrappers.
2
+
3
+ This file enables VSCode IntelliSense autocomplete for C++ modules.
4
+ DO NOT EDIT - Auto-generated by IncludeCPP build system.
5
+ """
6
+
7
+ from typing import Any, List, Dict, Optional, Union, Protocol, overload
8
+
9
+ class StepcompilerModuleWrapper(Protocol):
10
+ """Type hints for stepcompiler module wrapper (VSCode autocomplete support)."""
11
+
12
+ def getInfo(self) -> Dict[str, Any]:
13
+ """Get stepcompiler module information."""
14
+ ...
15
+
16
+ class CryptoUtils:
17
+ """C++ class: CryptoUtils"""
18
+
19
+ def __init__(self) -> None:
20
+ """Initialize CryptoUtils instance"""
21
+ ...
22
+
23
+ def binaryToByte(self, *args: Any, **kwargs: Any) -> Any:
24
+ """C++ method: binaryToByte"""
25
+ ...
26
+
27
+ def byteToBinary(self, *args: Any, **kwargs: Any) -> Any:
28
+ """C++ method: byteToBinary"""
29
+ ...
30
+
31
+ def compress(self, *args: Any, **kwargs: Any) -> Any:
32
+ """C++ method: compress"""
33
+ ...
34
+
35
+ def crc32(self, *args: Any, **kwargs: Any) -> Any:
36
+ """C++ method: crc32"""
37
+ ...
38
+
39
+ def decompress(self, *args: Any, **kwargs: Any) -> Any:
40
+ """C++ method: decompress"""
41
+ ...
42
+
43
+ def deriveKeyStream(self, *args: Any, **kwargs: Any) -> Any:
44
+ """C++ method: deriveKeyStream"""
45
+ ...
46
+
47
+ def fromHexString(self, *args: Any, **kwargs: Any) -> Any:
48
+ """C++ method: fromHexString"""
49
+ ...
50
+
51
+ def generateIV(self, *args: Any, **kwargs: Any) -> Any:
52
+ """C++ method: generateIV"""
53
+ ...
54
+
55
+ def hashKey(self, *args: Any, **kwargs: Any) -> Any:
56
+ """C++ method: hashKey"""
57
+ ...
58
+
59
+ def scramble(self, *args: Any, **kwargs: Any) -> Any:
60
+ """C++ method: scramble"""
61
+ ...
62
+
63
+ def toHexString(self, *args: Any, **kwargs: Any) -> Any:
64
+ """C++ method: toHexString"""
65
+ ...
66
+
67
+ def xorEncrypt(self, *args: Any, **kwargs: Any) -> Any:
68
+ """C++ method: xorEncrypt"""
69
+ ...
70
+
71
+
72
+ class HDFileHeader:
73
+ """C++ class: HDFileHeader"""
74
+
75
+ def __init__(self) -> None:
76
+ """Initialize HDFileHeader instance"""
77
+ ...
78
+
79
+ pass
80
+
81
+ class StepCompiler:
82
+ """C++ class: StepCompiler"""
83
+
84
+ @overload
85
+ def __init__(self) -> None: ...
86
+ @overload
87
+ def __init__(self, arg0: str, arg1: str, arg2: str, arg3: str, arg4: bool, arg5: bool) -> None: ...
88
+
89
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
90
+ """Initialize StepCompiler instance"""
91
+ ...
92
+
93
+ def Decrypt(self, *args: Any, **kwargs: Any) -> Any:
94
+ """C++ method: Decrypt"""
95
+ ...
96
+
97
+ def Encrypt(self, *args: Any, **kwargs: Any) -> Any:
98
+ """C++ method: Encrypt"""
99
+ ...
100
+
101
+ def GetHeader(self, *args: Any, **kwargs: Any) -> Any:
102
+ """C++ method: GetHeader"""
103
+ ...
104
+
105
+ def GetOutputPath(self, *args: Any, **kwargs: Any) -> Any:
106
+ """C++ method: GetOutputPath"""
107
+ ...
108
+
109
+ def GetStatusMessage(self, *args: Any, **kwargs: Any) -> Any:
110
+ """C++ method: GetStatusMessage"""
111
+ ...
112
+
113
+ def Init(self, *args: Any, **kwargs: Any) -> Any:
114
+ """C++ method: Init"""
115
+ ...
116
+
117
+ def Process(self, *args: Any, **kwargs: Any) -> Any:
118
+ """C++ method: Process"""
119
+ ...
120
+
121
+
122
+
123
+
124
+ # CppApi with typed include() overloads for each module
125
+ class CppApi:
126
+ """C++ API Manager with typed module loading.
127
+
128
+ The include() method returns a module wrapper with full type hints
129
+ for VSCode/PyCharm autocomplete support.
130
+ """
131
+
132
+ def __init__(self, project_root: Optional[str] = None, auto_update: bool = True) -> None:
133
+ """Initialize CppApi.
134
+
135
+ Args:
136
+ project_root: Path to project root (default: auto-detect)
137
+ auto_update: Whether to auto-rebuild on source changes
138
+ """
139
+ ...
140
+
141
+ @overload
142
+ def include(self, module_name: str = "stepcompiler", auto_update: Optional[bool] = None) -> StepcompilerModuleWrapper: ...
143
+
144
+ @overload
145
+ def include(self, module_name: str, auto_update: Optional[bool] = None) -> Any: ...
146
+
147
+ def include(self, module_name: str, auto_update: Optional[bool] = None) -> Any:
148
+ """Load a C++ module.
149
+
150
+ Args:
151
+ module_name: Name of the module to load
152
+ auto_update: Override auto-update setting for this module
153
+
154
+ Returns:
155
+ ModuleWrapper with access to C++ classes, functions, and structs
156
+ """
157
+ ...
158
+
159
+ def rebuild(self, verbose: bool = False) -> bool:
160
+ """Rebuild all C++ modules."""
161
+ ...
162
+
163
+ def list_modules(self) -> List[str]:
164
+ """List available modules."""
165
+ ...