From 309835f4451d9615c47964ca032c7506ae361ff3 Mon Sep 17 00:00:00 2001 From: Kwabena N Amponsah Date: Fri, 22 Nov 2024 10:55:19 +0000 Subject: [PATCH] #20 Add castxml_compiler option --- .flake8 | 1 + README.md | 27 ++++++++++--------- cppwg/__main__.py | 8 ++++++ cppwg/generators.py | 16 ++++++++++- cppwg/info/class_info.py | 2 -- cppwg/info/cpp_entity_info.py | 1 - cppwg/info/free_function_info.py | 1 - cppwg/info/method_info.py | 1 - cppwg/info/variable_info.py | 1 - cppwg/parsers/source_parser.py | 12 +++++---- cppwg/writers/base_writer.py | 1 - cppwg/writers/class_writer.py | 4 +-- cppwg/writers/constructor_writer.py | 1 - cppwg/writers/free_function_writer.py | 1 - cppwg/writers/header_collection_writer.py | 1 - cppwg/writers/method_writer.py | 1 - examples/cells/src/py/pycells/_syntax.py | 1 - examples/cells/tests/test_cells.py | 1 - examples/shapes/src/py/pyshapes/_syntax.py | 1 - examples/shapes/src/py/tests/test_classes.py | 3 --- .../shapes/src/py/tests/test_functions.py | 1 - 21 files changed, 46 insertions(+), 40 deletions(-) diff --git a/.flake8 b/.flake8 index b3432bc..5d3b091 100644 --- a/.flake8 +++ b/.flake8 @@ -5,6 +5,7 @@ exclude = __pycache__, .git, .github, + .venv, build, cppwg/templates, doc, diff --git a/README.md b/README.md index 6927ced..3b48845 100644 --- a/README.md +++ b/README.md @@ -25,30 +25,30 @@ pip install . ## Usage ``` -usage: cppwg [-h] [-w WRAPPER_ROOT] [-p PACKAGE_INFO] [-c CASTXML_BINARY] - [--std STD] [-i [INCLUDES ...]] [-q] [-l [LOGFILE]] [-v] - SOURCE_ROOT +usage: cppwg [-h] [-w WRAPPER_ROOT] [-p PACKAGE_INFO] [-c CASTXML_BINARY] + [-m CASTXML_COMPILER] [--std STD] [-i [INCLUDES ...]] [-q] + [-l [LOGFILE]] [-v] SOURCE_ROOT Generate Python Wrappers for C++ code positional arguments: - SOURCE_ROOT Path to the root directory of the input C++ source - code. + SOURCE_ROOT Path to the root directory of the input C++ source code. options: -h, --help show this help message and exit - -w WRAPPER_ROOT, --wrapper_root WRAPPER_ROOT - Path to the output directory for the Pybind11 wrapper - code. - -p PACKAGE_INFO, --package_info PACKAGE_INFO + -w, --wrapper_root WRAPPER_ROOT + Path to the output directory for the Pybind11 wrapper code. + -p, --package_info PACKAGE_INFO Path to the package info file. - -c CASTXML_BINARY, --castxml_binary CASTXML_BINARY + -c, --castxml_binary CASTXML_BINARY Path to the castxml executable. + -m, --castxml_compiler CASTXML_COMPILER + Path to a compiler to be used by castxml. --std STD C++ standard e.g. c++17. - -i [INCLUDES ...], --includes [INCLUDES ...] + -i, --includes [INCLUDES ...] List of paths to include directories. -q, --quiet Disable informational messages. - -l [LOGFILE], --logfile [LOGFILE] + -l, --logfile [LOGFILE] Output log messages to a file. -v, --version Print cppwg version. ``` @@ -97,7 +97,8 @@ cd examples/shapes cppwg src/cpp \ --wrapper_root wrapper \ --package_info wrapper/package_info.yaml \ - --includes src/cpp/geometry src/cpp/math_funcs src/cpp/mesh src/cpp/primitives + --includes src/cpp/geometry src/cpp/math_funcs src/cpp/primitives \ + --std c++17 ``` For the `Rectangle` class, this creates two files in diff --git a/cppwg/__main__.py b/cppwg/__main__.py index 0d6e209..11fb62e 100644 --- a/cppwg/__main__.py +++ b/cppwg/__main__.py @@ -45,6 +45,13 @@ def parse_args() -> argparse.Namespace: help="Path to the castxml executable.", ) + parser.add_argument( + "-m", + "--castxml_compiler", + type=str, + help="Path to a compiler to be used by castxml.", + ) + # Note: we're passing in std directly because syntax like # --castxml_cflags "-std=c++17" isn't supported by argparse because of # the initial "-" in the argument. See https://bugs.python.org/issue9334 @@ -112,6 +119,7 @@ def generate(args: argparse.Namespace) -> None: package_info_path=args.package_info, castxml_binary=args.castxml_binary, castxml_cflags=castxml_cflags, + castxml_compiler=args.castxml_compiler, ) generator.generate() diff --git a/cppwg/generators.py b/cppwg/generators.py index c6aef3d..5b9b23d 100644 --- a/cppwg/generators.py +++ b/cppwg/generators.py @@ -3,6 +3,7 @@ import logging import os import re +import shutil import subprocess import uuid from pathlib import Path @@ -40,6 +41,8 @@ class CppWrapperGenerator: The path to the castxml binary castxml_cflags : str Optional cflags to be passed to castxml e.g. "-std=c++17" + castxml_compiler : str + Optional compiler path to be passed to CastXML package_info_path : str The path to the package info yaml config file; defaults to "package_info.yaml" source_ns : pygccxml.declarations.namespace_t @@ -56,6 +59,7 @@ def __init__( castxml_binary: Optional[str] = None, package_info_path: Optional[str] = None, castxml_cflags: Optional[str] = None, + castxml_compiler: Optional[str] = None, ): logger = logging.getLogger() @@ -100,6 +104,16 @@ def __init__( if castxml_cflags: self.castxml_cflags = f"{self.castxml_cflags} {castxml_cflags}" + # Try to set castxml compiler + if castxml_compiler: + self.castxml_compiler = castxml_compiler + else: + compiler_path = shutil.which("clang++") + if compiler_path: + self.castxml_compiler = compiler_path + else: + self.castxml_compiler = None + # Sanitize source_root self.source_root: str = os.path.abspath(source_root) if not os.path.isdir(self.source_root): @@ -195,7 +209,6 @@ def log_unknown_classes(self) -> None: # Check for uninstantiated class templates not parsed by pygccxml for hpp_file_path in self.package_info.source_hpp_files: - class_list = utils.find_classes_in_source_file(hpp_file_path) for _, class_name, _ in class_list: @@ -216,6 +229,7 @@ def parse_headers(self) -> None: self.castxml_binary, self.source_includes, self.castxml_cflags, + self.castxml_compiler, ) self.source_ns = source_parser.parse() diff --git a/cppwg/info/class_info.py b/cppwg/info/class_info.py index ff1cf8e..2542c3b 100644 --- a/cppwg/info/class_info.py +++ b/cppwg/info/class_info.py @@ -27,7 +27,6 @@ class CppClassInfo(CppEntityInfo): """ def __init__(self, name: str, class_config: Optional[Dict[str, Any]] = None): - super().__init__(name, class_config) self.base_decls: List["declaration_t"] = [] # noqa: F821 @@ -298,7 +297,6 @@ class instantiation. For example, class "Foo" with template arguments template_string = "" for idx, arg in enumerate(template_arg_list): - # Do standard name replacements arg_str = str(arg) for name, replacement in self.name_replacements.items(): diff --git a/cppwg/info/cpp_entity_info.py b/cppwg/info/cpp_entity_info.py index bbc60f0..2602659 100644 --- a/cppwg/info/cpp_entity_info.py +++ b/cppwg/info/cpp_entity_info.py @@ -32,7 +32,6 @@ class CppEntityInfo(BaseInfo): """ def __init__(self, name: str, entity_config: Optional[Dict[str, Any]] = None): - super().__init__(name, entity_config) self.name_override: str = "" diff --git a/cppwg/info/free_function_info.py b/cppwg/info/free_function_info.py index 3c927a9..b89cb41 100644 --- a/cppwg/info/free_function_info.py +++ b/cppwg/info/free_function_info.py @@ -11,7 +11,6 @@ class CppFreeFunctionInfo(CppEntityInfo): def __init__( self, name: str, free_function_config: Optional[Dict[str, Any]] = None ): - super().__init__(name, free_function_config) def update_from_ns(self, source_ns: "namespace_t") -> None: # noqa: F821 diff --git a/cppwg/info/method_info.py b/cppwg/info/method_info.py index d004903..0e010b3 100644 --- a/cppwg/info/method_info.py +++ b/cppwg/info/method_info.py @@ -16,7 +16,6 @@ class CppMethodInfo(CppEntityInfo): """ def __init__(self, name: str, _) -> None: - super().__init__(name) self.class_info: Optional["CppClassInfo"] = None # noqa: F821 diff --git a/cppwg/info/variable_info.py b/cppwg/info/variable_info.py index 8e58f93..c8c0dde 100644 --- a/cppwg/info/variable_info.py +++ b/cppwg/info/variable_info.py @@ -9,5 +9,4 @@ class CppVariableInfo(CppEntityInfo): """An information structure for individual variables to be wrapped.""" def __init__(self, name: str, variable_config: Optional[Dict[str, Any]] = None): - super().__init__(name, variable_config) diff --git a/cppwg/parsers/source_parser.py b/cppwg/parsers/source_parser.py index 211b797..785fb0b 100644 --- a/cppwg/parsers/source_parser.py +++ b/cppwg/parsers/source_parser.py @@ -30,14 +30,12 @@ class CppSourceParser: ---------- castxml_cflags : str Optional cflags to be passed to CastXML e.g. "-std=c++17" + castxml_compiler : str + Optional compiler path to be passed to CastXML castxml_binary : str The path to the CastXML binary - global_ns : namespace_t - The namespace containing all parsed C++ declarations source_includes : List[str] The list of source include paths - source_ns : namespace_t - The namespace containing C++ declarations from the source tree source_root : str The root directory of the source code wrapper_header_collection : str @@ -51,12 +49,14 @@ def __init__( castxml_binary: str, source_includes: List[str], castxml_cflags: str = "", + castxml_compiler: str = None, ): self.source_root: str = source_root self.wrapper_header_collection: str = wrapper_header_collection self.castxml_binary: str = castxml_binary self.source_includes: List[str] = source_includes self.castxml_cflags: str = castxml_cflags + self.castxml_compiler: str = castxml_compiler def parse(self) -> namespace_t: """ @@ -74,8 +74,10 @@ def parse(self) -> namespace_t: xml_generator_path=self.castxml_binary, xml_generator="castxml", cflags=self.castxml_cflags, + compiler_path=self.castxml_compiler, include_paths=self.source_includes, ) + logger.info(f"Using compiler: {xml_generator_config.compiler_path}") # Parse all the C++ source code to extract declarations logger.info("Parsing source code for declarations.") @@ -85,7 +87,7 @@ def parse(self) -> namespace_t: compilation_mode=parser.COMPILATION_MODE.ALL_AT_ONCE, ) - # Get access to the global namespace + # Get access to the global namespace containing all parsed C++ declarations global_ns: namespace_t = declarations.get_global_namespace(decls) # Filter declarations for which files exist diff --git a/cppwg/writers/base_writer.py b/cppwg/writers/base_writer.py index ca2f3cd..77c5536 100644 --- a/cppwg/writers/base_writer.py +++ b/cppwg/writers/base_writer.py @@ -17,7 +17,6 @@ class CppBaseWrapperWriter: """ def __init__(self, wrapper_templates: Dict[str, str]) -> None: - self.wrapper_templates = wrapper_templates self.tidy_replacements = OrderedDict( [ diff --git a/cppwg/writers/class_writer.py b/cppwg/writers/class_writer.py index 9efd8cf..c35afdf 100644 --- a/cppwg/writers/class_writer.py +++ b/cppwg/writers/class_writer.py @@ -292,9 +292,7 @@ def write(self, work_dir: str) -> None: continue # Find and define virtual function "trampoline" overrides - methods_needing_override: List["member_function_t"] = ( # noqa: F821 - self.add_virtual_overrides(idx) - ) + methods_needing_override = self.add_virtual_overrides(idx) # Add the virtual "trampoline" overrides from "Foo_Overrides" to # the "Foo" wrapper class definition if needed diff --git a/cppwg/writers/constructor_writer.py b/cppwg/writers/constructor_writer.py index 02073ba..e643550 100644 --- a/cppwg/writers/constructor_writer.py +++ b/cppwg/writers/constructor_writer.py @@ -39,7 +39,6 @@ def __init__( ctor_decl: "constructor_t", # noqa: F821 wrapper_templates: Dict[str, str], ) -> None: - super().__init__(wrapper_templates) self.class_info: "CppClassInfo" = class_info # noqa: F821 diff --git a/cppwg/writers/free_function_writer.py b/cppwg/writers/free_function_writer.py index de02532..4b931cc 100644 --- a/cppwg/writers/free_function_writer.py +++ b/cppwg/writers/free_function_writer.py @@ -21,7 +21,6 @@ class CppFreeFunctionWrapperWriter(CppBaseWrapperWriter): """ def __init__(self, free_function_info, wrapper_templates) -> None: - super().__init__(wrapper_templates) self.free_function_info: CppFreeFunctionInfo = free_function_info diff --git a/cppwg/writers/header_collection_writer.py b/cppwg/writers/header_collection_writer.py index 838e0cd..61bb278 100644 --- a/cppwg/writers/header_collection_writer.py +++ b/cppwg/writers/header_collection_writer.py @@ -39,7 +39,6 @@ def __init__( wrapper_root: str, hpp_collection_file: str, ): - self.package_info: PackageInfo = package_info self.wrapper_root: str = wrapper_root self.hpp_collection_file: str = hpp_collection_file diff --git a/cppwg/writers/method_writer.py b/cppwg/writers/method_writer.py index 5cb7f4b..e55298c 100644 --- a/cppwg/writers/method_writer.py +++ b/cppwg/writers/method_writer.py @@ -39,7 +39,6 @@ def __init__( method_decl: "member_function_t", # noqa: F821 wrapper_templates: Dict[str, str], ) -> None: - super().__init__(wrapper_templates) self.class_info: "CppClassInfo" = class_info # noqa: F821 diff --git a/examples/cells/src/py/pycells/_syntax.py b/examples/cells/src/py/pycells/_syntax.py index a6733ea..c37f900 100644 --- a/examples/cells/src/py/pycells/_syntax.py +++ b/examples/cells/src/py/pycells/_syntax.py @@ -5,7 +5,6 @@ class TemplateClassDict: - def __init__(self, template_dict): self._dict = {} for arg_tuple, cls in template_dict.items(): diff --git a/examples/cells/tests/test_cells.py b/examples/cells/tests/test_cells.py index 6b4390d..1e2e727 100644 --- a/examples/cells/tests/test_cells.py +++ b/examples/cells/tests/test_cells.py @@ -7,7 +7,6 @@ class TestCells(unittest.TestCase): - def testVtkCaster(self): scene = Scene[2]() renderer = scene.GetRenderer() diff --git a/examples/shapes/src/py/pyshapes/_syntax.py b/examples/shapes/src/py/pyshapes/_syntax.py index 2afd7e6..786444a 100644 --- a/examples/shapes/src/py/pyshapes/_syntax.py +++ b/examples/shapes/src/py/pyshapes/_syntax.py @@ -3,7 +3,6 @@ class TemplateClassDict: - def __init__(self, template_dict): self._dict = {} for arg_tuple, cls in template_dict.items(): diff --git a/examples/shapes/src/py/tests/test_classes.py b/examples/shapes/src/py/tests/test_classes.py index d723b25..b45b870 100644 --- a/examples/shapes/src/py/tests/test_classes.py +++ b/examples/shapes/src/py/tests/test_classes.py @@ -5,9 +5,7 @@ class TestClasses(unittest.TestCase): - def testGeometry(self): - p0 = pyshapes.geometry.Point_2() self.assertTrue(p0.GetLocation() == [0.0, 0.0]) @@ -36,7 +34,6 @@ def testGeometry(self): self.assertTrue(len(cuboid.rGetVertices()) == 8) def testSyntax(self): - self.assertEqual(pyshapes.geometry.Point[2], pyshapes.geometry.Point_2) point = pyshapes.geometry.Point[3](0.0, 1.0, 2.0) diff --git a/examples/shapes/src/py/tests/test_functions.py b/examples/shapes/src/py/tests/test_functions.py index 62a546b..47db051 100644 --- a/examples/shapes/src/py/tests/test_functions.py +++ b/examples/shapes/src/py/tests/test_functions.py @@ -4,7 +4,6 @@ class TestFunctions(unittest.TestCase): - def testAdd(self): a = 4 b = 5