├── .github └── workflows │ └── create_wheels.yaml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.rst ├── ci └── install_rust.sh ├── pyproject.toml ├── setup.cfg ├── setup.py ├── src └── lib.rs └── tests ├── __init__.py └── test_demangle.py /.github/workflows/create_wheels.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ master ] 7 | tags: 8 | - v* 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build-wheels: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [macos-latest, ubuntu-latest, windows-latest] 18 | python-version: [37, 38, 39, 310, 311] 19 | 20 | steps: 21 | - uses: actions/checkout@v3 22 | 23 | - name: Set up QEMU 24 | if: runner.os == 'Linux' 25 | uses: docker/setup-qemu-action@v2 26 | with: 27 | platforms: all 28 | 29 | - name: Setup rust 30 | uses: actions-rs/toolchain@v1 31 | with: 32 | toolchain: stable 33 | 34 | - name: Build wheels 35 | uses: pypa/cibuildwheel@v2.11.3 36 | env: 37 | CIBW_BUILD: cp${{matrix.python-version}}-* 38 | CIBW_ENVIRONMENT: 'PATH="$HOME/.cargo/bin:$PATH" CARGO_TERM_COLOR="always"' 39 | CIBW_ENVIRONMENT_WINDOWS: 'PATH="$UserProfile\.cargo\bin;$PATH"' 40 | 41 | - name: Upload Binaries 42 | uses: actions/upload-artifact@v3 43 | with: 44 | name: wheels 45 | path: wheelhouse 46 | 47 | test-wheels: 48 | needs: [build-wheels] 49 | runs-on: ${{ matrix.os }} 50 | strategy: 51 | matrix: 52 | python-version: [3.7, 3.8, 3.9, '3.10', '3.11'] 53 | os: [macos-latest, ubuntu-latest, windows-latest] 54 | 55 | steps: 56 | - uses: actions/checkout@v3 57 | with: 58 | path: py_cpp_demangle_source 59 | - uses: actions/download-artifact@v3 60 | with: 61 | name: wheels 62 | - name: Set up Python ${{ matrix.python-version }} 63 | uses: actions/setup-python@v4 64 | with: 65 | python-version: ${{ matrix.python-version }} 66 | - name: Install wheel 67 | run: | 68 | pip install --force-reinstall --no-deps --no-index --find-links . cpp-demangle 69 | - name: Run unittests 70 | run: | 71 | python -m unittest discover py_cpp_demangle_source/tests 72 | 73 | release: 74 | name: Release 75 | runs-on: ubuntu-latest 76 | if: "startsWith(github.ref, 'refs/tags/')" 77 | needs: [test-wheels] 78 | steps: 79 | - uses: actions/download-artifact@v3 80 | with: 81 | name: wheels 82 | - name: Create GitHub Release 83 | uses: fnkr/github-action-ghr@v1.3 84 | env: 85 | GHR_PATH: . 86 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 87 | - uses: actions/setup-python@v2 88 | with: 89 | python-version: 3.9 90 | - name: Push to PyPi 91 | env: 92 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 93 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 94 | run: | 95 | pip install --upgrade wheel pip setuptools twine 96 | twine upload * 97 | rm * 98 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust 2 | /target 3 | **/*.rs.bk 4 | Cargo.lock 5 | 6 | # Python 7 | # Byte-compiled / optimized / DLL files 8 | __pycache__/ 9 | *.py[cod] 10 | *$py.class 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | env/ 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | *.egg-info/ 30 | .installed.cfg 31 | *.egg 32 | 33 | # PyInstaller 34 | # Usually these files are written by a python script from a template 35 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 36 | *.manifest 37 | *.spec 38 | 39 | # Installer logs 40 | pip-log.txt 41 | pip-delete-this-directory.txt 42 | 43 | # Unit test / coverage reports 44 | htmlcov/ 45 | .tox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *,cover 52 | .hypothesis/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | 61 | # Sphinx documentation 62 | docs/_build/ 63 | 64 | # PyBuilder 65 | target/ 66 | 67 | #Ipython Notebook 68 | .ipynb_checkpoints 69 | 70 | .vscode/ 71 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "py_cpp_demangle" 3 | version = "0.1.2" 4 | authors = ["Ben Frederickson "] 5 | edition = "2021" 6 | 7 | [lib] 8 | name = "cpp_demangle" 9 | crate-type = ["cdylib"] 10 | 11 | [dependencies] 12 | cpp_demangle = "0.4.0" 13 | 14 | [dependencies.pyo3] 15 | version = "0.17.3" 16 | features = ["extension-module"] 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ben Frederickson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | py-cpp-demangle: Demangles C++ linker symbols 2 | ============================================================ 3 | 4 | .. image:: https://github.com/benfred/py-cpp-demangle/workflows/Build/badge.svg?branch=master 5 | :target: https://github.com/benfred/py-cpp-demangle/actions?query=branch%3Amaster 6 | 7 | A package for demangling C++ linker symbol strings 8 | 9 | This package provides python bindings for the rust crate 10 | `cpp_demangle `_ by building 11 | a native Python extension using `PyO3 `_. 12 | 13 | This is mainly an experiment in creating python extensions in Rust. 14 | `A blog post about this is here. 15 | `_ 16 | 17 | Usage 18 | ------------------- 19 | 20 | To install 21 | 22 | .. code-block:: python 23 | 24 | pip install cpp-demangle 25 | 26 | 27 | Building from source requires the nightly version of the rust compiler. 28 | 29 | This module exposes a single function that transforms C++ linker symbols to a human readable 30 | representation. 31 | 32 | .. code-block:: python 33 | 34 | from cpp_demangle import demangle 35 | 36 | print(demangle('_ZN7mangled3fooEd')) 37 | # prints 'mangled::foo(double)' 38 | 39 | Released under the MIT License 40 | -------------------------------------------------------------------------------- /ci/install_rust.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d ~/rust-installer ]; then 2 | mkdir ~/rust-installer 3 | curl -sL https://static.rust-lang.org/rustup.sh -o ~/rust-installer/rustup.sh 4 | sh ~/rust-installer/rustup.sh -y 5 | source $HOME/.cargo/env 6 | rustup default stable 7 | fi 8 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.cibuildwheel] 2 | # skip testing in the cibuildwheel phase, will install the wheels later 3 | # and verify 4 | test-command = "" 5 | skip = ["pp*", "*musl*", "*-manylinux_i686", "*win32"] 6 | 7 | [tool.cibuildwheel.macos] 8 | archs = ["x86_64"] 9 | 10 | [build-system] 11 | requires = [ 12 | "setuptools>=42", 13 | "wheel", 14 | "setuptools_rust", 15 | ] 16 | build-backend = "setuptools.build_meta" 17 | 18 | [tool.cibuildwheel.linux] 19 | before-all = "ci/install_rust.sh" 20 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.1.2 3 | commit = True 4 | tag = True 5 | 6 | [bumpversion:file:setup.py] 7 | 8 | [bumpversion:file:Cargo.toml] 9 | search = name = "py_cpp_demangle" 10 | version = "{current_version}" 11 | replace = name = "py_cpp_demangle" 12 | version = "{new_version}" 13 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | from setuptools_rust import Binding, RustExtension 3 | 4 | setup(name='cpp-demangle', 5 | author="Ben Frederickson", 6 | author_email="ben@benfrederickson.com", 7 | url='http://github.com/benfred/py-cpp-demangle/', 8 | description="A package for demangling C++ linker symbols", 9 | long_description=open("README.rst").read(), 10 | version="0.1.2", 11 | rust_extensions=[RustExtension('cpp_demangle', 'Cargo.toml', binding=Binding.PyO3)], 12 | test_suite="tests", 13 | license="MIT", 14 | classifiers=[ 15 | "Development Status :: 3 - Alpha", 16 | "Programming Language :: Python :: 3", 17 | "Intended Audience :: Developers", 18 | "License :: OSI Approved :: MIT License", 19 | "Topic :: Software Development :: Libraries", 20 | "Topic :: Utilities"], 21 | zip_safe=False) 22 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | use pyo3::prelude::*; 2 | use pyo3::exceptions; 3 | 4 | 5 | 6 | // This defines a python module. pyo3 will copy the rust doc comment 7 | // below into a python docstring 8 | 9 | /// A package for demangling C++ linker symbols 10 | /// 11 | /// This package provides python bindings for the rust crate 12 | /// [cpp_demangle](http://github.com/gimli-rs/cpp_demangle) by building 13 | /// a native Python extension using [PyO3](https://github.com/pyO3/pyO3) 14 | /// 15 | /// Basic usage: 16 | /// 17 | /// >>> demangle('_ZN7mangled3fooEd') 18 | /// 'mangled::foo(double)' 19 | /// 20 | /// Passing an invalid identifier will throw a ValueError: 21 | /// 22 | /// >>> demangle('invalid c++ symbol') 23 | /// Traceback (most recent call last): 24 | /// ... 25 | /// ValueError: ('Could not demangle symbol', 'mangled symbol is not well-formed') 26 | #[pymodule] 27 | fn cpp_demangle(_py: Python, m: &PyModule) -> PyResult<()> { 28 | // This adds a function to the python module: 29 | /// Demangles a mangled c++ linker symbol name and returns it as a string 30 | #[pyfn(m)] 31 | fn demangle(mangled: String) -> PyResult { 32 | let symbol = ::cpp_demangle::Symbol::new(&mangled[..]).map_err(|error| { 33 | exceptions::PyValueError::new_err(("Could not demangle symbol", error.to_string())) 34 | })?; 35 | let demangled = symbol.demangle(&Default::default()).map_err(|error| { 36 | exceptions::PyValueError::new_err(( 37 | "Could not format demangled name as string", 38 | error.to_string(), 39 | )) 40 | })?; 41 | 42 | Ok(demangled) 43 | } 44 | 45 | Ok(()) 46 | } 47 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/benfred/py-cpp-demangle/44407c58a2ba044823385ce22c86fc1b23239587/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_demangle.py: -------------------------------------------------------------------------------- 1 | import doctest 2 | import cpp_demangle 3 | 4 | 5 | def load_tests(loader, tests, ignore): 6 | tests.addTests(doctest.DocTestSuite(cpp_demangle)) 7 | return tests 8 | --------------------------------------------------------------------------------