diff --git a/bindings/pyroot/cppyy/cppyy-backend/.circleci/config.yml b/bindings/pyroot/cppyy/cppyy-backend/.circleci/config.yml new file mode 100644 index 0000000000000..856bea23ac884 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/.circleci/config.yml @@ -0,0 +1,42 @@ +version: 2.1 + +parameters: + build_aarch64_wheel: + description: "Whether to build aarch64 wheel on CircleCI" + default: false + type: boolean + + +jobs: + linux-aarch64-wheels: + working_directory: ~/linux-aarch64-wheels + machine: + image: ubuntu-2004:2022.04.1 + # resource_class is what tells CircleCI to use an ARM worker for native arm builds + # https://circleci.com/product/features/resource-classes/ + resource_class: arm.large + environment: + STDCXX: 20 + MAKE_NPROCS: 4 + steps: + - checkout + - run: + name: Build the Linux aarch64 wheels. + command: | + python3 -m venv venv + . venv/bin/activate + python3 -m pip install pip --upgrade + python3 -m pip install cibuildwheel==2.12.0 + python3 -m cibuildwheel cling --print-build-identifiers + python3 -m cibuildwheel cling --output-dir wheelhouse + - store_artifacts: + path: wheelhouse/ + + +workflows: + version: 2 + build-aarch64-wheels: + when: << pipeline.parameters.build_aarch64_wheel >> + jobs: + - linux-aarch64-wheels + diff --git a/bindings/pyroot/cppyy/cppyy-backend/.github/workflows/cling-wheels.yml b/bindings/pyroot/cppyy/cppyy-backend/.github/workflows/cling-wheels.yml new file mode 100644 index 0000000000000..131675c022d8b --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/.github/workflows/cling-wheels.yml @@ -0,0 +1,157 @@ +name: Build and upload to PyPI + +on: [workflow_dispatch] + +jobs: + #build-aarch64-wheels: + # runs-on: ubuntu-latest + # outputs: + # job_number: ${{ steps.aarch64-job-number.outputs.job_number }} + # steps: + # - uses: actions/checkout@v3 + # + # - name: Setup python + # uses: actions/setup-python@v4 + # with: + # python-version: "3.10" + # - name: Trigger circleci build for ARM + # id: aarch64-job-number + # run: | + # export JOB_NUMBER=$(python3 circleci.py job --token ${{ secrets.CIRCLE_API_TOKEN }}) + # echo "job_number=$JOB_NUMBER" >> "$GITHUB_OUTPUT" + + build_wheels: + name: Build wheels on ${{ matrix.platform_id }} + runs-on: ${{ matrix.os }} + + env: + CIBW_BUILD: cp${{ matrix.python }}-${{ matrix.platform_id }} + CIBW_ARCHS: "${{ matrix.cibw.arch || 'auto' }}" + CIBW_MANYLINUX_X86_64_IMAGE: ${{ matrix.manylinux_image }} + CIBW_MANYLINUX_I686_IMAGE: ${{ matrix.manylinux_image }} + + strategy: + fail-fast: false + matrix: + include: + #- os: macos-14 + # name: mac-cpython + # python: 310 + # platform_id: macosx_x86_64 + + # cross-compilation platform, disabled because tools build + # during the build process won't run + #- os: macos-latest + # name: mac-cpython-arm + # python: 310 + # platform_id: macosx_arm64 + # cibw: + # arch: arm64 + + - os: ubuntu-latest + name: manylinux2014-x86_64 + python: 310 + platform_id: manylinux_x86_64 + manylinux_image: manylinux2014 + + #- os: ubuntu-latest + # name: manylinux2014-i686 + # python: 310 + # platform_id: manylinux_i686 + # manylinux_image: manylinux2014 + + - os: windows-latest + name: win32 + python: 310 + platform_id: win32 + + - os: windows-latest + name: win_amd64 + python: 310 + platform_id: win_amd64 + + # cross-compilation platform (requires cross-compilation setup + # for cmake configuration), disabled because tools build during + # the build process won't run + #- os: windows-latest + # name: win32-arm64 + # python: 310 + # platform_id: win_arm64 + # cibw: + # arch: ARM64 + + steps: + - uses: actions/checkout@v3 + + - name: setup python + uses: actions/setup-python@v4 + with: + python-version: "3.10" + architecture: ${{ matrix.architecture }} + + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v2 + with: + platforms: all + + #- name: customize mac-arm-64 + # if: contains(matrix.os, 'macos') && matrix.platform_id == 'macosx_arm64' + # run: | + # echo 'MACOSX_DEPLOYMENT_TARGET=10.15' >> "$GITHUB_ENV" + + - name: Install cibuildwheel + run: | + python -m pip install cibuildwheel==2.12.0 + + - name: list target wheels + run: | + python -m cibuildwheel cling --print-build-identifiers + + - name: Build wheels + timeout-minutes: 600 + run: | + python -m cibuildwheel cling --output-dir wheelhouse + + - uses: actions/upload-artifact@v4 + with: + # add unique name as artifact@v4 workaround, after cibuildwheel + name: cppyy-cling-wheels-${{ matrix.os }}-${{ strategy.job-index }} + path: ./wheelhouse/*.whl + + #build_sdist: + # name: Build source distribution + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v3 + # + # - name: Build sdist + # run: cd cling && pipx run build --sdist + # + # - uses: actions/upload-artifact@v3 + # with: + # path: ./cling/dist/*.tar.gz + + #upload_aarch64_wheel: + # needs: [build_wheels, build-aarch64-wheels] # Just wait until this workflow is done - then aarch64 should be done + # runs-on: ubuntu-latest + # + # steps: + # - name: Checkout + # uses: actions/checkout@v3 + # + # - name: Setup python + # uses: actions/setup-python@v4 + # with: + # python-version: "3.10" + # + # - name: Get wheel from CircleCI artifact + # env: + # JOB_NUMBER: ${{ needs.build-aarch64-wheels.outputs.job_number }} + # run: | + # export WHEEL_PATH=$(python circleci.py artifact --job-number $JOB_NUMBER --token ${{ secrets.CIRCLE_API_TOKEN }}) + # echo "wheel_path=$WHEEL_PATH" >> "$GITHUB_ENV" + # + # - uses: actions/upload-artifact@v3 + # with: + # path: ${{ env.wheel_path }} diff --git a/bindings/pyroot/cppyy/cppyy-backend/.gitignore b/bindings/pyroot/cppyy/cppyy-backend/.gitignore index 99c41e704969a..2184627bef7dc 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/.gitignore +++ b/bindings/pyroot/cppyy/cppyy-backend/.gitignore @@ -1,6 +1,6 @@ releases/ root-*/ -cling/src/ +cling/src/interpreter builddir/ # Byte-compiled / optimized / DLL files @@ -14,7 +14,6 @@ __pycache__/ # Distribution / packaging .Python env/ -build/ develop-eggs/ dist/ downloads/ diff --git a/bindings/pyroot/cppyy/cppyy-backend/circleci.py b/bindings/pyroot/cppyy/cppyy-backend/circleci.py new file mode 100644 index 0000000000000..47733aa8b317d --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/circleci.py @@ -0,0 +1,139 @@ +import http.client +from typing import Sequence +import argparse +import os +import urllib.request +from pathlib import Path +import time +import json + +import sys + + +def get_artifact( + token: str, + vcs: str = "github", + org: str = "wlav", + project: str = "cppyy-backend", + job_number: int = 0, + **kwargs, +) -> int: + + conn = http.client.HTTPSConnection("circleci.com") + + headers = {"Circle-Token": token} + + conn.request( + "GET", + f"/api/v2/project/{vcs}/{org}/{project}/{job_number}/artifacts", + headers=headers, + ) + + res = conn.getresponse() + data = json.loads(res.read().decode("utf-8")) + url = data["items"][0]["url"] + path = Path(data["items"][0]["path"]) + path.parent.mkdir(exist_ok=True) + + urllib.request.urlretrieve(url, path) + time.sleep(1.0) + print(path) + return 0 + + +def start_job( + token: str, + vcs: str = "github", + org: str = "wlav", + project: str = "cppyy-backend", + build_aarch64_wheel: bool = True, + branch: str = "master", + **kwargs, +) -> int: + import http.client + + conn = http.client.HTTPSConnection("circleci.com") + + headers = { + "content-type": "application/json", + "Circle-Token": f"{token}", + } + + # Start pipeline + payload = { + "branch": branch, + "parameters": {"build_aarch64_wheel": build_aarch64_wheel}, + } + conn.request( + "POST", + f"/api/v2/project/{vcs}/{org}/{project}/pipeline", + json.dumps(payload), + headers, + ) + res = conn.getresponse() + pipeline_data = json.loads(res.read().decode("utf-8")) + time.sleep(1.0) + + # Get pipeline id + conn.request( + "GET", + f"/api/v2/project/{vcs}/{org}/{project}/pipeline/{pipeline_data['number']}", + headers=headers, + ) + res = conn.getresponse() + data = json.loads(res.read().decode("utf-8")) + + time.sleep(1.0) + + # Get workflow id + conn.request( + "GET", + f"/api/v2/pipeline/{data['id']}/workflow", + headers=headers, + ) + + res = conn.getresponse() + workflow_data = json.loads(res.read().decode("utf-8")) + + time.sleep(1.0) + + # Get job id + conn.request( + "GET", + f"/api/v2/workflow/{workflow_data['items'][0]['id']}/job", + headers=headers, + ) + + res = conn.getresponse() + job_data = json.loads(res.read().decode("utf-8")) + + return 0 + + +def main(argv: Sequence[str] | None = None) -> int: + parser = argparse.ArgumentParser() + + parser.add_argument("--token", default=os.environ.get("CIRCLE_API_TOKEN")) + parser.add_argument("mode", choices=["artifact", "job"]) + parser.add_argument("--vcs", default="github") + parser.add_argument("--org", default="wlav") + parser.add_argument("--project", default="cppyy-backend") + parser.add_argument("--job-number", default=0) + parser.add_argument("--build-aarch64-wheel", default=True) + + kwargs = vars(parser.parse_args(argv)) + mode = kwargs.pop("mode") + + if mode == "artifact": + return get_artifact(**kwargs) + + if mode == "job": + return start_job(**kwargs) + + print("Invaild arguments") + print(f"You entered: {kwargs}") + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/LICENSE.txt b/bindings/pyroot/cppyy/cppyy-backend/cling/LICENSE.txt index c5a5b34514dcc..b94be0c88516b 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/LICENSE.txt +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2017-2019, The Regents of the University of California, +Copyright (c) 2017-2021, The Regents of the University of California, through Lawrence Berkeley National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved. Redistribution and use in source and binary forms, with or @@ -53,24 +53,34 @@ source code): Ellis Breen Antonio Cuni Aditi Dutta + Henrik Finsberg Shaheed Haque + Dennis Hemker + Jean Hominal Jonsomi + Baidyanath Kundu Alvaro Moran Tarmo Pikaro Matti Picus Camille Scott + Clemens Wolff External code ------------- -The create_src_directory.py script will pull in ROOT and LLVM sources, which -are licensed differently: +The 'src' directory contains source code from the ROOT project; these codes +have been extensively patched. The create_src_directory.py script will pull +in Cling and LLVM source codes, and apply some more patches. + +These codes are licensed as follows: LLVM: distributed under University of Illinois/NCSA Open Source License https://opensource.org/licenses/UoI-NCSA.php + Cling: distributed under University of Illinois/NCSA Open Source License + https://opensource.org/licenses/UoI-NCSA.php ROOT: distributed under LGPL 2.1 - https://root.cern.ch/license + https://root.cern.ch/license (see also src/LICENSE) -The ROOT and LLVM/Clang codes are modified/patched, as part of the build -process. +The ROOT code is build into independent shared libraries to allow use under +LGPL. The Cling and LLVM codes are combined into a single shared library. diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/README.rst b/bindings/pyroot/cppyy/cppyy-backend/cling/README.rst index 8256ae781314f..644886dc4d533 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/README.rst +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/README.rst @@ -14,9 +14,8 @@ used, but it is also recommended to add the verbose flag to see progress: For further details, see cppyy's installation instructions: https://cppyy.readthedocs.io/en/latest/installation.html - Cling documentation is here: - https://root.cern.ch/cling + https://github.com/vgvassilev/cling ---- @@ -27,4 +26,4 @@ Change log: https://cppyy.readthedocs.io/en/latest/changelog.html Bug reports/feedback: - https://bitbucket.org/wlav/cppyy/issues?status=new&status=open + https://github.com/wlav/cppyy/issues diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/create_src_directory.py b/bindings/pyroot/cppyy/cppyy-backend/cling/create_src_directory.py index 8d5859f4e6fed..7e461ac3170a4 100755 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/create_src_directory.py +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/create_src_directory.py @@ -1,8 +1,13 @@ #!/usr/bin/env python from __future__ import print_function -import os, sys, subprocess -import shutil, tarfile +import contextlib +import os +import shutil +import subprocess +import sys +import tarfile + try: import urllib2 except ModuleNotFoundError: @@ -19,7 +24,10 @@ def is_manylinux(): _is_manylinux = False try: for line in open('/etc/redhat-release').readlines(): - if 'CentOS release 6.10 (Final)' in line: + # mark manylinux1, manylinux2010, or manylinux2014 + if 'CentOS release 5.11 (Final)' in line or \ + 'CentOS release 6.10 (Final)' in line or \ + 'CentOS Linux release 7.9.2009 (Core)' in line: _is_manylinux = True break except (OSError, IOError): @@ -28,101 +36,14 @@ def is_manylinux(): DEBUG_TESTBUILD = False - TARBALL_CACHE_DIR = 'releases' - -ROOT_KEEP = ['build', 'cmake', 'config', 'core', 'etc', 'interpreter', - 'io', 'LICENSE', 'LGPL2_1.txt', 'Makefile', 'CMakeLists.txt', 'math', - 'main', # main only needed in more recent root b/c of rootcling - 'builtins'] -ROOT_CORE_KEEP = ['CMakeLists.txt', 'base', 'clib', 'clingutils', 'cont', - 'dictgen', 'foundation', 'macosx', 'meta', - 'metacling', 'metautils', 'rootcling_stage1', 'textinput', - 'thread', 'unix', 'utils', 'winnt', 'zip'] -ROOT_BUILTINS_KEEP = ['openssl', 'pcre', 'xxhash', 'zlib'] -ROOT_IO_KEEP = ['CMakeLists.txt', 'io', 'rootpcm'] -ROOT_MATH_KEEP = ['CMakeLists.txt', 'mathcore'] -ROOT_ETC_KEEP = ['Makefile.arch', 'class.rules', 'cmake', 'dictpch', - 'gdb-backtrace.sh', 'runfirefox.sh', 'gitinfo.txt', 'helgrind-root.supp', - 'hostcert.conf', 'plugins', 'system.plugins-ios', - 'valgrind-root-python.supp', 'valgrind-root.supp'] -ROOT_PLUGINS_KEEP = ['TVirtualStreamerInfo'] - -ROOT_EXPLICIT_REMOVE = [os.path.join('core', 'base', 'v7'), - os.path.join('math', 'mathcore', 'v7'), - os.path.join('io', 'io', 'v7')] - - ERR_RELEASE_NOT_FOUND = 2 - -def get_root_version(try_recover=True): - import pkg_resources - path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'python') - dists = pkg_resources.find_distributions(path) - try: - cppyy_cling = [d for d in dists if d.key == 'cppyy-cling'][0] - version = cppyy_cling.version - except IndexError: - if try_recover and os.path.exists('setup.py'): - print('No egg_info ... running "python setup.py egg_info"') - if subprocess.call(['python', 'setup.py', 'egg_info']) != 0: - print('ERROR: creation of egg_info failed ... giving up') - sys.exit(2) - return get_root_version(False) - else: - print('ERROR: cannot determine version. Please run "python setup.py egg_info" first.') - sys.exit(1) - # - parts = version.split('.', 3) - major, minor, patch = map(int, parts[:3]) - root_version = '%d.%02d.%02d' % (major, minor, patch) - return root_version - - -ROOT_VERSION = get_root_version() +ROOT_VERSION = '6.32.08' # -## ROOT source pull and cleansing +## released source pull and copy of Cling # -def clean_directory(directory, keeplist, trim_cmake=True): - removed_entries = [] - for entry in os.listdir(directory): - if entry[0] == '.' or entry in keeplist: - continue - removed_entries.append(entry) - entry = os.path.join(directory, entry) - print('now removing', entry) - if os.path.isdir(entry): - shutil.rmtree(entry) - else: - os.remove(entry) - - if not trim_cmake: - return - - # now take the removed entries out of the CMakeLists.txt - inp = os.path.join(directory, 'CMakeLists.txt') - if removed_entries and os.path.exists(inp): - print('trimming', inp) - outp = inp+'.new' - new_cml = open(outp, 'w') - for line in open(inp).readlines(): - if ('add_subdirectory' in line) or\ - ('COMMAND' in line and 'copy' in line) or\ - ('ROOT_ADD_TEST_SUBDIRECTORY' in line) or\ - ('install(DIRECTORY' in line): - for sub in removed_entries: - if sub in line: - line = '#'+line - break - new_cml.write(line) - new_cml.close() - rename(outp, inp) - else: - print('reusing existing %s/CMakeLists.txt' % (directory,)) - - if not os.path.exists(TARBALL_CACHE_DIR): os.mkdir(TARBALL_CACHE_DIR) @@ -131,14 +52,9 @@ def clean_directory(directory, keeplist, trim_cmake=True): if not os.path.exists(os.path.join(TARBALL_CACHE_DIR, fn)): try: print('retrieving', fn) - if sys.hexversion < 0x3000000: - output_fn = fn - else: - output_fn = bytes(fn, 'utf-8') - resp = urllib2.urlopen(addr, output_fn) - out = open(os.path.join(TARBALL_CACHE_DIR, fn), 'wb') - out.write(resp.read()) - out.close() + with contextlib.closing(urllib2.urlopen(addr)) as resp: + with open(os.path.join(TARBALL_CACHE_DIR, fn), 'wb') as out: + shutil.copyfileobj(resp, out) except urllib2.HTTPError: print('release %s not found' % ROOT_VERSION) sys.exit(ERR_RELEASE_NOT_FOUND) @@ -156,246 +72,12 @@ def clean_directory(directory, keeplist, trim_cmake=True): else: print('reusing existing directory', pkgdir) -# remove everything except for the listed set of libraries + +# remove old directoy, if any and enter release directory try: - shutil.rmtree('src') + shutil.rmtree(os.path.join('src', 'interpreter')) except OSError: pass -os.chdir(pkgdir) -clean_directory(os.path.curdir, ROOT_KEEP) -clean_directory('core', ROOT_CORE_KEEP) -clean_directory('builtins', ROOT_BUILTINS_KEEP) -clean_directory('etc', ROOT_ETC_KEEP, trim_cmake=False) -clean_directory(os.path.join('etc', 'plugins'), ROOT_PLUGINS_KEEP, trim_cmake=False) -clean_directory('io', ROOT_IO_KEEP) -clean_directory('math', ROOT_MATH_KEEP) - - -# trim main (only need rootcling) -print('trimming main') -for entry in os.listdir(os.path.join('main', 'src')): - if entry != 'rootcling.cxx': - os.remove(os.path.join('main', 'src', entry)) -inp = os.path.join('main', 'CMakeLists.txt') -outp = inp+'.new' -new_cml = open(outp, 'w') -now_stripping = False -for line in open(inp).readlines(): - if ('ROOT_EXECUTABLE' in line or 'root.exe' in line or \ - 'SET_TARGET_PROPERTIES' in line) and\ - not 'rootcling' in line: - line = '#'+line - elif '#---CreateHadd' == line[0:14]: - now_stripping = True - elif now_stripping and line == ')\n': - line = '#'+line - now_stripping = False - if now_stripping: - line = '#'+line - new_cml.write(line) -new_cml.close() -rename(outp, inp) - -# trim core (remove lz4 and lzma, and gGLManager which otherwise crashes on call) -print('trimming core/CMakeLists.txt') -inp = os.path.join('core', 'CMakeLists.txt') -outp = inp+'.new' -new_cml = open(outp, 'w') -for line in open(inp).readlines(): - if ('Lzma' in line or 'Lz4' in line): - line = '#'+line - else: - line = line.replace(' ${LZMA_LIBRARIES}', '') - line = line.replace(' LZ4::LZ4', '') - line = line.replace(' LZMA', '') - new_cml.write(line) -new_cml.close() -rename(outp, inp) - -print('trimming core/base') -os.remove(os.path.join('core', 'base', 'src', 'TVirtualGL.cxx')) -os.remove(os.path.join('core', 'base', 'inc', 'TVirtualGL.h')) -inp = os.path.join('core', 'base', 'CMakeLists.txt') -outp = inp+'.new' -now_stripping = False -new_cml = open(outp, 'w') -for line in open(inp).readlines(): - if 'if(cxx14 OR cxx17 OR root7)' == line[0:27]: # get rid of v7 stuff - now_stripping = True - elif 'if(root7)' == line[0:9]: - now_stripping = False - elif 'RLogger' in line or \ - ('BASE_HEADER_DIRS' in line and 'v7' in line) or \ - 'TVirtualGL' in line or \ - ('argparse' in line and 'Man' in line): - line = '#'+line - if now_stripping: - line = '#'+line - new_cml.write(line) -new_cml.close() -rename(outp, inp) - -# do not copy wchar.h & friends b/c the pch should be generated at install time, -# so preventing conflict -print('trimming clingutils') -inp = os.path.join('core', 'clingutils', 'CMakeLists.txt') -outp = inp+'.new' -now_stripping = False -new_cml = open(outp, 'w') -for line in open(inp).readlines(): - if '# Capture their build-time' == line[0:26]: - now_stripping = True - elif 'set(stamp_file' == line[0:14]: - now_stripping = False - if now_stripping: - line = '#'+line - new_cml.write(line) -new_cml.close() -rename(outp, inp) - -# remove extraneous external software explicitly -print('trimming externals') -for cmf in ['AfterImage', 'FTGL']: - fname = os.path.join('cmake', 'modules', 'Find%s.cmake' % (cmf,)) - if os.path.exists(fname): - os.remove(fname) -inp = os.path.join('cmake', 'modules', 'SearchInstalledSoftware.cmake') -outp = inp+'.new' -now_stripping = False -new_cml = open(outp, 'w') -for line in open(inp).readlines(): - if '#---Check for ftgl if needed' == line[0:28] or\ - '#---Check for AfterImage' == line[0:24] or\ - '#---Check for Freetype' == line[0:22] or\ - '#---Check for LZMA' == line[0:18] or\ - '#---Check for LZ4' == line[0:17] or\ - '#-------' == line[0:8]: # openui5 (doesn't follow convention) - now_stripping = True - elif '#---Check' == line[0:9] or\ - '#---Report' == line[0:10]: - now_stripping = False - if now_stripping or 'builtin_freetype' in line: - line = '#'+line - new_cml.write(line) -new_cml.close() -rename(outp, inp) - -inp = os.path.join('cmake', 'modules', 'RootBuildOptions.cmake') -outp = inp+'.new' -new_cml = open(outp, 'w') -for line in open(inp).readlines(): - if 'ROOT_BUILD_OPTION(builtin_ftgl' in line or\ - 'ROOT_BUILD_OPTION(builtin_afterimage' in line: - line = '#'+line - new_cml.write(line) -new_cml.close() -rename(outp, inp) - -# remove testing, examples, and notebook -print('trimming testing') -inp = 'CMakeLists.txt' -outp = inp+'.new' -now_stripping = False -new_cml = open(outp, 'w') -for line in open(inp).readlines(): - if '#---Configure Testing using CTest' == line[0:33] or\ - '#---hsimple.root' == line[0:16]: - now_stripping = True - elif '#---Packaging' == line[0:13] or\ - '#---version' == line[0:11]: - now_stripping = False - if now_stripping: - line = '#'+line - elif 'root_kernel' in line: - line = '#'+line - new_cml.write(line) -new_cml.close() -rename(outp, inp) - -print('trimming RootCPack') -inp = os.path.join('cmake', 'modules', 'RootCPack.cmake') -outp = inp+'.new' -new_cml = open(outp, 'w') -for line in open(inp): - if 'README.txt' in line: - line = '#'+line - new_cml.write(line) -new_cml.close() -rename(outp, inp) - - -# some more explicit removes: -for dir_to_remove in ROOT_EXPLICIT_REMOVE: - try: - shutil.rmtree(dir_to_remove) - except OSError: - pass - - -# special fixes -for inp in [os.path.join('core', 'unix', 'src', 'TUnixSystem.cxx'), - os.path.join('core', 'winnt', 'src', 'TWinNTSystem.cxx')]: - outp = inp+'.new' - new_cml = open(outp, 'w') - for line in open(inp): - if '#include "TSocket.h"' == line[0:20]: - line = """//#include "TSocket.h" -enum ESockOptions { - kSendBuffer, // size of send buffer - kRecvBuffer, // size of receive buffer - kOobInline, // OOB message inline - kKeepAlive, // keep socket alive - kReuseAddr, // allow reuse of local portion of address 5-tuple - kNoDelay, // send without delay - kNoBlock, // non-blocking I/O - kProcessGroup, // socket process group (used for SIGURG and SIGIO) - kAtMark, // are we at out-of-band mark (read only) - kBytesToRead // get number of bytes to read, FIONREAD (read only) -}; - -enum ESendRecvOptions { - kDefault, // default option (= 0) - kOob, // send or receive out-of-band data - kPeek, // peek at incoming message (receive only) - kDontBlock // send/recv as much data as possible without blocking -}; -""" - new_cml.write(line) - new_cml.close() - rename(outp, inp) - -print('trimming mathcore') -os.remove(os.path.join('math', 'mathcore', 'src', 'triangle.h')) -os.remove(os.path.join('math', 'mathcore', 'src', 'triangle.c')) -os.remove(os.path.join('math', 'mathcore', 'inc', 'Math', 'Delaunay2D.h')) -os.remove(os.path.join('math', 'mathcore', 'src', 'Delaunay2D.cxx')) - -inp = os.path.join('math', 'mathcore', 'CMakeLists.txt') -outp = inp+'.new' -now_stripping = False -new_cml = open(outp, 'w') -for line in open(inp).readlines(): - if 'Delaunay2D' in line or 'triangle' in line: - new_cml.write('#') - new_cml.write(line) -new_cml.close() -rename(outp, inp) - -# done -os.chdir(os.path.pardir) - -# debugging: run a test build -if DEBUG_TESTBUILD: - print('running a debug test build') - tb = "test_builddir" - if os.path.exists(tb): - shutil.rmtree(tb) - os.mkdir(tb) - os.chdir(tb) - os.system('cmake %s -DCMAKE_INSTALL_PREFIX=%s -Dminimal=ON -Dasimage=OFF' % \ - (os.path.join(os.pardir, pkgdir), os.path.join(os.pardir, 'install'))) - os.system('make -j 32') - # ## package creation @@ -405,17 +87,9 @@ def clean_directory(directory, keeplist, trim_cmake=True): print('adding src ... ') if not os.path.exists('src'): os.mkdir('src') -for entry in os.listdir(pkgdir): - fullp = os.path.join(pkgdir, entry) - if entry[0] == '.': - continue - dest = os.path.join('src', entry) - if os.path.isdir(fullp): - if not os.path.exists(dest): - shutil.copytree(fullp, dest) - else: - if not os.path.exists(dest): - shutil.copy2(fullp, dest) +fullp = os.path.join(pkgdir, 'interpreter') +dest = os.path.join('src', 'interpreter') +shutil.copytree(fullp, dest) # ## apply patches (in order) @@ -435,19 +109,23 @@ def apply(self): res = os.system('patch -p1 < ' + self.fdiff) return res == 0 -for fdiff in ('cleanup_tstring', 'scanner', 'scanner_2', 'faux_typedef', 'classrules', 'template_fwd', - 'dep_template', 'no_long64_t', 'using_decls', 'sfinae', 'typedef_of_private', - 'optlevel2_forced', 'silence', 'explicit_template', 'alias_template', 'lambda', 'templ_ops', - 'private_type_args', 'incomplete_types', 'clang_printing', 'resolution', - 'stdfunc_printhack', 'anon_union', 'no_inet', 'signaltrycatch', 'nofastmath', 'pch', - 'stackoverflow', 'stdvalue_type', 'strip_lz4_lzma', - 'msvc', 'win64rtti', 'win64', 'win64s2'): +patch_files = ['typedef_of_private', 'optlevel2_forced', 'explicit_template', + 'alias_template', 'incomplete_types', 'clang_printing', + 'improv_load', 'pch', 'win64rtti', 'win64s2', 'locales', 'build'] + +if 'linux' in sys.platform: + patch_files.append('system_dirs') + +if 'darwin' in sys.platform: + patch_files.append('apple') + +for fdiff in patch_files: fpatch = os.path.join('patches', fdiff+'.diff') print(' ==> applying patch:', fpatch) pset = patch.fromfile(fpatch) if not pset or not pset.apply(): print("Failed to apply patch:", fdiff) - sys.exit(2) + # sys.exit(2) # ## manylinux1 specific patch, as there a different, older, compiler is used diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/alias_template.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/alias_template.diff new file mode 100644 index 0000000000000..34cef73b89bfd --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/alias_template.diff @@ -0,0 +1,173 @@ +diff --git a/src/interpreter/cling/include/cling/Interpreter/LookupHelper.h b/src/interpreter/cling/include/cling/Interpreter/LookupHelper.h +index 5c344223c6..d0b9b060d2 100644 +--- a/src/interpreter/cling/include/cling/Interpreter/LookupHelper.h ++++ b/src/interpreter/cling/include/cling/Interpreter/LookupHelper.h +@@ -116,6 +116,15 @@ namespace cling { + const clang::ClassTemplateDecl* + findClassTemplate(llvm::StringRef Name, DiagSetting diagOnOff) const; + ++ ///\brief Determine whether a name represents a class template. ++ /// ++ ///\param [in] Name - The name of the class template to lookup. ++ ///\param [in] diagOnOff - Whether to diagnose lookup failures. ++ ///\returns The found declaration or null. ++ /// ++ bool ++ existsClassTemplate(llvm::StringRef Name, DiagSetting diagOnOff) const; ++ + ///\brief Lookup a data member based on its Decl(Context), name. + /// + ///\param [in] scopeDecl - the scope (namespace or tag) that is searched for +diff --git a/src/interpreter/cling/lib/Interpreter/LookupHelper.cpp b/src/interpreter/cling/lib/Interpreter/LookupHelper.cpp +index a863eb7db1..5dacfdc59f 100644 +--- a/src/interpreter/cling/lib/Interpreter/LookupHelper.cpp ++++ b/src/interpreter/cling/lib/Interpreter/LookupHelper.cpp +@@ -906,6 +906,148 @@ namespace cling { + return 0; + } + ++ bool LookupHelper::existsClassTemplate(llvm::StringRef Name, DiagSetting diagOnOff) const { ++ // ++ // Find whether a class template exists, given its name. ++ // ++ ++ // This code is basically findClassTemplate, which is isn't AFAICT used in any ++ // other capacity than "exists", returning a Decl*, but since this is a patch, ++ // there is no reason to spend the effort in refactoring. ++ ++ if (Name.empty()) return 0; ++ ++ // Humm ... this seems to do the trick ... or does it? or is there a better way? ++ ++ // Use P for shortness ++ Parser& P = *m_Parser; ++ Sema& S = P.getActions(); ++ ASTContext& Context = S.getASTContext(); ++ StartParsingRAII ParseStarted(const_cast(*this), ++ Name.str(), ++ llvm::StringRef("lookup.class.by.name.file"), ++ diagOnOff); ++ ++ // ++ // Prevent failing on an assert in TryAnnotateCXXScopeToken. ++ // ++ if (!P.getCurToken().is(clang::tok::identifier) ++ && !P.getCurToken().is(clang::tok::coloncolon) ++ && !(P.getCurToken().is(clang::tok::annot_template_id) ++ && P.NextToken().is(clang::tok::coloncolon)) ++ && !P.getCurToken().is(clang::tok::kw_decltype)) { ++ // error path ++ return 0; ++ } ++ ++ // ++ // Now try to parse the name as a type. ++ // ++ if (P.TryAnnotateTypeOrScopeToken()) { ++ // error path ++ return 0; ++ } ++ DeclContext *where = 0; ++ if (P.getCurToken().getKind() == tok::annot_cxxscope) { ++ CXXScopeSpec SS; ++ S.RestoreNestedNameSpecifierAnnotation(P.getCurToken().getAnnotationValue(), ++ P.getCurToken().getAnnotationRange(), ++ SS); ++ if (SS.isValid()) { ++ P.ConsumeAnyToken(); ++ if (!P.getCurToken().is(clang::tok::identifier)) { ++ return 0; ++ } ++ NestedNameSpecifier *nested = SS.getScopeRep(); ++ if (!nested) return 0; ++ switch (nested->getKind()) { ++ case NestedNameSpecifier::Global: ++ where = Context.getTranslationUnitDecl(); ++ break; ++ case NestedNameSpecifier::Namespace: ++ where = nested->getAsNamespace(); ++ break; ++ case NestedNameSpecifier::NamespaceAlias: ++ case NestedNameSpecifier::Identifier: ++ return 0; ++ case NestedNameSpecifier::TypeSpec: ++ case NestedNameSpecifier::TypeSpecWithTemplate: ++ { ++ const Type *ntype = nested->getAsType(); ++ where = ntype->getAsCXXRecordDecl(); ++ if (!where) return 0; ++ break; ++ } ++ case NestedNameSpecifier::Super: ++ // Microsoft's __super:: ++ return 0; ++ }; ++ } ++ } else if (P.getCurToken().is(clang::tok::annot_typename)) { ++ // A deduced template? ++ ++ // P.getTypeAnnotation() takes a non-const Token& until clang r306291. ++ //auto ParsedTy = P.getTypeAnnotation(P.getCurToken()); ++ auto ParsedTy ++ = ParsedType::getFromOpaquePtr(P.getCurToken().getAnnotationValue()); ++ if (ParsedTy) { ++ QualType QT = ParsedTy.get(); ++ const Type* TyPtr = QT.getTypePtr(); ++ if (const auto *LocInfoTy = dyn_cast(TyPtr)) ++ TyPtr = LocInfoTy->getType().getTypePtr(); ++ TyPtr = TyPtr->getUnqualifiedDesugaredType(); ++ if (const auto *DTST ++ = dyn_cast(TyPtr)) { ++ if (auto TD = DTST->getTemplateName().getAsTemplateDecl()) { ++ if (auto CTD = dyn_cast(TD)) ++ return CTD; ++ else if (auto TAT = dyn_cast(TD)) { ++ TypeAliasDecl* Pattern = TAT->getCanonicalDecl()->getTemplatedDecl(); ++ if (Pattern && !Pattern->isInvalidDecl()) { ++ QualType QT = Pattern->getUnderlyingType().getCanonicalType(); ++ if (!QT.isNull() && QT.getTypePtr()) { ++ if (auto TST = dyn_cast(QT.getTypePtr())) ++ return TST->getTemplateName().getAsTemplateDecl(); ++ if (dyn_cast(QT.getTypePtr())) ++ return true; ++ } ++ } ++ } ++ } ++ } ++ } ++ } else if (P.getCurToken().is(clang::tok::identifier)) { ++ // We have a single indentifier, let's look for it in the ++ // the global scope. ++ where = Context.getTranslationUnitDecl(); ++ } ++ if (where) { ++ // Great we now have a scope and something to search for,let's go ahead. ++ Interpreter::PushTransactionRAII pushedT(m_Interpreter); ++ DeclContext::lookup_result R ++ = where->lookup(P.getCurToken().getIdentifierInfo()); ++ for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); ++ I != E; ++I) { ++ // this is the same code as above under the deduced type and needs refactoring ++ if (auto CTD = dyn_cast(*I)) ++ return CTD; ++ else if (auto TAT = dyn_cast(*I)) { ++ TypeAliasDecl* Pattern = TAT->getCanonicalDecl()->getTemplatedDecl(); ++ if (Pattern && !Pattern->isInvalidDecl()) { ++ QualType QT = Pattern->getUnderlyingType().getCanonicalType(); ++ if (!QT.isNull() && QT.getTypePtr()) { ++ if (auto TST = dyn_cast(QT.getTypePtr())) ++ return TST->getTemplateName().getAsTemplateDecl(); ++ if (dyn_cast(QT.getTypePtr())) ++ return true; ++ } ++ } ++ } ++ } ++ } ++ return 0; ++ } ++ + const ValueDecl* LookupHelper::findDataMember(const clang::Decl* scopeDecl, + llvm::StringRef dataName, + DiagSetting diagOnOff) const { diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/apple.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/apple.diff new file mode 100644 index 0000000000000..342571f68cf64 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/apple.diff @@ -0,0 +1,18 @@ +diff --git a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +index aec153242b..abcfd33597 100644 +--- a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp ++++ b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +@@ -336,6 +336,13 @@ namespace { + } + #endif // _LIBCPP_VERSION + ++ // special case for Mac, use `xcrun` to get around various recent path changes ++ // in system updates ++ #ifdef __APPLE__ ++ if (sArguments.empty()) ++ ReadCompilerIncludePaths("xcrun c++", buffer, sArguments, Verbose); ++ #endif ++ + // First try the relative path 'g++' + #ifdef CLING_CXX_RLTV + if (sArguments.empty()) diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/build.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/build.diff new file mode 100644 index 0000000000000..94c0f3c67a0e8 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/build.diff @@ -0,0 +1,47 @@ +diff --git a/src/interpreter/CMakeLists.txt b/src/interpreter/CMakeLists.txt +index 373461bd2f..909b2df071 100644 +--- a/src/interpreter/CMakeLists.txt ++++ b/src/interpreter/CMakeLists.txt +@@ -473,7 +473,8 @@ endif() + set(CMAKE_CXX_FLAGS ${cxx_flags_prev}) + unset(cxx_flags_prev) + +-add_custom_target(CLING) ++# Custuom target "CLING" is already defined in src/cmake/modules/SearchInstalledSoftware.cmake ++# add_custom_target(CLING) + set(CLING_LIBRARIES clingInterpreter;clingMetaProcessor;clingUtils CACHE STRING "") + if (builtin_cling) + + +diff --git a/src/interpreter/CMakeLists.txt b/src/interpreter/CMakeLists.txt +index 7002e43f36..dfdf718685 100644 +--- a/src/interpreter/CMakeLists.txt ++++ b/src/interpreter/CMakeLists.txt +@@ -496,7 +496,10 @@ if (builtin_cling) + set(CLING_CXXFLAGS " ${LLVM_DEFS} -DNOMINMAX -D_XKEYCHECK_H") + else() + # FIXME: Work hard to remove -Wno-shadow and -Wno-unused-parameter +- set(CLING_CXXFLAGS " ${LLVM_DEFS} -fno-strict-aliasing -Wwrite-strings -Wno-shadow -Wno-unused-parameter -Wno-deprecated-declarations") ++ set(CLING_CXXFLAGS " ${LLVM_DEFS} -fvisibility=hidden -fno-strict-aliasing -Wwrite-strings -Wno-shadow -Wno-unused-parameter -Wno-deprecated-declarations") ++ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") ++ string(APPEND CLING_CXXFLAGS " -Wl,-Bsymbolic") ++ endif() + endif() + + # Set the flags in the parent scope for the rest of the cling-based libraries in ROOT. +diff --git a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +index 1ab35553fa..b7c99ba281 100644 +--- a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp ++++ b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +@@ -459,7 +459,10 @@ namespace { + Opts.CXXExceptions = 1; + } + +- //Opts.Modules = 1; ++// TODO: temporary hack, switching off modules for C++20, which is enabled ++// by default otherwise (yet not currently supported in cppyy-cling) ++ if (Opts.CPlusPlus20) ++ Opts.Modules = 0; + + // See test/CodeUnloading/PCH/VTables.cpp which implicitly compares clang + // to cling lang options. They should be the same, we should not have to diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/clang_printing.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/clang_printing.diff new file mode 100644 index 0000000000000..fb9306c8cde43 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/clang_printing.diff @@ -0,0 +1,16 @@ +diff --git a/src/interpreter/llvm-project/clang/lib/AST/Decl.cpp b/src/interpreter/llvm-project/clang/lib/AST/Decl.cpp +index 573a98efe9..41995a9a24 100644 +--- a/src/interpreter/llvm-project/clang/lib/AST/Decl.cpp ++++ b/src/interpreter/llvm-project/clang/lib/AST/Decl.cpp +@@ -3006,6 +3006,11 @@ unsigned ParmVarDecl::getParameterIndexLarge() const { + void FunctionDecl::getNameForDiagnostic( + raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { + NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); ++ const DeclarationName& N = getDeclName(); ++ if (N.getNameKind() == DeclarationName::CXXOperatorName) { ++ const std::string& opname = N.getAsString(); ++ if (opname.back() == '<') OS << ' '; ++ } + const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs(); + if (TemplateArgs) + printTemplateArgumentList(OS, TemplateArgs->asArray(), Policy); diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/explicit_template.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/explicit_template.diff new file mode 100644 index 0000000000000..35c045a415ff0 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/explicit_template.diff @@ -0,0 +1,46 @@ +diff --git a/src/interpreter/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/src/interpreter/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +index 6fee23aa8b..ed30f06ca9 100644 +--- a/src/interpreter/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp ++++ b/src/interpreter/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +@@ -4819,6 +4819,19 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, + !DefinitionRequired) + return; + ++ // Pure extern declarations do not need an instantiation (would prefer to ++ // verify the linker symbol availability but can't do that here ++ if (TSK == TSK_ExplicitInstantiationDeclaration) { ++ const FunctionDecl* PFD = Function->getTemplateInstantiationPattern(); ++ if (PFD && !PFD->getReturnType()->getContainedAutoType() ++#ifdef __APPLE__ ++ // special case for Apple's choice of ABI control with extern declared inline ++ // functions; since these are instantiated in the library but not exported ++ && (!PFD->isInlined() || PFD->isInlineDefinitionExternallyVisible()) ++#endif ++ ) return; ++ } ++ + // Don't instantiate a definition if we already have one. + const FunctionDecl *ExistingDefn = nullptr; + if (Function->isDefined(ExistingDefn, +diff --git a/src/interpreter/llvm-project/clang/lib/AST/TemplateBase.cpp b/src/interpreter/llvm-project/clang/lib/AST/TemplateBase.cpp +index 88a554c985..5e6e53e1e7 100644 +--- a/src/interpreter/llvm-project/clang/lib/AST/TemplateBase.cpp ++++ b/src/interpreter/llvm-project/clang/lib/AST/TemplateBase.cpp +@@ -423,7 +425,16 @@ void TemplateArgument::print(const PrintingPolicy &Policy, + case Type: { + PrintingPolicy SubPolicy(Policy); + SubPolicy.SuppressStrongLifetime = true; +- getAsType().print(Out, SubPolicy); ++ SubPolicy.SuppressScope = false; ++ SubPolicy.SuppressUnwrittenScope = true; ++// this is dumb, but I can't seem to figure out the exact conditions that cause the ++// "type-parameter" generic name to appear (when TemplateTypeParmType does not have ++// any IdentifierInfo, but how to extract the TemplateTypeParmType to check?) ++ const std::string& canonical = getAsType().getCanonicalType().getAsString(SubPolicy); ++ if (canonical.compare(0, 14, "type-parameter", 14) != 0) ++ Out << canonical; ++ else ++ getAsType().print(Out, SubPolicy); + break; + } + diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/improv_load.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/improv_load.diff new file mode 100644 index 0000000000000..97a067e13cac0 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/improv_load.diff @@ -0,0 +1,101 @@ +diff --git a/src/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h b/src/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h +index d6e1006334..d982cb61d6 100644 +--- a/src/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h ++++ b/src/interpreter/cling/include/cling/Interpreter/DynamicLibraryManager.h +@@ -160,9 +160,9 @@ namespace cling { + /// other error was encountered. + /// + LoadLibResult loadLibrary(llvm::StringRef, bool permanent, +- bool resolved = false); ++ bool resolved = false, bool silent = false); + +- void unloadLibrary(llvm::StringRef libStem); ++ void unloadLibrary(llvm::StringRef libStem, bool silent = false); + + ///\brief Returns true if the file was a dynamic library and it was already + /// loaded. +diff --git a/src/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp b/src/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp +index c49f06e411..f51530567e 100644 +--- a/src/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp ++++ b/src/interpreter/cling/lib/Interpreter/DynamicLibraryManager.cpp +@@ -350,7 +352,7 @@ namespace cling { + + DynamicLibraryManager::LoadLibResult + DynamicLibraryManager::loadLibrary(llvm::StringRef libStem, +- bool permanent, bool resolved) { ++ bool permanent, bool resolved, bool silent) { + if (DEBUG > 7) { + cling::errs() << "Dyld::loadLibrary: " << libStem.str() << ", " << + (permanent ? "permanent" : "not-permanent") << ", " << +@@ -380,8 +382,11 @@ namespace cling { + return kLoadLibSuccess; + } + +- cling::errs() << "cling::DynamicLibraryManager::loadLibrary(): " << errMsg +- << '\n'; ++ if (!silent) { ++ cling::errs() << "cling::DynamicLibraryManager::loadLibrary() [" ++ << libStem << " -> " << canonicalLoadedLib << "]: " ++ << errMsg << '\n'; ++ } + return kLoadLibLoadError; + } + else if (InterpreterCallbacks* C = getCallbacks()) +@@ -396,7 +401,7 @@ namespace cling { + return kLoadLibSuccess; + } + +- void DynamicLibraryManager::unloadLibrary(llvm::StringRef libStem) { ++ void DynamicLibraryManager::unloadLibrary(llvm::StringRef libStem, bool silent) { + std::string canonicalLoadedLib = lookupLibrary(libStem); + if (!isLibraryLoaded(canonicalLoadedLib)) + return; +@@ -414,8 +419,9 @@ namespace cling { + + std::string errMsg; + platform::DLClose(dyLibHandle, &errMsg); +- if (!errMsg.empty()) { +- cling::errs() << "cling::DynamicLibraryManager::unloadLibrary(): " ++ if (!errMsg.empty() && !silent) { ++ cling::errs() << "cling::DynamicLibraryManager::unloadLibrary() [" ++ << libStem << " -> " << canonicalLoadedLib << "]: " + << errMsg << '\n'; + } + +diff --git a/src/interpreter/cling/lib/Utils/PlatformWin.cpp b/src/interpreter/cling/lib/Utils/PlatformWin.cpp +index 6135f838e4..d4c5c39227 100644 +--- a/src/interpreter/cling/lib/Utils/PlatformWin.cpp ++++ b/src/interpreter/cling/lib/Utils/PlatformWin.cpp +@@ -40,6 +40,7 @@ + #include // EnumProcessModulesEx + #include // _getcwd + #include // SHGetFolderPath ++#include // PathCanonicalize + #pragma comment(lib, "Advapi32.lib") + + extern "C" char* __unDName(char *demangled, const char *mangled, int out_len, +@@ -533,8 +533,14 @@ std::string GetCwd() { + + std::string NormalizePath(const std::string& Path) { + char Buf[MAX_PATHC]; +- if (const char* Result = ::_fullpath(Buf, Path.c_str(), sizeof(Buf))) +- return std::string(Result); ++ if (const char* Result = ::_fullpath(Buf, Path.c_str(), MAX_PATH)) { ++ std::string fpath(Result); ++ if (PathCanonicalizeA(Buf, fpath.c_str())) ++ return std::string(Buf); ++ ++ ReportLastError("PathCanonicalizeA"); ++ return std::string(); ++ } + + ReportLastError("_fullpath"); + return std::string(); +@@ -637,6 +646,7 @@ const void* DLSym(const std::string& Name, std::string* Err) { + } + + void DLClose(const void* Lib, std::string* Err) { ++ if (!Lib) return; + if (::FreeLibrary(reinterpret_cast(const_cast(Lib))) == 0) { + if (Err) + GetLastErrorAsString(*Err, "FreeLibrary"); diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/incomplete_types.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/incomplete_types.diff new file mode 100644 index 0000000000000..08097ae67424d --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/incomplete_types.diff @@ -0,0 +1,21 @@ +diff --git a/src/interpreter/cling/lib/Interpreter/LookupHelper.cpp b/src/interpreter/cling/lib/Interpreter/LookupHelper.cpp +index b5384d579f..979c7b3ae5 100644 +--- a/src/interpreter/cling/lib/Interpreter/LookupHelper.cpp ++++ b/src/interpreter/cling/lib/Interpreter/LookupHelper.cpp +@@ -578,10 +578,13 @@ namespace cling { + + // break; + // the next code executed must be the TransactionRAII below +- } else +- return RequireCompleteDeclContext(S, PP, tagdecl, diagOnOff); ++ } else { ++ const Decl* complete = RequireCompleteDeclContext(S, PP, tagdecl, diagOnOff); ++ if (complete) return complete; ++ return tagdecl; ++ } + } else { +- return nullptr; ++ return tagdecl;//nullptr; + } + } else { + return defdecl; // now pointing to the definition. diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/locales.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/locales.diff new file mode 100644 index 0000000000000..65f59ede2913d --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/locales.diff @@ -0,0 +1,17 @@ +diff --git a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +index f4a61b6640..9956a11bdf 100644 +--- a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp ++++ b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +@@ -114,11 +114,11 @@ namespace { + bool Verbose) { + std::string CppInclQuery("LC_ALL=C "); + CppInclQuery.append(Compiler); + + CppInclQuery.append(" -xc++ -E -v /dev/null 2>&1 |" +- " sed -n -e '/^.include/,${' -e '/^ \\/.*++/p' -e '}'"); ++ " sed -n -e '/^.*include/,${' -e '/^ \\/.*++/p' -e '}'"); + + if (Verbose) + cling::log() << "Looking for C++ headers with:\n " << CppInclQuery << "\n"; + + if (FILE *PF = ::popen(CppInclQuery.c_str(), "r")) { diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/manylinux1.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/manylinux1.diff new file mode 100644 index 0000000000000..bc5fd05d223f3 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/manylinux1.diff @@ -0,0 +1,35 @@ +diff --git a/src/builtins/zlib/adler32_cf.c b/src/builtins/zlib/adler32_cf.c +index 7cbf8a030a..bc21d2d066 100644 +--- a/src/builtins/zlib/adler32_cf.c ++++ b/src/builtins/zlib/adler32_cf.c +@@ -171,7 +171,7 @@ uLong ZEXPORT adler32_default(uLong adler, const Bytef *buf, uInt len) + return adler | (sum2 << 16); + } + +-#if defined (__x86_64__) && defined (__linux__) && ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) || (__clang__)) ++#if defined (NOT_DEFINED) && defined (__x86_64__) && defined (__linux__) && ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) || (__clang__)) + + #ifdef _MSC_VER + +diff --git a/src/builtins/zlib/deflate_cf.c b/src/builtins/zlib/deflate_cf.c +index 54aebec62a..6ac7ecdfd0 100644 +--- a/src/builtins/zlib/deflate_cf.c ++++ b/src/builtins/zlib/deflate_cf.c +@@ -1165,7 +1165,7 @@ static uint32_t hash_func(deflate_state *s, uint32_t h, void* str) { + } + + #endif // ARMv8 without crc32 support +-#elif defined (__x86_64__) && defined (__linux__) && ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) || (__clang__)) ++#elif defined (NOT_DEFINED) && defined (__x86_64__) && defined (__linux__) && ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) || (__clang__)) + + static uint32_t hash_func_sse42(deflate_state *s, uint32_t UNUSED(h), void* str) __attribute__ ((__target__ ("sse4.2"))); + +@@ -2477,7 +2477,7 @@ static void fill_window_default(s) + "not enough room for search"); + } + +-#if defined (__x86_64__) && defined (__linux__) && ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) || (__clang__)) ++#if defined (NOT_DEFINED) && defined (__x86_64__) && defined (__linux__) && ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) || (__clang__)) + + /* =========================================================================== + * Fill the window when the lookahead becomes insufficient. diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/optlevel2_forced.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/optlevel2_forced.diff new file mode 100644 index 0000000000000..e7059234de209 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/optlevel2_forced.diff @@ -0,0 +1,44 @@ +diff --git a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +index f97c86032f..69321c5579 100644 +--- a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp ++++ b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +@@ -1685,8 +1685,9 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, + + // Set CodeGen options. + CodeGenOptions& CGOpts = CI->getCodeGenOpts(); ++ CGOpts.OptimizationLevel = 2; ++ CGOpts.RelaxedAliasing = 1; + #ifdef _MSC_VER +- CGOpts.RelaxedAliasing = 1; + CGOpts.EmitCodeView = 1; + CGOpts.CXXCtorDtorAliases = 1; + #endif +diff --git a/src/interpreter/cling/lib/Interpreter/IncrementalParser.cpp b/src/interpreter/cling/lib/Interpreter/IncrementalParser.cpp +index 4b971bb02e..cbea6870db 100644 +--- a/src/interpreter/cling/lib/Interpreter/IncrementalParser.cpp ++++ b/src/interpreter/cling/lib/Interpreter/IncrementalParser.cpp +@@ -18,7 +18,6 @@ + #include "DefinitionShadower.h" + #include "DeviceKernelInliner.h" + #include "DynamicLookup.h" +-#include "NullDerefProtectionTransformer.h" + #include "TransactionPool.h" + #include "ValueExtractionSynthesizer.h" + #include "ValuePrinterSynthesizer.h" +@@ -1006,15 +1005,8 @@ namespace cling { + ASTTransformers.emplace_back(new AutoSynthesizer(TheSema)); + ASTTransformers.emplace_back(new EvaluateTSynthesizer(TheSema)); + if (hasCodeGenerator() && !m_Interpreter->getOptions().NoRuntime) { +- // Don't protect against crashes if we cannot run anything. +- // cling might also be in a PCH-generation mode; don't inject our Sema +- // pointer into the PCH. +- if (!isCUDADevice && m_Interpreter->getOptions().PtrCheck) +- ASTTransformers.emplace_back( +- new NullDerefProtectionTransformer(m_Interpreter)); + if (isCUDADevice) +- ASTTransformers.emplace_back( +- new DeviceKernelInliner(TheSema)); ++ ASTTransformers.emplace_back(new DeviceKernelInliner(TheSema)); + } + ASTTransformers.emplace_back(new DefinitionShadower(*TheSema, *m_Interpreter)); + diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/pch.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/pch.diff new file mode 100644 index 0000000000000..7defcd1ee015a --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/pch.diff @@ -0,0 +1,104 @@ +diff --git a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +index 80d1b1c52a..58edb8c26d 100644 +--- a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp ++++ b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +@@ -56,6 +56,8 @@ + #include + #include + ++#include ++ + using namespace clang; + using namespace cling; + +@@ -345,7 +347,63 @@ namespace { + } + + #ifdef CLING_OSX_SYSROOT +- sArguments.addArgument("-isysroot", CLING_OSX_SYSROOT); ++ { ++ std::string sysroot{CLING_OSX_SYSROOT}; ++ struct stat buf; ++ if (stat(sysroot.c_str(), &buf) == 0) { ++ sArguments.addArgument("-isysroot", CLING_OSX_SYSROOT); ++ } else { ++ // attempt to find a proper sysroot, or leave it up to Clang and user ++ // defined variables such as SDKROOT and MACOSX_DEPLOYMENT_TARGET ++ // first, strip Xcode version number if any and if it does not exist ++ std::string::size_type xpos1 = sysroot.find("Xcode_"); ++ std::string::size_type xpos2 = xpos1 != std::string::npos ? sysroot.find(".app", xpos1) : xpos1; ++ if (xpos1 != std::string::npos && xpos2 != std::string::npos) { ++ if (stat(sysroot.substr(0, xpos2+4).c_str(), &buf) != 0 && ++ stat(sysroot.substr(0, xpos1 ).c_str(), &buf) == 0) { ++ sysroot = sysroot.substr(0, xpos1) + "Xcode.app" + sysroot.substr(xpos2+4, std::string::npos); ++ } ++ } ++ // similarly, strip SDK version number as needed ++ std::string::size_type pos = sysroot.rfind("SDKs/MacOSX"); ++ if (pos != std::string::npos) { ++ if (getenv("MACOSX_DEPLOYMENT_TARGET")) ++ sysroot = sysroot.substr(0, pos+11) + getenv("MACOSX_DEPLOYMENT_TARGET") + ".sdk"; ++ else ++ sysroot = sysroot.substr(0, pos+11)+".sdk"; // generic location ++ } ++ if (stat(sysroot.c_str(), &buf) != 0) { ++ // final attempt, query xcrun ++ std::string SdkPathQuery("xcrun --show-sdk-path"); ++ if (Verbose) ++ cling::log() << "Looking for sysroot:\n " << SdkPathQuery << "\n"; ++ ++ if (FILE *PF = ::popen(SdkPathQuery.c_str(), "r")) { ++ llvm::SmallVector Buf; ++ Buf.resize(Buf.capacity_in_bytes()); ++ while (fgets(&Buf[0], Buf.capacity_in_bytes(), PF) && Buf[0]) { ++ llvm::StringRef Path(&Buf[0]); ++ Path = Path.trim(); ++ if (!Path.empty()) { ++ if (!llvm::sys::fs::is_directory(Path)) { ++ if (Verbose) ++ cling::utils::LogNonExistantDirectory(Path); ++ } ++ else { ++ sysroot = Path.str(); ++ break; ++ } ++ } ++ ::pclose(PF); ++ } ++ } ++ } ++ if (stat(sysroot.c_str(), &buf) == 0) ++ sArguments.addArgument("-isysroot", sysroot.c_str()); ++ else ++ cling::errs() << "Warning: sysroot \"" << sysroot << "\" not found (ignoring for now)."; ++ } ++ } + #endif + + #endif // _MSC_VER +diff --git a/src/interpreter/cling/lib/Interpreter/IncrementalParser.cpp b/src/interpreter/cling/lib/Interpreter/IncrementalParser.cpp +index 2593c21fb2..dbe8caa04b 100644 +--- a/src/interpreter/cling/lib/Interpreter/IncrementalParser.cpp ++++ b/src/interpreter/cling/lib/Interpreter/IncrementalParser.cpp +@@ -88,20 +88,7 @@ namespace { + " Failed to extract C++ standard library version.\n"; + } + +- if (CLING_CXXABI_BACKWARDCOMP && CurABI < CLING_CXXABI_VERS) { +- // Backward compatible ABIs allow us to interpret old headers +- // against a newer stdlib.so. +- return true; +- } +- +- cling::errs() << +- "Warning in cling::IncrementalParser::CheckABICompatibility():\n" +- " Possible C++ standard library mismatch, compiled with " +- << CLING_CXXABI_NAME << " '" << CLING_CXXABI_VERS << "'\n" +- " Extraction of runtime standard library version was: '" +- << CurABI << "'\n"; +- +- return false; ++ return true; + } + + /// \brief Overrides the current DiagnosticConsumer to supress many warnings diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/system_dirs.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/system_dirs.diff new file mode 100644 index 0000000000000..c2e9732c232c0 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/system_dirs.diff @@ -0,0 +1,141 @@ +diff --git a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +index 1213179cba..774e31c24d 100644 +--- a/src/interpreter/cling/lib/Interpreter/CIFactory.cpp ++++ b/src/interpreter/cling/lib/Interpreter/CIFactory.cpp +@@ -93,11 +95,13 @@ namespace { + } + + class AdditionalArgList { +- typedef std::vector< std::pair > container_t; ++ typedef std::deque< std::pair > container_t; + container_t m_Saved; + + public: +- ++ void preArgument(const char* arg, std::string value = std::string()) { ++ m_Saved.push_front(std::make_pair(arg,std::move(value))); ++ } + void addArgument(const char* arg, std::string value = std::string()) { + m_Saved.push_back(std::make_pair(arg,std::move(value))); + } +@@ -111,16 +115,23 @@ namespace { + static void ReadCompilerIncludePaths(const char* Compiler, + llvm::SmallVectorImpl& Buf, + AdditionalArgList& Args, ++ const std::string& resourcePath, + bool Verbose) { + std::string CppInclQuery("LC_ALL=C "); + CppInclQuery.append(Compiler); + + CppInclQuery.append(" -xc++ -E -v /dev/null 2>&1 |" +- " sed -n -e '/^.*include/,${' -e '/^ \\/.*++/p' -e '}'"); ++ " sed -n -e '/^.*include/,${' -e '/^ \\/.*include/p' -e '}'"); + + if (Verbose) + cling::log() << "Looking for C++ headers with:\n " << CppInclQuery << "\n"; + ++ std::string resourceIncDir; ++ llvm::SmallString<512> recInc(resourcePath); ++ llvm::sys::path::append(recInc, "include"); ++ if (llvm::sys::fs::exists(recInc.str())) ++ resourceIncDir = recInc.str().str(); ++ + if (FILE *PF = ::popen(CppInclQuery.c_str(), "r")) { + Buf.resize(Buf.capacity_in_bytes()); + while (fgets(&Buf[0], Buf.capacity_in_bytes(), PF) && Buf[0]) { +@@ -132,8 +143,15 @@ namespace { + if (Verbose) + cling::utils::LogNonExistantDirectory(Path); + } +- else ++ else { ++ if (!resourceIncDir.empty()) { ++ llvm::SmallString<512> tmp(Path); ++ llvm::sys::path::append(tmp, "xmmintrin.h"); ++ if (llvm::sys::fs::exists(tmp.str())) ++ Args.addArgument("-cxx-isystem", resourceIncDir); ++ } + Args.addArgument("-cxx-isystem", Path.str()); ++ } + } + } + ::pclose(PF); +@@ -211,6 +229,21 @@ namespace { + static AdditionalArgList sArguments; + if (sArguments.empty()) { + const bool Verbose = opts.Verbose; ++ std::string resourcePath; ++ ++ if (!opts.ResourceDir && !opts.NoBuiltinInc) { ++ resourcePath = getResourceDir(llvmdir); ++ ++ // FIXME: Handle cases, where the cling is part of a library/framework. ++ // There we can't rely on the find executable logic. ++ if (!llvm::sys::fs::is_directory(resourcePath)) { ++ cling::errs() ++ << "ERROR in cling::CIFactory::createCI():\n resource directory " ++ << resourcePath << " not found!\n"; ++ resourcePath = ""; ++ } ++ } ++ + #ifdef _MSC_VER + // When built with access to the proper Windows APIs, try to actually find + // the correct include paths first. Init for UnivSDK.empty check below. +@@ -301,14 +334,14 @@ namespace { + clang.append(" -stdlib=libstdc++"); + #endif + } +- ReadCompilerIncludePaths(clang.c_str(), buffer, sArguments, Verbose); ++ ReadCompilerIncludePaths(clang.c_str(), buffer, sArguments, resourcePath, Verbose); + } + #endif // _LIBCPP_VERSION + + // First try the relative path 'g++' + #ifdef CLING_CXX_RLTV + if (sArguments.empty()) +- ReadCompilerIncludePaths(CLING_CXX_RLTV, buffer, sArguments, Verbose); ++ ReadCompilerIncludePaths(CLING_CXX_RLTV, buffer, sArguments, resourcePath, Verbose); + #endif + // Then try the include directory cling was built with + #ifdef CLING_CXX_INCL +@@ -318,7 +351,7 @@ namespace { + // Finally try the absolute path i.e.: '/usr/bin/g++' + #ifdef CLING_CXX_PATH + if (sArguments.empty()) +- ReadCompilerIncludePaths(CLING_CXX_PATH, buffer, sArguments, Verbose); ++ ReadCompilerIncludePaths(CLING_CXX_PATH, buffer, sArguments, resourcePath, Verbose); + #endif + + if (sArguments.empty()) { +@@ -404,28 +435,16 @@ namespace { + cling::errs() << "Warning: sysroot \"" << sysroot << "\" not found (ignoring for now)."; + } + } + #endif + + #endif // _MSC_VER + +- if (!opts.ResourceDir && !opts.NoBuiltinInc) { +- std::string resourcePath = getResourceDir(llvmdir); +- +- // FIXME: Handle cases, where the cling is part of a library/framework. +- // There we can't rely on the find executable logic. +- if (!llvm::sys::fs::is_directory(resourcePath)) { +- cling::errs() +- << "ERROR in cling::CIFactory::createCI():\n resource directory " +- << resourcePath << " not found!\n"; +- resourcePath = ""; +- } else { +- sArguments.addArgument("-resource-dir", std::move(resourcePath)); +- } +- } ++ if (!resourcePath.empty()) ++ sArguments.addArgument("-resource-dir", std::move(resourcePath)); + } + + for (auto& arg : sArguments) { + args.push_back(arg.first); + args.push_back(arg.second.c_str()); + } + } diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/typedef_of_private.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/typedef_of_private.diff new file mode 100644 index 0000000000000..5001de64a6718 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/typedef_of_private.diff @@ -0,0 +1,31 @@ +diff --git a/src/interpreter/cling/lib/Utils/AST.cpp b/src/interpreter/cling/lib/Utils/AST.cpp +index da3b0724e5..f7ba7623aa 100644 +--- a/src/interpreter/cling/lib/Utils/AST.cpp ++++ b/src/interpreter/cling/lib/Utils/AST.cpp +@@ -708,7 +708,12 @@ namespace utils { + const llvm::SmallSet& ToSkip) + { + // Return true, if we should keep this typedef rather than desugaring it. +- ++ QualType qt = TT->getDecl()->getUnderlyingType(); ++ CXXRecordDecl* decl = qt->getAsCXXRecordDecl(); ++ if (decl && (decl->getAccess() == AS_private || decl->getAccess() == AS_protected)) { ++ // desugaring would result in an inaccessible type, so leave it alone ++ return true; ++ } + return 0 != ToSkip.count(TT->getDecl()->getCanonicalDecl()); + } + +@@ -1140,6 +1145,10 @@ namespace utils { + dyn_cast_or_null(QT.getTypePtr()); + if (typedeftype) { + decl = typedeftype->getDecl(); ++ if (decl && (decl->getAccess() == AS_private || decl->getAccess() == AS_protected)) { ++ // desugaring would result in an inaccessible type, so leave it alone ++ return QT; ++ } + } else if (usingtype) { + decl = usingtype->getFoundDecl(); + } else { + // There are probably other cases ... + const TagType* tagdecltype = dyn_cast_or_null(QT.getTypePtr()); diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/win64rtti.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/win64rtti.diff new file mode 100644 index 0000000000000..55d33d190e104 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/win64rtti.diff @@ -0,0 +1,38 @@ +diff --git a/src/interpreter/llvm-project/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/src/interpreter/llvm-project/clang/lib/CodeGen/MicrosoftCXXABI.cpp +index 1bd2937e47..108b5d6e66 100644 +--- a/src/interpreter/llvm-project/clang/lib/CodeGen/MicrosoftCXXABI.cpp ++++ b/src/interpreter/llvm-project/clang/lib/CodeGen/MicrosoftCXXABI.cpp +@@ -543,10 +543,11 @@ public: + getImageRelativeType(CGM.Int8PtrTy), + getImageRelativeType(getClassHierarchyDescriptorType()->getPointerTo()), + getImageRelativeType(CompleteObjectLocatorType), ++ CGM.VoidPtrTy, + }; + llvm::ArrayRef FieldTypesRef(FieldTypes); + if (!isImageRelative()) +- FieldTypesRef = FieldTypesRef.drop_back(); ++ FieldTypesRef = FieldTypesRef.drop_back(2); + CompleteObjectLocatorType->setBody(FieldTypesRef); + return CompleteObjectLocatorType; + } +@@ -3907,17 +3808,18 @@ MSRTTIBuilder::getCompleteObjectLocator(const VPtrInfo &Info) { + + // Initialize the CompleteObjectLocator. + llvm::Constant *Fields[] = { +- llvm::ConstantInt::get(CGM.IntTy, ABI.isImageRelative()), ++ llvm::ConstantInt::get(CGM.IntTy, ABI.isImageRelative() ? 2 : 0), + llvm::ConstantInt::get(CGM.IntTy, OffsetToTop), + llvm::ConstantInt::get(CGM.IntTy, VFPtrOffset), + ABI.getImageRelativeConstant( + CGM.GetAddrOfRTTIDescriptor(Context.getTypeDeclType(RD))), + ABI.getImageRelativeConstant(getClassHierarchyDescriptor()), + ABI.getImageRelativeConstant(COL), ++ CGM.GetAddrOfRTTIDescriptor(Context.getTypeDeclType(RD)), + }; + llvm::ArrayRef FieldsRef(Fields); + if (!ABI.isImageRelative()) +- FieldsRef = FieldsRef.drop_back(); ++ FieldsRef = FieldsRef.drop_back(2); + COL->setInitializer(llvm::ConstantStruct::get(Type, FieldsRef)); + if (COL->isWeakForLinker()) + COL->setComdat(CGM.getModule().getOrInsertComdat(COL->getName())); diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/patches/win64s2.diff b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/win64s2.diff new file mode 100644 index 0000000000000..3cc4b937e9979 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/patches/win64s2.diff @@ -0,0 +1,184 @@ +diff --git a/src/interpreter/llvm-project/clang/lib/AST/MicrosoftMangle.cpp b/src/interpreter/llvm-project/clang/lib/AST/MicrosoftMangle.cpp +index 24b16f892e..57a5b6f686 100644 +--- a/src/interpreter/llvm-project/clang/lib/AST/MicrosoftMangle.cpp ++++ b/src/interpreter/llvm-project/clang/lib/AST/MicrosoftMangle.cpp +@@ -35,7 +35,8 @@ + #include "llvm/Support/MathExtras.h" + #include "llvm/Support/StringSaver.h" + #include "llvm/Support/xxhash.h" ++#include "llvm/Support/raw_ostream.h" + #include + + using namespace clang; + +@@ -2816,11 +2817,13 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, + Qualifiers, SourceRange Range) { + // Probably should be mangled as a template instantiation; need to see what + // VC does first. ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this unresolved dependent type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + // ::= | | | +@@ -2966,20 +2967,24 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, Qualifiers + + void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T, + Qualifiers, SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this template type parameter type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T, + Qualifiers, SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this substituted parameter pack yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + // ::= +@@ -3136,11 +3137,13 @@ void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, + + void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, + Qualifiers, SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this dependent-sized extended vector type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const ConstantMatrixType *T, +@@ -3236,97 +3237,117 @@ void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *, + + void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T, + Qualifiers, SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this template specialization type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T, Qualifiers, + SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this dependent name type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType( + const DependentTemplateSpecializationType *T, Qualifiers, + SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this dependent template specialization type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, Qualifiers, + SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this pack expansion yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, Qualifiers, + SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this typeof(type) yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T, Qualifiers, + SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this typeof(expression) yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T, Qualifiers, + SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this decltype() yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T, + Qualifiers, SourceRange Range) { ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this unary transform type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const AutoType *T, Qualifiers, + SourceRange Range) { + assert(T->getDeducedType().isNull() && "expecting a dependent type!"); + ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this 'auto' type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType( + const DeducedTemplateSpecializationType *T, Qualifiers, SourceRange Range) { + assert(T->getDeducedType().isNull() && "expecting a dependent type!"); + ++/* + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot mangle this deduced class template specialization type yet"); + Diags.Report(Range.getBegin(), DiagID) + << Range; ++*/ + } + + void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers, diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/pyproject.toml b/bindings/pyroot/cppyy/cppyy-backend/cling/pyproject.toml new file mode 100644 index 0000000000000..c3fad2aae7cd5 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/pyproject.toml @@ -0,0 +1,25 @@ +[build-system] +requires = ["cmake", "setuptools", "wheel"] + +[tool.cibuildwheel] +archs = ["auto"] +build-frontend = "pip" +dependency-versions = "pinned" +build-verbosity = "1" +build = "cp39-manylinux_{x86_64,i686,aarch64} cp310-macosx_{x86_64,arm64} cp310-{win_amd64,win32,win_arm64}" + + +before-all = "cd cling && python create_src_directory.py" + + +test-requires = [] +test-command = 'python -c "import cppyy_backend"' + +[tool.cibuildwheel.linux] +repair-wheel-command = "" +# repair-wheel-command = "LD_LIBRARY_PATH=$PWD/lib auditwheel repair -w {dest_dir} {wheel}" + +# mac-arm target is 10.15 +[[tool.cibuildwheel.overrides]] +select = "*macos*" +environment = { MACOSX_DEPLOYMENT_TARGET = "10.15" } diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_cppyy_generator.py b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_cppyy_generator.py index 07a82b5f1a0e9..0135417cc7d71 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_cppyy_generator.py +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_cppyy_generator.py @@ -15,6 +15,11 @@ from clang.cindex import AccessSpecifier, Config, CursorKind, Diagnostic, Index, SourceRange, TokenKind, TypeKind +if sys.hexversion > 0x3030000: + collMapping = collections.abc.Mapping +else: + collMapping = collections.Mapping + class HelpFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter): pass @@ -92,7 +97,7 @@ def unpreprocessed(self, extent, nl=" "): def _read(self, source): lines = [] - with open(source, "rU") as f: + with open(source, "r") as f: for line in f: lines.append(line) return lines @@ -329,7 +334,7 @@ def mark_forward_kinds(kind, definition): # - first as just the bare fields # - then as children of the typedef # - if "type" in child_info and isinstance(child_info["type"], collections.Mapping) and child_info["type"]["kind"] in ("struct", "union"): + if "type" in child_info and isinstance(child_info["type"], collMapping) and child_info["type"]["kind"] in ("struct", "union"): assert children[-1] == child_info["type"] children.pop() children.append(child_info) diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_get_cppflags.py b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_get_cppflags.py index b8432960ab2b4..9a5a6170ee876 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_get_cppflags.py +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_get_cppflags.py @@ -20,3 +20,28 @@ def get_cppflags(): pass return extra_flags + +def get_cppversion(): + # requested C++ version based on flags or environment variables + try: + return os.environ['STDCXX'] + except KeyError: + pass + + pstd = -1 + try: + flags = os.environ['EXTRA_CLING_ARGS'] + pstd = flags.find("std") + except KeyError: + pass + + if pstd < 0: + flags = get_cppflags() + pstd = flags.find("std") + + if 0 < pstd: + # syntax is "-std=c++XY" on Linux/Mac and "/std:c++NM" on Windows + return flags[pstd+7:pstd+9] + + return "20" # default but should never happen anyway + diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_version.py b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_version.py new file mode 100644 index 0000000000000..88d945d240ef7 --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/_version.py @@ -0,0 +1 @@ +__version__ = '6.32.8.1' diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindCppyy.cmake b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindCppyy.cmake index cd1e991572cd4..8e36ef871d508 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindCppyy.cmake +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindCppyy.cmake @@ -253,7 +253,7 @@ endfunction(cppyy_generate_init) # # cppyy_add_bindings( # "${PROJECT_NAME}" "${PROJECT_VERSION}" "user" "user@gmail.com" -# LANGUAGE_STANDARD "14" +# LANGUAGE_STANDARD "17" # GENERATE_OPTIONS "-D__PIC__;-Wno-macro-redefined" # INCLUDE_DIRS ${PCL_INCLUDE_DIRS} # LINKDEFS LinkDef.h @@ -318,7 +318,7 @@ function(cppyy_add_bindings pkg pkg_version author author_email) # Language standard. # if("${ARG_LANGUAGE_STANDARD}" STREQUAL "") - set(ARG_LANGUAGE_STANDARD "14") + set(ARG_LANGUAGE_STANDARD "17") endif() ################################################################ @@ -424,13 +424,14 @@ function(cppyy_add_bindings pkg pkg_version author author_email) list(APPEND cling_args "-f" ${cpp_file}) list(APPEND cling_args "-s" ${pkg_simplename}) list(APPEND cling_args "-rmf" ${rootmap_file} "-rml" ${lib_file}) + list(APPEND cling_args "--interpreteronly") foreach(in_pcm IN LISTS ARG_IMPORTS) # # Create -m options for any imported .pcm files. # list(APPEND cling_args "-m" "${in_pcm}") endforeach(in_pcm) - list(APPEND cling_args "${ARG_GENERATE_OPTIONS}") + list(APPEND cling_args "-cxxflags='${ARG_GENERATE_OPTIONS}'") # run rootcling add_custom_command(OUTPUT ${cpp_file} ${pcm_file} ${rootmap_file} @@ -439,8 +440,7 @@ function(cppyy_add_bindings pkg pkg_version author author_email) ############### cppyy-generator ####################### find_package(LibClang REQUIRED) - get_filename_component(Cppyygen_EXECUTABLE ${Cppyy_EXECUTABLE} DIRECTORY) - set(Cppyygen_EXECUTABLE ${Cppyygen_EXECUTABLE}/cppyy-generator) + find_program(Cppyygen_EXECUTABLE NAMES cppyy-generator) # # Set up arguments for cppyy-generator. @@ -461,7 +461,7 @@ function(cppyy_add_bindings pkg pkg_version author author_email) endforeach() add_custom_command(OUTPUT ${extra_map_file} - COMMAND ${LibClang_Python3_EXECUTABLE} ${Cppyygen_EXECUTABLE} + COMMAND ${LibClang_PYTHON_EXECUTABLE} ${Cppyygen_EXECUTABLE} --libclang ${LibClang_LIBRARY} --flags "\"${generator_args}\"" ${extra_map_file} ${ARG_H_FILES} WORKING_DIRECTORY ${pkg_dir} DEPENDS ${ARG_H_FILES} @@ -516,7 +516,10 @@ function(cppyy_add_bindings pkg pkg_version author author_email) # Copy initializor # set(initializor ${CMAKE_CURRENT_BINARY_DIR}/initializor.py) - file(COPY ${BACKEND_PREFIX}/pkg_templates/initializor.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${pkg} USE_SOURCE_PERMISSIONS) + message(STATUS ${BACKEND_PREFIX}/pkg_templates/initializor.py) + if (EXISTS ${BACKEND_PREFIX}/pkg_templates/initializor.py) + file(COPY ${BACKEND_PREFIX}/pkg_templates/initializor.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${pkg} USE_SOURCE_PERMISSIONS) + endif() # # Copy README and LICENSE @@ -565,9 +568,9 @@ function(cppyy_add_bindings pkg pkg_version author author_email) string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSTEM_STR) set(pkg_whl "${CMAKE_BINARY_DIR}/dist/${pkg}-${pkg_version}-py3-none-${SYSTEM_STR}_${CMAKE_SYSTEM_PROCESSOR}.whl") add_custom_command(OUTPUT ${pkg_whl} - COMMAND ${LibClang_Python3_EXECUTABLE} setup.py bdist_wheel + COMMAND ${LibClang_PYTHON_EXECUTABLE} setup.py bdist_wheel DEPENDS ${SETUP_PY_FILE} ${lib_name} ${setup_cfg} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_custom_target(wheel ALL DEPENDS ${pkg_whl} diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindLibClang.cmake b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindLibClang.cmake index 73fde3cbfc7e5..c8d1d59b582bf 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindLibClang.cmake +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/cmake/FindLibClang.cmake @@ -10,14 +10,44 @@ # # LibClang_FOUND - True if libclang is found. # LibClang_LIBRARY - Clang library to link against. -# LibClang_VERSION - Version number as a string (e.g. "3.9"). +# LibClang_VERSION - Version number as a string (e.g. "9.0"). # LibClang_PYTHON_EXECUTABLE - Compatible python version. # -# Python support for clang might not be available for Python3. We need to -# find what we have. +# Find libclang.so/.dll to be used by the clang Python bindings # -find_library(LibClang_LIBRARY libclang.so PATH_SUFFIXES $ENV{CONDA_PREFIX}/lib x86_64-linux-gnu llvm llvm/6/lib64 llvm-6.0/lib) +if (NOT LibClang_LIBRARY) + set(LibClang_LIBRARY $ENV{LibClang_LIBRARY}) + if (NOT LibClang_LIBRARY) + find_library(LibClang_LIBRARY libclang${CMAKE_SHARED_LIBRARY_SUFFIX}) + if (NOT LibClang_LIBRARY) + find_program(LibClang_LLVM_CONFIG "llvm-config") + if (NOT LibClang_LLVM_CONFIG) + set(llvm_config_versioned llvm-config) + foreach(version RANGE 13 6) + list(APPEND llvm_config_versioned "llvm-config-${version}") + endforeach () + find_program(LibClang_LLVM_CONFIG NAMES ${llvm_config_versioned}) + endif () + + set(LibClang_PREFIX "") + if (LibClang_LLVM_CONFIG) + execute_process(COMMAND ${LibClang_LLVM_CONFIG} --prefix OUTPUT_VARIABLE LibClang_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() + + set(LibClang_SUFFIX_versioned llvm) + foreach(version RANGE 13 6) + list(APPEND LibClang_SUFFIX_versioned "llvm-${version}/lib" "llvm/${version}/lib") + endforeach () + + find_library(LibClang_LIBRARY libclang${CMAKE_SHARED_LIBRARY_SUFFIX} + HINTS ${LibClang_PREFIX} $ENV{CONDA_PREFIX} + PATH_SUFFIXES lib lib64 x86_64-linux-gnu ${LibClang_SUFFIX_versioned} + ) + endif() + endif() +endif() + function(_find_libclang_python python_executable) # # Prefer python3 explicitly or implicitly over python2. @@ -48,7 +78,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibClang REQUIRED_VARS LibClang_LIBRARY LibCl VERSION_VAR LibClang_VERSION) find_program(CLANG_EXE clang++) -EXECUTE_PROCESS( COMMAND ${CLANG_EXE} --version OUTPUT_VARIABLE clang_full_version_string ) +execute_process(COMMAND ${CLANG_EXE} --version OUTPUT_VARIABLE clang_full_version_string OUTPUT_STRIP_TRAILING_WHITESPACE) string (REGEX REPLACE ".*clang version ([0-9]+\\.[0-9]+\\.[0-9]+).*" "\\1" CLANG_VERSION_STRING "${clang_full_version_string}") set(CLANG_VERSION_STRING ${CLANG_VERSION_STRING} PARENT_SCOPE) diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/pkg_templates/initializor.py b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/pkg_templates/initializor.py index 213332e589d18..463a578b9c069 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/pkg_templates/initializor.py +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/python/cppyy_backend/pkg_templates/initializor.py @@ -63,7 +63,7 @@ def add_pythonizations(py_files, noisy=False): continue tokens = name.split('_') if len(tokens) > 1: - namespace = tokens[1] + namespace = "::".join(tokens[1:]) if noisy: print('added pythonization', func, namespace) if namespace == 'gbl': @@ -218,3 +218,4 @@ def map_operator_name(name): continue simplenames = child["name"].split('::') add_to_pkg(file["name"], child["kind"], simplenames, child) + diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/setup.cfg b/bindings/pyroot/cppyy/cppyy-backend/cling/setup.cfg index 82bf11f7840c7..ef9e2d189a6fd 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/cling/setup.cfg +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/setup.cfg @@ -1,5 +1,2 @@ -[bdist_wheel] -universal=1 - [metadata] -license_file = LICENSE.txt +license_files = LICENSE.txt diff --git a/bindings/pyroot/cppyy/cppyy-backend/cling/setup.py b/bindings/pyroot/cppyy/cppyy-backend/cling/setup.py old mode 100644 new mode 100755 index 4c8d777d51932..1cb0ada9c749d --- a/bindings/pyroot/cppyy/cppyy-backend/cling/setup.py +++ b/bindings/pyroot/cppyy/cppyy-backend/cling/setup.py @@ -1,4 +1,4 @@ -import codecs, multiprocessing, os, sys, subprocess, stat +import codecs, multiprocessing, os, sys, subprocess, stat, re from setuptools import setup, find_packages from distutils import log @@ -22,6 +22,19 @@ with codecs.open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: long_description = f.read() +# https://packaging.python.org/guides/single-sourcing-package-version/ +def read(*parts): + with codecs.open(os.path.join(here, *parts), 'r') as fp: + return fp.read() + +def find_version(*file_paths): + version_file = read(*file_paths) + version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", + version_file, re.M) + if version_match: + return version_match.group(1) + raise RuntimeError("Unable to find version string.") + # # platform-dependent helpers @@ -33,7 +46,10 @@ def is_manylinux(): _is_manylinux = False try: for line in open('/etc/redhat-release').readlines(): - if 'CentOS release 6.10 (Final)' in line: + # mark manylinux1, manylinux2010, or manylinux2014 + if 'CentOS release 5.11 (Final)' in line or \ + 'CentOS release 6.10 (Final)' in line or \ + 'CentOS Linux release 7.9.2009 (Core)' in line: _is_manylinux = True break except (OSError, IOError): @@ -86,10 +102,10 @@ def run(self): builddir = get_builddir() prefix = get_prefix() srcdir = get_srcdir() - if not os.path.exists(srcdir): - log.info('No src directory ... creating with "python create_src_directory.py"') + if not os.path.exists(os.path.join(srcdir, 'interpreter')): + log.info('No Cling source found ... downloading with "python create_src_directory.py"') if subprocess.call([sys.executable, 'create_src_directory.py']) != 0: - log.error('ERROR: the source directory "%s" does not exist' % srcdir) + log.error('ERROR: the Cling source directory "%s" does not exist' % os.path.join(srcdir, 'interpreter')) log.error('Please run "python create_src_directory.py" first.') sys.exit(1) @@ -102,14 +118,12 @@ def run(self): stdcxx = os.environ['STDCXX'] except KeyError: if is_manylinux(): - stdcxx = '11' - elif 'win32' in sys.platform: - stdcxx = '14' # current cmake claims MSVC'17 does not support C++17 yet - else: stdcxx = '17' + else: + stdcxx = '20' - if not stdcxx in ['11', '14', '17']: - log.fatal('FATAL: envar STDCXX should be one of 11, 14, or 17') + if not stdcxx in ['14', '17', '20']: + log.fatal('FATAL: envar STDCXX should be one of 14, 17, or 20') sys.exit(1) stdcxx='-DCMAKE_CXX_STANDARD='+stdcxx @@ -133,24 +147,23 @@ def run(self): if has_avx: extra_args += ' -mavx' os.putenv('EXTRA_CLING_ARGS', extra_args) - CMAKE_COMMAND = ['cmake', srcdir, - stdcxx, '-DLLVM_ENABLE_TERMINFO=0', - '-Dminimal=ON', '-Dasimage=OFF', '-Droot7=OFF', '-Dhttp=OFF', - '-Dbuiltin_pcre=ON', '-Dbuiltin_freetype=ON', '-Dbuiltin_zlib=ON', '-Dbuiltin_xxhash=ON'] + CMAKE_COMMAND = ['cmake', srcdir, '-Wno-dev', + stdcxx, '-DLLVM_ENABLE_TERMINFO=0', '-DLLVM_ENABLE_ASSERTIONS=0', + '-Dminimal=ON', '-Dbuiltin_cling=ON', '-Druntime_cxxmodules=OFF', '-Dbuiltin_zlib=ON'] if 'darwin' in sys.platform: CMAKE_COMMAND.append('-Dlibcxx=ON') CMAKE_COMMAND.append('-DCMAKE_BUILD_TYPE='+get_build_type()) if 'win32' in sys.platform: import platform - if '64' in platform.architecture()[0]: - CMAKE_COMMAND += ['-Thost=x64', '-DCMAKE_GENERATOR_PLATFORM=x64', '-Dall=OFF', - '-Dmathmore=OFF', '-Dbuiltin_ftgl=OFF', '-Droofit=OFF', '-Dgfal=OFF', '-Dfftw3=OFF'] - FFTW_INC = os.environ.get("FFTW_INC", None) - FFTW_LIB = os.environ.get("FFTW_LIB", None) - if FFTW_INC and FFTW_LIB: - CMAKE_COMMAND += ["-DFFTW_INCLUDE_DIR={}".format(FFTW_INC), "-DFFTW_LIBRARY={}".format(FFTW_LIB)] - else: - CMAKE_COMMAND += ['-Dbuiltin_freetype=OFF'] + bits = platform.architecture()[0] + if '64' in bits: + CMAKE_COMMAND += ['-A x64', '-Thost=x64', '-DCMAKE_GENERATOR_PLATFORM=x64'] + elif '32' in bits: + CMAKE_COMMAND += ['-Thost=x86', '-DCMAKE_GENERATOR_PLATFORM=win32'] + elif 'darwin' in sys.platform: + import platform + if 'arm64' in platform.machine(): + CMAKE_COMMAND += ['-DLLVM_TARGETS_TO_BUILD=ARM;AArch64;NVPTX'] CMAKE_COMMAND.append('-DCMAKE_INSTALL_PREFIX='+prefix) log.info('Running cmake for cppyy-cling: %s', ' '.join(CMAKE_COMMAND)) @@ -241,42 +254,53 @@ def run(self): # remove allDict.cxx.pch as it's not portable (rebuild on first run, see cppyy) log.info('removing allDict.cxx.pch') os.remove(os.path.join(get_prefix(), 'etc', 'allDict.cxx.pch')) - # for manylinux, reset the default cxxversion to 17 if no user override - if not 'STDCXX' in os.environ and is_manylinux(): - log.info('updating root-config to C++17 for manylinux') + # fix-up the standard reported by cling-config (which calls root-config): if C++14 + # was requested, LLVM16 (and thus ROOT) will up it 17; and for manylinux,# which + # was build with 17, reset the default cxxversion to 20 if no user override + update_cxxversion = os.environ.get('STDCXX', None) + if update_cxxversion is None and is_manylinux(): + update_cxxversion = '2a' + + if update_cxxversion is not None: + # for manylinux, reset the default cxxversion to 20 if no user override + log.info('updating cling-config to C++%s' % update_cxxversion) inp = os.path.join(get_prefix(), 'bin', 'root-config') outp = inp+'.new' outfile = open(outp, 'w') for line in open(inp).readlines(): if line.find('cxxversionflag=', 0, 15) == 0: - line = 'cxxversionflag="-std=c++1z "\n' + line = 'cxxversionflag="-std=c++%s "\n' % update_cxxversion elif line.find('features=', 0, 9) == 0: - line = line.replace('cxx11', 'cxx17') + pcxx = line.find('cxx') + if 0 < pcxx: + line = line[:pcxx+3] + update_cxxversion + line[pcxx+5:] outfile.write(line) outfile.close() - os.rename(outp, inp) + os.replace(outp, inp) os.chmod(inp, stat.S_IMODE(os.lstat(inp).st_mode) | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) - log.info('updating allCppflags.txt to C++17 for manylinux') + log.info('updating allCppflags.txt to C++%s' % update_cxxversion) inp = os.path.join(get_prefix(), 'etc', 'dictpch', 'allCppflags.txt') outp = inp+'.new' outfile = open(outp, 'w') for line in open(inp).readlines(): if '-std=' == line[:5]: - line = '-std=c++1z\n' + line = '-std=c++%s\n' % update_cxxversion outfile.write(line) outfile.close() - os.rename(outp, inp) + os.replace(outp, inp) - log.info('updating compiledata.h to C++17 for manylinux') + log.info('updating compiledata.h to C++{update_cxxversion}') inp = os.path.join(get_prefix(), 'include', 'compiledata.h') outp = inp+'.new' outfile = open(outp, 'w') for line in open(inp).readlines(): - line = line.replace('-std=c++11', '-std=c++1z') + pstd = line.find('-std=c++') + if 0 < pstd: + line = line[pstd+8] + update_cxxversion + line[pstd+10:] outfile.write(line) outfile.close() - os.rename(outp, inp) + os.replace(outp, inp) install_path = self._get_install_path() log.info('Copying installation to: %s ...', install_path) @@ -287,7 +311,9 @@ def run(self): def get_outputs(self): outputs = _install.get_outputs(self) outputs.append(os.path.join(self._get_install_path(), 'cppyy_backend')) - outputs.append(os.path.join(self._get_install_path(), 'cppyy_backend', 'etc', 'allDict.cxx.pch')) + version = find_version('python', 'cppyy_backend', '_version.py') + outputs.append(os.path.join( + self._get_install_path(), 'cppyy_backend', 'etc', 'allDict.cxx.pch.'+str(version))) return outputs @@ -341,11 +367,10 @@ def run_commands(self): long_description=long_description, url='https://root.cern.ch/cling', - # Author details - author='ROOT Developers', - author_email='rootdev@cern.ch', + maintainer='Wim Lavrijsen', + maintainer_email='WLavrijsen@lbl.gov', - version='6.18.2.7', + version=find_version('python', 'cppyy_backend', '_version.py'), license='LLVM: UoI-NCSA; ROOT: LGPL 2.1', @@ -365,8 +390,13 @@ def run_commands(self): 'Operating System :: POSIX :: Linux', 'Operating System :: MacOS :: MacOS X', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', 'Programming Language :: C', 'Programming Language :: C++', @@ -377,8 +407,7 @@ def run_commands(self): setup_requires=['wheel'], - include_package_data=True, - package_data={'': ['cmake/*.cmake', 'pkg_templates/*.in', 'pkg_templates/*.py']}, + package_data={'cppyy_backend': ['cmake/*.cmake', 'pkg_templates/*.in', 'pkg_templates/*.py']}, package_dir={'': 'python'}, packages=find_packages('python', include=['cppyy_backend']), diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/LICENSE.txt b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/LICENSE.txt index 593bcd7fc5f84..838eb22c670ef 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/LICENSE.txt +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2017-2019, The Regents of the University of California, +Copyright (c) 2017-2021, The Regents of the University of California, through Lawrence Berkeley National Laboratory (subject to receipt of any required approvals from the U.S. Dept. of Energy). All rights reserved. Redistribution and use in source and binary forms, with or @@ -51,3 +51,5 @@ source code): Antonio Cuni Aditi Dutta Shaheed Haque + Aaron Jomy + Baidyanath Kundu diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/README.rst b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/README.rst index 311e4611913e1..a2dca8a1f3c37 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/README.rst +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/README.rst @@ -27,4 +27,4 @@ Change log: https://cppyy.readthedocs.io/en/latest/changelog.html Bug reports/feedback: - https://bitbucket.org/wlav/cppyy/issues?status=new&status=open + https://github.com/wlav/cppyy/issues diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/pyproject.toml b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/pyproject.toml new file mode 100644 index 0000000000000..d89eff41c60bf --- /dev/null +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["cppyy-cling==6.32.8", "setuptools", "wheel"] diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/setup.cfg b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/setup.cfg index 82bf11f7840c7..ef9e2d189a6fd 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/setup.cfg +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/setup.cfg @@ -1,5 +1,2 @@ -[bdist_wheel] -universal=1 - [metadata] -license_file = LICENSE.txt +license_files = LICENSE.txt diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/setup.py b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/setup.py old mode 100644 new mode 100755 index ee720f37651a1..28f5234057f26 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/setup.py +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/setup.py @@ -2,24 +2,13 @@ from setuptools import setup, find_packages, Extension from distutils import log -from setuptools.dist import Distribution from setuptools.command.install import install as _install from distutils.command.build_ext import build_ext as _build_ext from distutils.command.clean import clean as _clean from distutils.dir_util import remove_tree -try: - from wheel.bdist_wheel import bdist_wheel as _bdist_wheel - has_wheel = True -except ImportError: - has_wheel = False from distutils.errors import DistutilsSetupError -force_bdist = False -if '--force-bdist' in sys.argv: - force_bdist = True - sys.argv.remove('--force-bdist') - -requirements = ['cppyy-cling<6.18.3', 'cppyy-cling>=6.18.2.4'] +requirements = ['cppyy-cling==6.32.8'] setup_requirements = ['wheel'] if 'build' in sys.argv or 'install' in sys.argv: setup_requirements += requirements @@ -28,6 +17,10 @@ with codecs.open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: long_description = f.read() +if 'win32' in sys.platform: + soext = '.dll' +else: + soext = '.so' # # platform-dependent helpers @@ -43,7 +36,7 @@ def is_manylinux(): def _get_linker_options(): if 'win32' in sys.platform: - link_libraries = ['libCore', 'libThread', 'libRIO', 'libCling'] + link_libraries = ['libCoreLegacy', 'libThreadLegacy', 'libRIOLegacy', 'libCling'] import cppyy_backend link_dirs = [os.path.join(os.path.dirname(cppyy_backend.__file__), 'lib')] else: @@ -92,7 +85,7 @@ def build_extension(self, ext): ext_path = self.get_ext_fullpath(ext.name) output_dir = os.path.dirname(ext_path) libname_base = 'libcppyy_backend' - libname = libname_base+self.compiler.shared_lib_extension + libname = libname_base+soext # not: self.compiler.shared_lib_extension extra_postargs = list() if 'linux' in sys.platform: extra_postargs.append('-Wl,-Bsymbolic-functions') @@ -133,74 +126,14 @@ def run(self): _clean.run(self) class my_install(_install): - def _get_install_path(self): - # depending on goal, copy over pre-installed tree - if hasattr(self, 'bdist_dir') and self.bdist_dir: - install_path = self.bdist_dir - else: - install_path = self.install_lib - return install_path - def run(self): - # base install - _install.run(self) - - # custom install of backend - log.info('Now installing cppyy_backend') - builddir = self.build_lib - if not os.path.exists(builddir): - raise DistutilsSetupError('Failed to find build dir!') - - install_path = self._get_install_path() - log.info('Copying installation to: %s ...', install_path) - self.copy_tree(builddir, install_path) - - log.info('Install finished') - - def get_outputs(self): - outputs = _install.get_outputs(self) - #outputs.append(os.path.join(self._get_install_path(), 'cppyy_backend')) - return outputs + return _install.run(self) cmdclass = { 'build_ext': my_build_cpplib, - 'clean': my_clean, + #'clean': my_clean, 'install': my_install } -if has_wheel: - class my_bdist_wheel(_bdist_wheel): - def finalize_options(self): - # this is a universal, but platform-specific package; a combination - # that wheel does not recognize, thus simply fool it - from distutils.util import get_platform - self.plat_name = get_platform() - self.universal = True - _bdist_wheel.finalize_options(self) - self.root_is_pure = True - cmdclass['bdist_wheel'] = my_bdist_wheel - - -# -# customized distribition to disable binaries -# -class MyDistribution(Distribution): - def run_commands(self): - # pip does not resolve dependencies before building binaries, so unless - # packages are installed one-by-one, on old install is used or the build - # will simply fail hard. The following is not completely quiet, but at - # least a lot less conspicuous. - if not is_manylinux() and not force_bdist: - disabled = set(( - 'bdist_wheel', 'bdist_egg', 'bdist_wininst', 'bdist_rpm')) - for cmd in self.commands: - if not cmd in disabled: - self.run_command(cmd) - else: - log.info('Command "%s" is disabled', cmd) - cmd_obj = self.get_command_obj(cmd) - cmd_obj.get_outputs = lambda: None - else: - return Distribution.run_commands(self) setup( @@ -210,10 +143,10 @@ def run_commands(self): url='http://pypy.org', # Author details - author='PyPy Developers', - author_email='pypy-dev@python.org', + author='Wim Lavrijsen', + author_email='WLavrijsen@lbl.gov', - version='1.10.8', + version='1.15.3', license='LBNL BSD', @@ -247,7 +180,6 @@ def run_commands(self): sources=glob.glob(os.path.join('src', 'clingwrapper.cxx')))], cmdclass=cmdclass, - distclass=MyDistribution, zip_safe=False, ) diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/callcontext.h b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/callcontext.h index 26a73825a2484..edd7ca522c864 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/callcontext.h +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/callcontext.h @@ -1,6 +1,9 @@ #ifndef CPYCPPYY_CALLCONTEXT_H #define CPYCPPYY_CALLCONTEXT_H +// Standard +#include + //Bindings #include "cpp_cppyy.h" diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/capi.h b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/capi.h index d88cac939ef0a..829724b2db531 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/capi.h +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/capi.h @@ -11,6 +11,7 @@ extern "C" { typedef size_t cppyy_scope_t; typedef cppyy_scope_t cppyy_type_t; + typedef void* cppyy_enum_t; typedef void* cppyy_object_t; typedef intptr_t cppyy_method_t; @@ -22,6 +23,10 @@ extern "C" { /* direct interpreter access ---------------------------------------------- */ RPY_EXPORTED int cppyy_compile(const char* code); + RPY_EXPORTED + int cppyy_compile_silent(const char* code); + RPY_EXPORTED + char* cppyy_to_string(cppyy_type_t klass, cppyy_object_t obj); /* name to opaque C++ scope representation -------------------------------- */ RPY_EXPORTED @@ -37,6 +42,11 @@ extern "C" { RPY_EXPORTED size_t cppyy_size_of_type(const char* type_name); + RPY_EXPORTED + int cppyy_is_builtin(const char* type_name); + RPY_EXPORTED + int cppyy_is_complete(const char* type_name); + /* memory management ------------------------------------------------------ */ RPY_EXPORTED cppyy_object_t cppyy_allocate(cppyy_type_t type); @@ -99,8 +109,6 @@ extern "C" { RPY_EXPORTED int cppyy_is_namespace(cppyy_scope_t scope); RPY_EXPORTED - int cppyy_is_static_template(cppyy_scope_t scope, const char* name); - RPY_EXPORTED int cppyy_is_template(const char* template_name); RPY_EXPORTED int cppyy_is_abstract(cppyy_type_t type); @@ -108,6 +116,8 @@ extern "C" { int cppyy_is_enum(const char* type_name); RPY_EXPORTED int cppyy_is_aggregate(cppyy_type_t type); + RPY_EXPORTED + int cppyy_is_default_constructable(cppyy_type_t type); RPY_EXPORTED const char** cppyy_get_all_cpp_names(cppyy_scope_t scope, size_t* count); @@ -140,6 +150,9 @@ extern "C" { RPY_EXPORTED void cppyy_add_smartptr_type(const char* type_name); + RPY_EXPORTED + void cppyy_add_type_reducer(const char* reducable, const char* reduced); + /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ RPY_EXPORTED ptrdiff_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction); @@ -148,6 +161,8 @@ extern "C" { RPY_EXPORTED int cppyy_num_methods(cppyy_scope_t scope); RPY_EXPORTED + int cppyy_num_methods_ns(cppyy_scope_t scope); + RPY_EXPORTED cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name); RPY_EXPORTED @@ -166,7 +181,7 @@ extern "C" { RPY_EXPORTED int cppyy_method_req_args(cppyy_method_t); RPY_EXPORTED - char* cppyy_method_arg_name(cppyy_method_t,int arg_index); + char* cppyy_method_arg_name(cppyy_method_t, int arg_index); RPY_EXPORTED char* cppyy_method_arg_type(cppyy_method_t, int arg_index); RPY_EXPORTED @@ -183,10 +198,16 @@ extern "C" { RPY_EXPORTED int cppyy_get_num_templated_methods(cppyy_scope_t scope); RPY_EXPORTED + int cppyy_get_num_templated_methods_ns(cppyy_scope_t scope); + RPY_EXPORTED char* cppyy_get_templated_method_name(cppyy_scope_t scope, cppyy_index_t imeth); RPY_EXPORTED + int cppyy_is_templated_constructor(cppyy_scope_t scope, cppyy_index_t imeth); + RPY_EXPORTED int cppyy_exists_method_template(cppyy_scope_t scope, const char* name); RPY_EXPORTED + int cppyy_is_static_template(cppyy_scope_t scope, const char* name); + RPY_EXPORTED int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx); RPY_EXPORTED cppyy_method_t cppyy_get_method_template(cppyy_scope_t scope, const char* name, const char* proto); @@ -199,6 +220,8 @@ extern "C" { RPY_EXPORTED int cppyy_is_publicmethod(cppyy_method_t); RPY_EXPORTED + int cppyy_is_protectedmethod(cppyy_method_t); + RPY_EXPORTED int cppyy_is_constructor(cppyy_method_t); RPY_EXPORTED int cppyy_is_destructor(cppyy_method_t); @@ -209,6 +232,8 @@ extern "C" { RPY_EXPORTED int cppyy_num_datamembers(cppyy_scope_t scope); RPY_EXPORTED + int cppyy_num_datamembers_ns(cppyy_scope_t scope); + RPY_EXPORTED char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index); RPY_EXPORTED char* cppyy_datamember_type(cppyy_scope_t scope, int datamember_index); @@ -216,11 +241,15 @@ extern "C" { intptr_t cppyy_datamember_offset(cppyy_scope_t scope, int datamember_index); RPY_EXPORTED int cppyy_datamember_index(cppyy_scope_t scope, const char* name); + RPY_EXPORTED + int cppyy_datamember_index_enumerated(cppyy_scope_t scope, int datamember_index); /* data member properties ------------------------------------------------- */ RPY_EXPORTED int cppyy_is_publicdata(cppyy_type_t type, cppyy_index_t datamember_index); RPY_EXPORTED + int cppyy_is_protecteddata(cppyy_type_t type, cppyy_index_t datamember_index); + RPY_EXPORTED int cppyy_is_staticdata(cppyy_type_t type, cppyy_index_t datamember_index); RPY_EXPORTED int cppyy_is_const_data(cppyy_scope_t scope, cppyy_index_t idata); @@ -229,6 +258,16 @@ extern "C" { RPY_EXPORTED int cppyy_get_dimension_size(cppyy_scope_t scope, cppyy_index_t idata, int dimension); + /* enum properties -------------------------------------------------------- */ + RPY_EXPORTED + cppyy_enum_t cppyy_get_enum(cppyy_scope_t scope, const char* enum_name); + RPY_EXPORTED + cppyy_index_t cppyy_get_num_enum_data(cppyy_enum_t); + RPY_EXPORTED + const char* cppyy_get_enum_data_name(cppyy_enum_t, cppyy_index_t idata); + RPY_EXPORTED + long long cppyy_get_enum_data_value(cppyy_enum_t, cppyy_index_t idata); + /* misc helpers ----------------------------------------------------------- */ RPY_EXPORTED long long cppyy_strtoll(const char* str); diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx index 7a4b46499c16a..24035993a0779 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.cxx @@ -1,3 +1,10 @@ +#ifndef WIN32 +#ifndef _CRT_SECURE_NO_WARNINGS +// silence warnings about getenv, strncpy, etc. +#define _CRT_SECURE_NO_WARNINGS +#endif +#endif + // Bindings #include "capi.h" #include "cpp_cppyy.h" @@ -29,6 +36,7 @@ #include "TMethodArg.h" #include "TROOT.h" #include "TSystem.h" +#include "TThread.h" // Standard #include @@ -101,15 +109,14 @@ class CallWrapper { typedef const void* DeclId_t; public: - CallWrapper(TFunction* f) : fDecl(f->GetDeclId()), fName(f->GetName()), fTF(nullptr) {} + CallWrapper(TFunction* f) : fDecl(f->GetDeclId()), fName(f->GetName()), fTF(new TFunction(*f)) {} CallWrapper(DeclId_t fid, const std::string& n) : fDecl(fid), fName(n), fTF(nullptr) {} ~CallWrapper() { - if (fTF && fDecl == fTF->GetDeclId()) - delete fTF; + delete fTF; } public: - TInterpreter::CallFuncIFacePtr_t fFaceptr; + TInterpreter::CallFuncIFacePtr_t fFaceptr; DeclId_t fDecl; std::string fName; TFunction* fTF; @@ -118,14 +125,17 @@ class CallWrapper { } static std::vector gWrapperHolder; -static inline CallWrapper* new_CallWrapper(TFunction* f) + +static inline +CallWrapper* new_CallWrapper(TFunction* f) { CallWrapper* wrap = new CallWrapper(f); gWrapperHolder.push_back(wrap); return wrap; } -static inline CallWrapper* new_CallWrapper(CallWrapper::DeclId_t fid, const std::string& n) +static inline +CallWrapper* new_CallWrapper(CallWrapper::DeclId_t fid, const std::string& n) { CallWrapper* wrap = new CallWrapper(fid, n); gWrapperHolder.push_back(wrap); @@ -133,7 +143,10 @@ static inline CallWrapper* new_CallWrapper(CallWrapper::DeclId_t fid, const std: } typedef std::vector GlobalVars_t; +typedef std::map GlobalVarsIndices_t; + static GlobalVars_t g_globalvars; +static GlobalVarsIndices_t g_globalidx; static std::set gSTLNames; @@ -237,7 +250,7 @@ class ApplicationStarter { // setup dummy holders for global and std namespaces assert(g_classrefs.size() == GLOBAL_HANDLE); - g_name2classrefidx[""] = GLOBAL_HANDLE; + g_name2classrefidx[""] = GLOBAL_HANDLE; g_classrefs.push_back(TClassRef("")); // aliases for std (setup already in pythonify) @@ -247,6 +260,7 @@ class ApplicationStarter { // add a dummy global to refer to as null at index 0 g_globalvars.push_back(nullptr); + g_globalidx[nullptr] = 0; // disable fast path if requested if (getenv("CPPYY_DISABLE_FASTPATH")) gEnableFastPath = false; @@ -306,6 +320,9 @@ class ApplicationStarter { "namespace __cppyy_internal { template" " bool is_not_equal(const C1& c1, const C2& c2) { return (bool)(c1 != c2); } }"); + // helper for multiple inheritance + gInterpreter->Declare("namespace __cppyy_internal { struct Sep; }"); + // retrieve all initial (ROOT) C++ names in the global scope to allow filtering later if (!getenv("CPPYY_NO_ROOT_FILTER")) { gROOT->GetListOfGlobals(true); // force initialize @@ -355,7 +372,7 @@ TClassRef& type_from_handle(Cppyy::TCppScope_t scope) static inline TFunction* m2f(Cppyy::TCppMethod_t method) { CallWrapper* wrap = ((CallWrapper*)method); - if (!wrap->fTF || wrap->fTF->GetDeclId() != wrap->fDecl) { + if (!wrap->fTF) { MethodInfo_t* mi = gInterpreter->MethodInfo_Factory(wrap->fDecl); wrap->fTF = new TFunction(mi); } @@ -641,6 +658,17 @@ Cppyy::TCppType_t Cppyy::GetActualClass(TCppType_t klass, TCppObject_t obj) TClassRef& cr = type_from_handle(klass); if (!cr.GetClass() || !obj) return klass; + if (!(cr->ClassProperty() & kClassHasVirtual)) + return klass; // not polymorphic: no RTTI info available + +// TODO: ios class casting (ostream, streambuf, etc.) fails with a crash in GetActualClass() +// below on Mac ARM (it's likely that the found actual class was replaced, maybe because +// there are duplicates from pcm/pch?); filter them out for now as it's usually unnecessary +// anyway to autocast these + std::string clName = cr->GetName(); + if (clName.find("std::", 0, 5) == 0 && clName.find("stream") != std::string::npos) + return klass; + #ifdef _WIN64 // Cling does not provide a consistent ImageBase address for calculating relative addresses // as used in Windows 64b RTTI. So, check for our own RTTI extension instead. If that fails, @@ -1428,7 +1456,7 @@ Cppyy::TCppIndex_t GetLongestInheritancePath(TClass *klass) } //////////////////////////////////////////////////////////////////////////////// -/// \fn Cppyy::TCppIndex_t Cppyy::GetNumBasesLongestBranch(TCppType_t klass) +/// \fn Cppyy::TCppIndex_t Cppyy::GetNumBasesLongest(TCppType_t klass) /// \brief Retrieve number of base classes in the longest branch of the /// inheritance tree. /// \param[in] klass The class to start the retrieval process from. @@ -1460,7 +1488,9 @@ bool Cppyy::IsSubtype(TCppType_t derived, TCppType_t base) return true; TClassRef& derived_type = type_from_handle(derived); TClassRef& base_type = type_from_handle(base); - return derived_type->GetBaseClass(base_type) != 0; + if (derived_type.GetClass() && base_type.GetClass()) + return derived_type->GetBaseClass(base_type) != 0; + return false; } bool Cppyy::IsSmartPtr(TCppType_t klass) @@ -1595,7 +1625,10 @@ std::vector Cppyy::GetMethodIndicesFromName( TIter next(cr->GetListOfMethods()); while ((func = (TFunction*)next())) { if (match_name(name, func->GetName())) { - if (func->Property() & kIsPublic) + // C++ functions should be public to allow access; C functions have no access + // specifier and should always be accepted + auto prop = func->Property(); + if ((prop & kIsPublic) || !(prop & (kIsPrivate | kIsProtected | kIsPublic))) indices.push_back((TCppIndex_t)imeth); } ++imeth; @@ -1668,9 +1701,12 @@ std::string Cppyy::GetMethodResultType(TCppMethod_t method) if (f->ExtraProperty() & kIsConstructor) return "constructor"; std::string restype = f->GetReturnTypeName(); - // TODO: this is ugly, but we can't use GetReturnTypeName() for ostreams - // and maybe others, whereas GetReturnTypeNormalizedName() has proven to - // be save in all cases (Note: 'int8_t' covers 'int8_t' and 'uint8_t') + // TODO: this is ugly; GetReturnTypeName() keeps typedefs, but may miss scopes + // for some reason; GetReturnTypeNormalizedName() has been modified to return + // the canonical type to guarantee correct namespaces. Sometimes typedefs look + // better, sometimes not, sometimes it's debatable (e.g. vector::size_type). + // So, for correctness sake, GetReturnTypeNormalizedName() is used, except for a + // special case of uint8_t/int8_t that must propagate as their typedefs. if (restype.find("int8_t") != std::string::npos) return restype; restype = f->GetReturnTypeNormalizedName(); @@ -1724,6 +1760,13 @@ std::string Cppyy::GetMethodArgType(TCppMethod_t method, TCppIndex_t iarg) if (method) { TFunction* f = m2f(method); TMethodArg* arg = (TMethodArg*)f->GetListOfMethodArgs()->At((int)iarg); + std::string ft = arg->GetFullTypeName(); + if (ft.rfind("enum ", 0) != std::string::npos) { // special case to preserve 'enum' tag + std::string arg_type = arg->GetTypeNormalizedName(); + return arg_type.insert(arg_type.rfind("const ", 0) == std::string::npos ? 0 : 6, "enum "); + } else if (g_builtins.find(ft) != g_builtins.end() || ft.find("int8_t") != std::string::npos) + return ft; // do not resolve int8_t and uint8_t typedefs + return arg->GetTypeNormalizedName(); } return ""; @@ -1916,6 +1959,20 @@ bool Cppyy::IsMethodTemplate(TCppScope_t scope, TCppIndex_t idx) // helpers for Cppyy::GetMethodTemplate() static std::map gMethodTemplates; +static inline +void remove_space(std::string& n) { + std::string::iterator pos = std::remove_if(n.begin(), n.end(), isspace); + n.erase(pos, n.end()); +} + +static inline +bool template_compare(std::string n1, std::string n2) { + if (n1.back() == '>') n1 = n1.substr(0, n1.size()-1); + remove_space(n1); + remove_space(n2); + return n2.compare(0, n1.size(), n1) == 0; +} + Cppyy::TCppMethod_t Cppyy::GetMethodTemplate( TCppScope_t scope, const std::string& name, const std::string& proto) { @@ -1925,16 +1982,15 @@ Cppyy::TCppMethod_t Cppyy::GetMethodTemplate( // to do an explicit lookup that ignores the prototype (i.e. the full name should be // enough), and finally to ignore the template arguments part of the name as this fails // in cling if there are default parameters. -// It would be possible to get the prototype from the created functions and use that to -// do a new lookup, after which ROOT/meta will manage the function. However, neither -// TFunction::GetPrototype() nor TFunction::GetSignature() is of the proper form, so -// we'll/ manage the new TFunctions instead and will assume that they are cached on the -// calling side to prevent multiple creations. TFunction* func = nullptr; ClassInfo_t* cl = nullptr; if (scope == (cppyy_scope_t)GLOBAL_HANDLE) { func = gROOT->GetGlobalFunctionWithPrototype(name.c_str(), proto.c_str()); - if (func && name.back() == '>' && name != func->GetName()) - func = nullptr; // happens if implicit conversion matches the overload + if (func && name.back() == '>') { + // make sure that all template parameters match (more are okay, e.g. defaults or + // ones derived from the arguments or variadic templates) + if (!template_compare(name, func->GetName())) + func = nullptr; // happens if implicit conversion matches the overload + } } else { TClassRef& cr = type_from_handle(scope); if (cr.GetClass()) { @@ -1986,8 +2042,7 @@ Cppyy::TCppMethod_t Cppyy::GetMethodTemplate( // allow if requested template names match up to the result const std::string& alt = GetMethodFullName(cppmeth); if (name.size() < alt.size() && alt.find('<') == pos) { - const std::string& partial = name.substr(pos, name.size()-1-pos); - if (strncmp(partial.c_str(), alt.substr(pos, alt.size()-1-pos).c_str(), partial.size()) == 0) + if (template_compare(name, alt)) return cppmeth; } } @@ -2001,16 +2056,19 @@ Cppyy::TCppMethod_t Cppyy::GetMethodTemplate( static inline std::string type_remap(const std::string& n1, const std::string& n2) { -// Operator lookups of (C++ string, Python str) should succeeded, for the combos of +// Operator lookups of (C++ string, Python str) should succeed for the combos of // string/str, wstring/str, string/unicode and wstring/unicode; since C++ does not have a // operator+(std::string, std::wstring), we'll have to look up the same type and rely on // the converters in CPyCppyy/_cppyy. - if (n1 == "str") { + if (n1 == "str" || n1 == "unicode") { if (n2 == "std::basic_string,std::allocator >") return n2; // match like for like return "std::string"; // probably best bet - } else if (n1 == "float") + } else if (n1 == "float") { return "double"; // debatable, but probably intended + } else if (n1 == "complex") { + return "std::complex"; + } return n1; } @@ -2107,22 +2165,11 @@ Cppyy::TCppIndex_t Cppyy::GetNumDatamembers(TCppScope_t scope, bool accept_names return (TCppIndex_t)0; // unknown class? } -static TDataMember *GetDataMemberByIndex(TClassRef cr, int idata) -{ - if (!cr.GetClass() || !cr->GetListOfDataMembers()) - return nullptr; - - int numDMs = cr->GetListOfDataMembers()->GetSize(); - if ((int)idata < numDMs) - return (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); - return (TDataMember*)cr->GetListOfUsingDataMembers()->At((int)idata - numDMs); -} - std::string Cppyy::GetDatamemberName(TCppScope_t scope, TCppIndex_t idata) { TClassRef& cr = type_from_handle(scope); if (cr.GetClass()) { - TDataMember *m = GetDataMemberByIndex(cr, (int)idata); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); return m->GetName(); } assert(scope == GLOBAL_HANDLE); @@ -2130,6 +2177,18 @@ std::string Cppyy::GetDatamemberName(TCppScope_t scope, TCppIndex_t idata) return gbl->GetName(); } +static inline +int count_scopes(const std::string& tpname) +{ + int count = 0; + std::string::size_type pos = tpname.find("::", 0); + while (pos != std::string::npos) { + count++; + pos = tpname.find("::", pos+1); + } + return count; +} + std::string Cppyy::GetDatamemberType(TCppScope_t scope, TCppIndex_t idata) { if (scope == GLOBAL_HANDLE) { @@ -2147,16 +2206,24 @@ std::string Cppyy::GetDatamemberType(TCppScope_t scope, TCppIndex_t idata) TClassRef& cr = type_from_handle(scope); if (cr.GetClass()) { - TDataMember* m = GetDataMemberByIndex(cr, (int)idata); - // TODO: fix this upstream. Usually, we want m->GetFullTypeName(), because it does - // not resolve typedefs, but it looses scopes for inner classes/structs, so in that - // case m->GetTrueTypeName() should be used (this also cleans up the cases where - // the "full type" retains spurious "struct" or "union" in the name). - std::string fullType = m->GetFullTypeName(); - if (fullType != m->GetTrueTypeName()) { - const std::string& trueName = m->GetTrueTypeName(); - if (fullType.find("::") == std::string::npos && trueName.find("::") != std::string::npos) + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); + // TODO: fix this upstream ... Usually, we want m->GetFullTypeName(), because it + // does not resolve typedefs, but it looses scopes for inner classes/structs, it + // doesn't resolve constexpr (leaving unresolved names), leaves spurious "struct" + // or "union" in the name, and can not handle anonymous unions. In that case + // m->GetTrueTypeName() should be used. W/o clear criteria to determine all these + // cases, the general rules are to prefer the true name if the full type does not + // exist as a type for classes, and the most scoped name otherwise. + const char* ft = m->GetFullTypeName(); std::string fullType = ft ? ft : ""; + const char* tn = m->GetTrueTypeName(); std::string trueName = tn ? tn : ""; + if (!trueName.empty() && fullType != trueName && !IsBuiltin(trueName)) { + if ( (!TClass::GetClass(fullType.c_str()) && TClass::GetClass(trueName.c_str())) || \ + (count_scopes(trueName) > count_scopes(fullType)) ) { + bool is_enum_tag = fullType.rfind("enum ", 0) != std::string::npos; fullType = trueName; + if (is_enum_tag) + fullType.insert(fullType.rfind("const ", 0) == std::string::npos ? 0 : 6, "enum "); + } } if ((int)m->GetArrayDim()) { @@ -2187,23 +2254,41 @@ intptr_t Cppyy::GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata) TClassRef& cr = type_from_handle(scope); if (cr.GetClass()) { - TDataMember* m = GetDataMemberByIndex(cr, (int)idata); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); // CLING WORKAROUND: the following causes templates to be instantiated first within the proper // scope, making the lookup succeed and preventing spurious duplicate instantiations later. Also, // if the variable is not yet loaded, pull it in through gInterpreter. + intptr_t offset = (intptr_t)-1; if (m->Property() & kIsStatic) { if (strchr(cr->GetName(), '<')) gInterpreter->ProcessLine(((std::string)cr->GetName()+"::"+m->GetName()+";").c_str()); - if ((intptr_t)m->GetOffsetCint() == (intptr_t)-1) + offset = (intptr_t)m->GetOffsetCint(); // yes, CINT (GetOffset() is both wrong + // and caches that wrong result! + if (offset == (intptr_t)-1) return (intptr_t)gInterpreter->ProcessLine((std::string("&")+cr->GetName()+"::"+m->GetName()+";").c_str()); - } - return (intptr_t)m->GetOffsetCint(); // yes, CINT (GetOffset() is both wrong - // and caches that wrong result! + } else + offset = (intptr_t)m->GetOffsetCint(); // yes, CINT, see above + return offset; } return (intptr_t)-1; } +static inline +Cppyy::TCppIndex_t gb2idx(TGlobal* gb) +{ + if (!gb) return (Cppyy::TCppIndex_t)-1; + + auto pidx = g_globalidx.find(gb); + if (pidx == g_globalidx.end()) { + auto idx = g_globalvars.size(); + g_globalvars.push_back(gb); + g_globalidx[gb] = idx; + return (Cppyy::TCppIndex_t)idx; + } + return (Cppyy::TCppIndex_t)pidx->second; +} + Cppyy::TCppIndex_t Cppyy::GetDatamemberIndex(TCppScope_t scope, const std::string& name) { if (scope == GLOBAL_HANDLE) { @@ -2235,11 +2320,7 @@ Cppyy::TCppIndex_t Cppyy::GetDatamemberIndex(TCppScope_t scope, const std::strin if (wrap && wrap->GetAddress()) gb = wrap; } - if (gb) { - // TODO: do we ever need a reverse lookup? - g_globalvars.push_back(gb); - return TCppIndex_t(g_globalvars.size() - 1); - } + return gb2idx(gb); } else { TClassRef& cr = type_from_handle(scope); @@ -2248,16 +2329,22 @@ Cppyy::TCppIndex_t Cppyy::GetDatamemberIndex(TCppScope_t scope, const std::strin (TDataMember*)cr->GetListOfDataMembers()->FindObject(name.c_str()); // TODO: turning this into an index is silly ... if (dm) return (TCppIndex_t)cr->GetListOfDataMembers()->IndexOf(dm); - dm = (TDataMember*)cr->GetListOfUsingDataMembers()->FindObject(name.c_str()); - if (dm) - return (TCppIndex_t)cr->GetListOfDataMembers()->IndexOf(dm) - + cr->GetListOfDataMembers()->GetSize(); } } return (TCppIndex_t)-1; } +Cppyy::TCppIndex_t Cppyy::GetDatamemberIndexEnumerated(TCppScope_t scope, TCppIndex_t idata) +{ + if (scope == GLOBAL_HANDLE) { + TGlobal* gb = (TGlobal*)((THashList*)gROOT->GetListOfGlobals(false /* load */))->At((int)idata); + return gb2idx(gb); + } + + return idata; +} + // data member properties ---------------------------------------------------- bool Cppyy::IsPublicData(TCppScope_t scope, TCppIndex_t idata) @@ -2267,7 +2354,7 @@ bool Cppyy::IsPublicData(TCppScope_t scope, TCppIndex_t idata) TClassRef& cr = type_from_handle(scope); if (cr->Property() & kIsNamespace) return true; - TDataMember* m = GetDataMemberByIndex(cr, (int)idata); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); return m->Property() & kIsPublic; } @@ -2278,7 +2365,7 @@ bool Cppyy::IsProtectedData(TCppScope_t scope, TCppIndex_t idata) TClassRef& cr = type_from_handle(scope); if (cr->Property() & kIsNamespace) return true; - TDataMember* m = GetDataMemberByIndex(cr, (int)idata); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); return m->Property() & kIsProtected; } @@ -2289,22 +2376,26 @@ bool Cppyy::IsStaticData(TCppScope_t scope, TCppIndex_t idata) TClassRef& cr = type_from_handle(scope); if (cr->Property() & kIsNamespace) return true; - TDataMember* m = GetDataMemberByIndex(cr, (int)idata); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); return m->Property() & kIsStatic; } bool Cppyy::IsConstData(TCppScope_t scope, TCppIndex_t idata) { + Long_t property = 0; if (scope == GLOBAL_HANDLE) { TGlobal* gbl = g_globalvars[idata]; - return gbl->Property() & kIsConstant; + property = gbl->Property(); } TClassRef& cr = type_from_handle(scope); if (cr.GetClass()) { - TDataMember* m = GetDataMemberByIndex(cr, (int)idata); - return m->Property() & kIsConstant; + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); + property = m->Property(); } - return false; + +// if the data type is const, but the data member is a pointer/array, the data member +// itself is not const; alternatively it is a pointer that is constant + return ((property & kIsConstant) && !(property & (kIsPointer | kIsArray))) || (property & kIsConstPointer); } bool Cppyy::IsEnumData(TCppScope_t scope, TCppIndex_t idata) @@ -2324,11 +2415,11 @@ bool Cppyy::IsEnumData(TCppScope_t scope, TCppIndex_t idata) TClassRef& cr = type_from_handle(scope); if (cr.GetClass()) { - TDataMember* m = GetDataMemberByIndex(cr, (int)idata); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); std::string ti = m->GetTypeName(); // can't check anonymous enums by type name, so just accept them as enums - if (ti.rfind("(unnamed)") != std::string::npos) + if (ti.rfind("(anonymous)") != std::string::npos || ti.rfind("(unnamed)") != std::string::npos) return m->Property() & kIsEnum; // since there seems to be no distinction between data of enum type and enum values, @@ -2355,7 +2446,7 @@ int Cppyy::GetDimensionSize(TCppScope_t scope, TCppIndex_t idata, int dimension) } TClassRef& cr = type_from_handle(scope); if (cr.GetClass()) { - TDataMember* m = GetDataMemberByIndex(cr, (int)idata); + TDataMember* m = (TDataMember*)cr->GetListOfDataMembers()->At((int)idata); return m->GetMaxIndex(dimension); } return -1; @@ -2382,12 +2473,12 @@ Cppyy::TCppIndex_t Cppyy::GetNumEnumData(TCppEnum_t etype) std::string Cppyy::GetEnumDataName(TCppEnum_t etype, TCppIndex_t idata) { - return ((TEnumConstant*)((TEnum*)etype)->GetConstants()->At(idata))->GetName(); + return ((TEnumConstant*)((TEnum*)etype)->GetConstants()->At((int)idata))->GetName(); } long long Cppyy::GetEnumDataValue(TCppEnum_t etype, TCppIndex_t idata) { - TEnumConstant* ecst = (TEnumConstant*)((TEnum*)etype)->GetConstants()->At(idata); + TEnumConstant* ecst = (TEnumConstant*)((TEnum*)etype)->GetConstants()->At((int)idata); return (long long)ecst->GetValue(); } @@ -2400,6 +2491,14 @@ int cppyy_compile(const char* code) { return Cppyy::Compile(code); } +int cppyy_compile_silent(const char* code) { + return Cppyy::Compile(code, true /* silent */); +} + +char* cppyy_to_string(cppyy_type_t klass, cppyy_object_t obj) { + return cppstring_to_cstring(Cppyy::ToString(klass, obj)); +} + /* name to opaque C++ scope representation -------------------------------- */ char* cppyy_resolve_name(const char* cppitem_name) { @@ -2426,6 +2525,14 @@ size_t cppyy_size_of_type(const char* type_name) { return Cppyy::SizeOf(type_name); } +int cppyy_is_builtin(const char* type_name) { + return (int)Cppyy::IsBuiltin(type_name); +} + +int cppyy_is_complete(const char* type_name) { + return (int)Cppyy::IsComplete(type_name); +} + /* memory management ------------------------------------------------------ */ cppyy_object_t cppyy_allocate(cppyy_type_t type) { @@ -2616,6 +2723,10 @@ int cppyy_is_aggregate(cppyy_type_t type) { return (int)Cppyy::IsAggregate(type); } +int cppyy_is_default_constructable(cppyy_type_t type) { + return (int)Cppyy::IsDefaultConstructable(type); +} + const char** cppyy_get_all_cpp_names(cppyy_scope_t scope, size_t* count) { std::set cppnames; Cppyy::GetAllCppNames(scope, cppnames); @@ -2665,10 +2776,6 @@ int cppyy_num_bases(cppyy_type_t type) { return (int)Cppyy::GetNumBases(type); } -int cppyy_num_bases_longest_branch(cppyy_type_t type) { - return (int)Cppyy::GetNumBasesLongestBranch(type); -} - char* cppyy_base_name(cppyy_type_t type, int base_index) { return cppstring_to_cstring(Cppyy::GetBaseName (type, base_index)); } @@ -2689,6 +2796,10 @@ void cppyy_add_smartptr_type(const char* type_name) { Cppyy::AddSmartPtrType(type_name); } +void cppyy_add_type_reducer(const char* reducable, const char* reduced) { + Cppyy::AddTypeReducer(reducable, reduced); +} + /* calculate offsets between declared and actual type, up-cast: direction > 0; down-cast: direction < 0 */ ptrdiff_t cppyy_base_offset(cppyy_type_t derived, cppyy_type_t base, cppyy_object_t address, int direction) { @@ -2701,6 +2812,10 @@ int cppyy_num_methods(cppyy_scope_t scope) { return (int)Cppyy::GetNumMethods(scope); } +int cppyy_num_methods_ns(cppyy_scope_t scope) { + return (int)Cppyy::GetNumMethods(scope, true); +} + cppyy_index_t* cppyy_method_indices_from_name(cppyy_scope_t scope, const char* name) { std::vector result = Cppyy::GetMethodIndicesFromName(scope, name); @@ -2768,15 +2883,19 @@ char* cppyy_method_prototype(cppyy_scope_t scope, cppyy_method_t method, int sho } int cppyy_is_const_method(cppyy_method_t method) { - return (int)Cppyy::IsConstMethod(method); + return (int)Cppyy::IsConstMethod((Cppyy::TCppMethod_t)method); } int cppyy_get_num_templated_methods(cppyy_scope_t scope) { - return (int)Cppyy::GetNumTemplatedMethods(scope); + return (int)Cppyy::GetNumTemplatedMethods((Cppyy::TCppScope_t)scope); +} + +int cppyy_get_num_templated_methods_ns(cppyy_scope_t scope) { + return (int)Cppyy::GetNumTemplatedMethods((Cppyy::TCppScope_t)scope, true); } char* cppyy_get_templated_method_name(cppyy_scope_t scope, cppyy_index_t imeth) { - return cppstring_to_cstring(Cppyy::GetTemplatedMethodName(scope, imeth)); + return cppstring_to_cstring(Cppyy::GetTemplatedMethodName((Cppyy::TCppScope_t)scope, (Cppyy::TCppIndex_t)imeth)); } int cppyy_is_templated_constructor(cppyy_scope_t scope, cppyy_index_t imeth) { @@ -2784,7 +2903,7 @@ int cppyy_is_templated_constructor(cppyy_scope_t scope, cppyy_index_t imeth) { } int cppyy_exists_method_template(cppyy_scope_t scope, const char* name) { - return (int)Cppyy::ExistsMethodTemplate(scope, name); + return (int)Cppyy::ExistsMethodTemplate((Cppyy::TCppScope_t)scope, name); } int cppyy_is_static_template(cppyy_scope_t scope, const char* name) { @@ -2792,11 +2911,11 @@ int cppyy_is_static_template(cppyy_scope_t scope, const char* name) { } int cppyy_method_is_template(cppyy_scope_t scope, cppyy_index_t idx) { - return (int)Cppyy::IsMethodTemplate(scope, idx); + return (int)Cppyy::IsMethodTemplate((Cppyy::TCppScope_t)scope, idx); } cppyy_method_t cppyy_get_method_template(cppyy_scope_t scope, const char* name, const char* proto) { - return cppyy_method_t(Cppyy::GetMethodTemplate(scope, name, proto)); + return cppyy_method_t(Cppyy::GetMethodTemplate((Cppyy::TCppScope_t)scope, name, proto)); } cppyy_index_t cppyy_get_global_operator(cppyy_scope_t scope, cppyy_scope_t lc, cppyy_scope_t rc, const char* op) { @@ -2831,6 +2950,10 @@ int cppyy_num_datamembers(cppyy_scope_t scope) { return (int)Cppyy::GetNumDatamembers(scope); } +int cppyy_num_datamembers_ns(cppyy_scope_t scope) { + return (int)Cppyy::GetNumDatamembers(scope, true); +} + char* cppyy_datamember_name(cppyy_scope_t scope, int datamember_index) { return cppstring_to_cstring(Cppyy::GetDatamemberName(scope, datamember_index)); } @@ -2847,6 +2970,9 @@ int cppyy_datamember_index(cppyy_scope_t scope, const char* name) { return (int)Cppyy::GetDatamemberIndex(scope, name); } +int cppyy_datamember_index_enumerated(cppyy_scope_t scope, int datamember_index) { + return (int)Cppyy::GetDatamemberIndexEnumerated(scope, datamember_index); +} /* data member properties ------------------------------------------------- */ @@ -2875,6 +3001,24 @@ int cppyy_get_dimension_size(cppyy_scope_t scope, cppyy_index_t idata, int dimen } +/* enum properties -------------------------------------------------------- */ +cppyy_enum_t cppyy_get_enum(cppyy_scope_t scope, const char* enum_name) { + return Cppyy::GetEnum(scope, enum_name); +} + +cppyy_index_t cppyy_get_num_enum_data(cppyy_enum_t e) { + return Cppyy::GetNumEnumData(e); +} + +const char* cppyy_get_enum_data_name(cppyy_enum_t e, cppyy_index_t idata) { + return cppstring_to_cstring(Cppyy::GetEnumDataName(e, idata)); +} + +long long cppyy_get_enum_data_value(cppyy_enum_t e, cppyy_index_t idata) { + return Cppyy::GetEnumDataValue(e, idata); +} + + /* misc helpers ----------------------------------------------------------- */ RPY_EXTERN void* cppyy_load_dictionary(const char* lib_name) { diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.h b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.h index fef5824ce3333..4f765763a640a 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.h +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/clingwrapper.h @@ -8,6 +8,7 @@ extern "C" { #endif // ifdef __cplusplus /* misc helpers */ + RPY_EXPORTED void* cppyy_load_dictionary(const char* lib_name); #ifdef __cplusplus diff --git a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h index fca4934c7c074..c72d855deaad4 100644 --- a/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h +++ b/bindings/pyroot/cppyy/cppyy-backend/clingwrapper/src/cpp_cppyy.h @@ -8,11 +8,27 @@ #include #include +// some more types; assumes Cppyy.h follows Python.h +#ifndef PY_LONG_LONG +#ifdef _WIN32 +typedef __int64 PY_LONG_LONG; +#else +typedef long long PY_LONG_LONG; +#endif +#endif + +#ifndef PY_ULONG_LONG +#ifdef _WIN32 +typedef unsigned __int64 PY_ULONG_LONG; +#else +typedef unsigned long long PY_ULONG_LONG; +#endif +#endif + +#ifndef PY_LONG_DOUBLE +typedef long double PY_LONG_DOUBLE; +#endif -// ROOT types -typedef long long Long64_t; -typedef unsigned long long ULong64_t; -typedef long double LongDouble_t; namespace Cppyy { typedef size_t TCppScope_t; @@ -76,13 +92,14 @@ namespace Cppyy { RPY_EXPORTED long CallL(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args); RPY_EXPORTED - Long64_t CallLL(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args); + PY_LONG_LONG CallLL(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args); RPY_EXPORTED float CallF(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args); RPY_EXPORTED double CallD(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args); RPY_EXPORTED - LongDouble_t CallLD(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args); + PY_LONG_DOUBLE CallLD(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args); + RPY_EXPORTED void* CallR(TCppMethod_t method, TCppObject_t self, size_t nargs, void* args); RPY_EXPORTED @@ -239,6 +256,8 @@ namespace Cppyy { intptr_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata); RPY_EXPORTED TCppIndex_t GetDatamemberIndex(TCppScope_t scope, const std::string& name); + RPY_EXPORTED + TCppIndex_t GetDatamemberIndexEnumerated(TCppScope_t scope, TCppIndex_t idata); // data member properties ---------------------------------------------------- RPY_EXPORTED