././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/.cirrus.yml0000644000000000000000000000311314607715450013365 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT test_template: &test test_script: - command -v python3 - python3 --version - python3 -m venv env - . env/bin/activate - python3 -m pip install .[test] - python3 -m pytest alpine-3_task: container: dockerfile: ci/alpine-3.docker cpu: 1 << : *test archlinux_task: container: dockerfile: ci/archlinux.docker cpu: 1 << : *test debian-11_task: container: dockerfile: ci/debian-11.docker cpu: 1 << : *test debian-12_task: container: dockerfile: ci/debian-12.docker cpu: 1 << : *test debian-unstable_task: container: dockerfile: ci/debian-unstable.docker cpu: 1 << : *test fedora-37_task: container: dockerfile: ci/fedora-37.docker cpu: 1 << : *test manylinux-python3.11_task: container: dockerfile: ci/manylinux.docker cpu: 1 env: PATH: "/opt/python/cp311-cp311/bin/:${PATH}" << : *test manylinux-python3.7_task: container: dockerfile: ci/manylinux.docker cpu: 1 env: PATH: "/opt/python/cp37-cp37m/bin/:${PATH}" << : *test miniconda_task: container: dockerfile: ci/miniconda.docker cpu: 1 << : *test opensuse-15_task: container: dockerfile: ci/opensuse-15.docker cpu: 1 << : *test freebsd_task: freebsd_instance: image_family: freebsd-13-2 install_script: pkg install -y git ninja << : *test macos-arm64_task: macos_instance: image: ghcr.io/cirruslabs/macos-ventura-xcode install_script: brew install git ninja python@3.11 << : *test ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/.github/workflows/docs.yml0000644000000000000000000000204714607715450016332 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT name: docs on: push: tags: - '[0-9]+.[0-9]+.[0-9]+' pull_request: branches: - main - release-* paths: - docs/** - CHANGELOG.rst - README.md workflow_dispatch: inputs: tag: required: true jobs: build: runs-on: ubuntu-latest steps: - uses: actions/setup-python@v5 with: python-version: '3.11' - uses: actions/checkout@v4 with: ref: ${{ github.event.push.tag || github.event.inputs.tag }} - run: python -m pip install .[docs] - run: python -m sphinx -W docs/ build/docs/ - uses: actions/upload-pages-artifact@v2 with: path: build/docs/ deploy: needs: build permissions: pages: write id-token: write environment: name: github-pages runs-on: ubuntu-latest if: ${{ github.event.push.tag || github.event.inputs.tag }} steps: - uses: actions/deploy-pages@v2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/.github/workflows/tests.yml0000644000000000000000000002141314607715450016542 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT name: tests on: push: branches: - main - release-* pull_request: branches: - main - release-* paths: # This is spelt like this to do not ignore the docs/examples/ folder. - '**' - '!docs/**' - 'docs/examples/**' - '!CHANGELOG.rst' - '!LICENSE' - '!LICENSES/**' - '!README.rst' - '!.github/workflows/docs.yml' workflow_dispatch: # Allow to run manually env: FORCE_COLOR: 1 PIP_DISABLE_PIP_VERSION_CHECK: 1 concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true jobs: test: runs-on: ${{ matrix.os }}-latest strategy: fail-fast: false matrix: os: - ubuntu - macos - windows python: - '3.7' - '3.12' meson: - include: - os: ubuntu python: 'pypy-3.9' - os: ubuntu python: 'pypy-3.10' - os: ubuntu python: '3.8' - os: ubuntu python: '3.9' - os: ubuntu python: '3.10' # Test with older supported Meson version. Meson up to # version 1.2.3 requires distutils, which has been removed # from the stdlib in Python 3.12, thus test with Pythn 3.11. - os: ubuntu python: '3.11' meson: '~=0.63.3' - os: ubuntu python: '3.11' meson: '~=0.64.0' - os: ubuntu python: '3.11' meson: '~=1.0.0' - os: ubuntu python: '3.11' meson: '~=1.1.0' - os: ubuntu python: '3.12' meson: '~=1.2.3' - os: ubuntu python: '3.12' meson: '~=1.3' # Test with Meson master branch. - os: ubuntu python: '3.12' meson: '@git+https://github.com/mesonbuild/meson.git' - os: windows python: '3.12' meson: '@git+https://github.com/mesonbuild/meson.git' steps: - name: Checkout uses: actions/checkout@v4 - name: Set up target Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - name: Install Ninja run: sudo apt-get install ninja-build if: ${{ matrix.os == 'ubuntu' }} - name: Install Ninja run: brew install ninja if: ${{ matrix.os == 'macos' }} - name: Install Ninja run: python -m pip install ninja if: ${{ matrix.os == 'windows' }} - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: python -m pip install .[test] - name: Run tests run: >- python -m pytest --showlocals -vv --cov --cov-report=xml - name: Upload coverage report uses: codecov/codecov-action@v4 if: ${{ always() }} msvc: runs-on: windows-latest strategy: fail-fast: false matrix: python: - '3.11' meson: - steps: - name: Checkout uses: actions/checkout@v4 - name: Set up target Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - name: Install Ninja run: python -m pip install ninja - name: Setup MSVC uses: bus1/cabuild/action/msdevshell@e22aba57d6e74891d059d66501b6b5aed8123c4d # v1 with: architecture: x64 - name: Install Meson run: python -m pip install "meson==${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: python -m pip install .[test] - name: Run tests run: >- python -m pytest --showlocals -vv cygwin: runs-on: windows-latest strategy: fail-fast: false matrix: python: - '3.9' meson: - steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Cygwin uses: cygwin/cygwin-install-action@v2 with: packages: >- python39 python39-devel python39-pip python39-setuptools cmake gcc-core gcc-g++ git make ninja - name: Fix git dubious ownership # This addresses the "fatal: detected dubious ownership in # repository" and "fatal: not in a git directory" errors # encountered when trying to run Cygwin git in a directory not # owned by the current user. This happens when the tests run # Cygwin git in a directory outside the Cygwin filesystem. run: git config --global --add safe.directory '*' shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} - name: Get pip cache path id: pip-cache-path run: echo "path=$(cygpath -w $(python -m pip cache dir))" >> $GITHUB_OUTPUT shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} - name: Restore cache # Cygwin Python cannot use binary wheels from PyPI. Building # some dependencies takes considerable time. Caching the built # wheels speeds up the CI job quite a bit. uses: actions/cache@v4 with: path: ${{ steps.pip-cache-path.outputs.path }} key: cygwin-pip-${{ github.sha }} restore-keys: cygwin-pip- - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} - name: Install # Cygwin patches Python's ensurepip module to look for the # wheels needed to initialize a new virtual environment in # /usr/share/python-wheels/ but nothing in Cygwin actually # puts the setuptools and pip wheels there. Fix this. run: | mkdir /usr/share/python-wheels/ pushd /usr/share/python-wheels/ python -m pip download setuptools pip popd python -m pip install .[test] shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} - name: Run tests run: >- python -m pytest --showlocals -vv shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -leo pipefail -o igncr {0} pyston: runs-on: ubuntu-20.04 strategy: fail-fast: false matrix: python: - '3.8' meson: - steps: - name: Checkout uses: actions/checkout@v4 - name: Install pyston run: | wget https://github.com/pyston/pyston/releases/download/pyston_2.3.5/pyston_2.3.5_20.04_amd64.deb sudo apt install $(pwd)/pyston_2.3.5_20.04_amd64.deb - name: Install Ninja run: sudo apt-get install ninja-build - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: pyston -m pip install .[test] - name: Run tests run: >- pyston -m pytest --showlocals -vv homebrew: runs-on: macos-latest strategy: fail-fast: false matrix: python: - '3.8' - '3.11' meson: - steps: - name: Checkout uses: actions/checkout@v4 - name: Install Homebrew Python run: | brew install --overwrite python@${{ matrix.python }} echo /usr/local/opt/python@${{ matrix.python }}/libexec/bin/ >> $GITHUB_PATH - name: Install Ninja run: brew install ninja - name: Update pip # pip >= 23.0 fixes https://github.com/pypa/pip/issues/11539 run: python -m pip install --upgrade "pip >= 23.0" - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: python -m pip install .[test] - name: Run tests run: >- python -m pytest --showlocals -vv mypy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install dependencies run: python -m pip install . - name: Install mypy run: python -m pip install mypy==1.5.1 - name: Run mypy run: mypy -p mesonpy ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/.gitignore0000644000000000000000000000025214607715450013246 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT .mesonpy-native-file.ini .mesonpy/ docs/_build *.pyc .cache/ dist/ .coverage ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/.mailmap0000644000000000000000000000024714607715450012703 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT Matthias Köppe Yue Yang ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/.pre-commit-config.yaml0000644000000000000000000000166014607715450015543 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT ci: autofix_prs: false autoupdate_commit_msg: 'MAINT: bump repositories' repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: check-ast - id: check-builtin-literals - id: check-docstring-first - id: check-merge-conflict - id: check-yaml - id: check-toml - id: debug-statements - id: double-quote-string-fixer - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.5 hooks: - id: ruff args: [--fix, --show-fixes, --output-format, grouped] - repo: https://github.com/fsfe/reuse-tool rev: v2.1.0 hooks: - id: reuse name: add SPDX headers args: [annotate, --skip-existing, --skip-unrecognised, --copyright=The meson-python developers, --license=MIT] pass_filenames: true - id: reuse name: reuse lint ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/.readthedocs.yaml0000644000000000000000000000036414607715450014511 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT version: 2 build: os: ubuntu-22.04 tools: python: "3.11" python: install: - method: pip path: . extra_requirements: [docs] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/CHANGELOG.rst0000644000000000000000000002672414607715450013313 0ustar00.. SPDX-FileCopyrightText: 2021 The meson-python developers .. .. SPDX-License-Identifier: MIT .. Contributors list for the latest release can be generated with git log --format='%aN' $PREV..HEAD | sort -u | awk '$1=$1' RS='' FS='\n' OFS=', ' +++++++++ Changelog +++++++++ 0.16.0 ====== - Correctly detect a wheel shipping shared libraries as being platform dependent also when it does not ship compiled executables or Python extension modules. - Use 11.0 as minimum macOS platform ABI tag on arm64: lower versions do not exist on arm64. - Improve parsing of the ``$ARCHFLAGS`` environment variable. Correctly handle repeated ``-arch`` flags. - Do not break when trying to log filename containing Unicode characters that cannot be encoded in the encoding used by the standard output stream. - Drop dependency on ``colorama`` on Windows. - Suppress all uses of ANSI terminal escapes when logging to a stream that does not support them. - Fix ANSI escape coloring of error messages. - Respect the ``exclude_dirs`` and ``exclude_files`` arguments passed to the ``install_subdir()`` Meson function in editable installs too. - Make ``pkgutil.iter_packages()`` work properly for modules loaded from editable installs. - Add support for the ``custom_target()`` Meson function installing a directory. - In editable installs, when a rebuild is triggered on module import, emit a message indicating that the package is being rebuilt but suppress any output when there is no work to do. Daniele Nicolodi, Loïc Estève, Ralf Gommers --- 16-04-2024 0.15.0 ====== - Enable compression for wheel files. The may result in several times smaller wheels. - Require Meson 1.2.3 or later on Python 3.12 or later. Meson 1.2.3 does not require anymore ``distutils``, allowing to remove the dependency on ``setuptools`` on Python 3.12 or later. - Unconditionally require ``patchelf`` on Linux. The ``patchelf`` package is added to the build dependencies if a suitable ``patchelf`` executable is not find on the ``$PATH``. This avoids cases where ``meson setup`` was run twice during the build process to determine whether ``patchelf`` is required. - Allow to configure the ``meson`` executable to use for the build process through the ``$MESON`` environment variable or the ``meson`` key under ``[tool.meson-python]`` in ``pyproject.toml``. - Fix wheel platform tag generation on FreeBSD. - Extend support to other UNIX-like systems and make the tests pass on FreeBSD. - Fix package name normalization in package metadata and improve package name validation. - Fix ``RPATH`` handling when the build ``RPATH`` points to subdirectories of the build directory. - Fix support for the Python limited C API when compiling for PyPy. - Rename the ``builddir`` config-setting to ``build-dir``. For backwards compatibility, the ``buildir`` config-setting remains supported as an alias. Christoph Reiter, Daniele Nicolodi, Elliott Sales de Andrade, Ralf Gommers, Yue Yang --- 26-10-2023 0.14.0 ====== - Do not run ``meson install`` to build a wheel. This was unnecessary as files are added to the wheel from the build and source directories. This does not affect the handling of ``meson install`` options, which are interpreted by ``meson-python`` itself. - Obey the ``--skip-subprojects`` when specified for the ``meson install`` command. - Implement support for the ``exclude_directories`` and ``exclude_files`` arguments to Meson ``install_subdir()`` function and similar installation functions. This requires Meson version 1.1.0 or later. - Implement support for building wheels targeting the Python limited API. Extension modules targeting the Python limited API can be easily built starting with the upcoming Meson 1.3.0 release. - When ``pyproject.toml`` does not contain a ``version`` field and ``version`` is not declared dynamic, raise an error instead of silently using the version declared in ``meson.build``. - Fix the mtime of source files in the sdist tarball. - Add ``objc`` and ``objcpp`` compilers to the cross file generated when the ``$ARCHFLAGS`` is set. - Extensive documentation improvements. Charles Brunet, Daniele Nicolodi, Henry Schreiner, Michał Górny, Ralf Gommers --- 05-09-2023 0.13.2 ====== - Fix system name in cross file generated when using ``$ARCHFLAGS``. - Fix handling of ``null`` Meson install tags. Charles Brunet, Daniele Nicolodi --- 22-06-2023. 0.13.1 ====== - Fix regression in cross-compilation via ``$ARCHFLAGS`` on macOS where the cross file was written in the build directory before it was created, resulting in an error. - Do not require setting ``$_PYTHON_HOST_PLATFORM`` when cross-compiling via ``$ARCHFLAGS`` on macOS. - Add the ``--quiet`` option when invoking ``meson install``. The installation paths are a detail of the ``meson-python`` implementation and are generally not interesting for the user. - Fix terminal logging when overriding the current line when listing files added to the wheel. - Improve the error message emitted when a package split between the ``purelib`` and ``platlib`` wheel locations is detected. Daniele Nicolodi, Ralf Gommers --- 28-04-2023. 0.13.0 ====== - Add support for editable installs. - Adjust the default build options passed to ``meson setup``. - Make sure that the directory where the wheel or sdist build artifacts are created exists. Fixes building with PDM. - Fix the specification of the C++ compiler for cross-compilation with ``$ARCHFLAGS`` on macOS. - Pass the ``--reconfigure`` option to ``meson setup`` if and only if the specified build directory exists and is a valid Meson build directory. - Pass the ``--no-rebuild`` option to ``meson install``. - Allow to select the files to be included in the wheel via Meson install tags passing the ``--tags`` option to ``meson install`` via ``pyproject.toml`` or config settings. - Do not use the ``meson compile`` indirection to build the project, except on Windows, where it is required to setup the Visual Studio environment. - Do not add ``ninja`` to the build dependencies if ``$NINJA`` is set but it does not point to a ``ninja`` executable with the required minimum version. - Verify at run time that Meson satisfies the minimum required version. - Place native and cross files in the build directory instead of in the source directory. - Drop the ``typing-extensions`` package dependency. - Add dependency on ``setuptools`` on Python 3.12 and later. This fixes build error due to Meson depending on the ``distutils`` standard library module removed in Python 3.12. - Bump the required ``pyproject-metadata`` version to 0.7.1. - Allows some more cross-compilation setups by not checking extension modules filename suffixes against the suffixes accepted by the current interpreter. - Raise an error when a file that would be installed by Meson cannot be mapped to a wheel location. - Raise an error when a package is split between ``platlib`` and ``purelib``. - Do not generate a warning when ``pyproject.toml`` does not contain a ``project`` section and Python package metadata is derived from ``meson.build``. - Improve reporting of ``pyproject.toml`` validation errors. - Fix validation of tool specific options in ``pyproject.toml``. In particular, allows to specify an incomplete set of options in the ``tool.meson-python.args`` table. Daniele Nicolodi, Doron Behar, Eli Schwartz, Filipe Laíns, Lars Pastewka, Luigi Giugliano, Matthias Köppe, Peter Urban, Ralf Gommers, Stefan van der Walt, Thomas Li --- 18-04-2023. 0.12.1 ====== - Fix regression where the ``$MACOSX_DEPLOYMENT_TARGET`` environment variable was accidentally renamed to ``$MACOS_DEPLOYMENT_TARGET``. Filipe Laíns, Stefan van der Walt --- 17-02-2023. 0.12.0 ====== - Require the ``typing_extensions`` package for Python < 3.10 rather than for Python < 3.8 only. - Emit an error message and raise ``SystemExit`` on expected errors. - Revise error messages for consistency. - Support setuptools-style macOS cross compilation via ``$ARCHFLAGS``. - Allow to overwrite macOS platform tag via ``$_PYTHON_HOST_PLATFORM``. - Include an hint with the most similar known option names in the error message emitted when an unknown config setting is encountered. Daniele Nicolodi, Filipe Laíns, Henry Schreiner, Matthias Köppe, Thomas A Caswell --- 22-12-2022. 0.11.0 ====== - Project moved to the ``mesonbuild`` organization. - Determine wheel tags by introspecting the Python interpreter. - Allow users to pass options directly to Meson via the ``dist``, ``setup``, ``compile``, and ``install`` entries in the ``tools.meson-python.args`` table in ``pyproject.toml``, or via the ``dist-args``, ``setup-args``, ``compile-args``, and ``install-args`` config settings. - Use the system ``ninja`` if possible. Return ``ninja`` as a build dependency otherwise. - Include files generated by ``mesonadd_dist_script`` in the sdist. - Use ``tomllib`` on Python 3.11 or later. - Drop the ``wheel`` package dependency. - Fix bug where the ``entry_points.txt`` file was not generated. - Fix bug where Cygwin Python extensions were not being noticed. Ben Greiner, Daniele Nicolodi, Filipe Laíns, Henry Schreiner, Matthias Köppe, Ralf Gommers, Sam Thursfield, Thomas Li --- 21-11-2022. 0.10.0 ====== - Ignore the minor version on macOS 11 or later, to match the behavior of ``pypa/packaging``. Filipe Laíns, Ralf Gommers --- 05-10-2022. 0.9.0 ===== - More fixes on ABI tag detection. - Fix incorrect tag on 32-bit Python running on a x86_64 host. - Fix sdist permissions. - Fix incorrect PyPy tags. - Fix ``install_subdirs`` not being included in wheels. - Take ``MACOSX_DEPLOYMENT_TARGET`` into account for the platform tag. - Don't set the rpath on binaries if unneeded. Eli Schwartz, Filipe Laíns, Matthias Köppe, Peyton Murray, Ralf Gommers, Thomas Kluyver, Thomas Li --- 29-09-2022. 0.8.1 ===== - Fix ``UnboundLocalError`` in tag detection code. Filipe Laíns, Ralf Gommers --- 28-07-2022. 0.8.0 ===== - Fix sometimes the incorrect ABI tags being generated. - Add workaround for macOS 11 and 12 installations that are missing a minor version in the platform string. Filipe Laíns --- 26-07-2022. 0.7.0 ===== - Fix the wrong Python and ABI tags being generated in Meson 0.63.0. - Fix project license not being included in the project metadata. Filipe Laíns, Ralf Gommers --- 22-07-2022. 0.6.0 ===== - Project re-licensed to MIT. - Error out when running in an unsupported interpreter. - Fix slightly broken Debian heuristics. - Update ``pep621`` dependency to ``pyproject-metadata``. Filipe Laíns, Ralf Gommers, Thomas A Caswell --- 21-06-2022. 0.5.0 ===== - Improvements in dependency detections. - Include uncommited changes in sdists. Filipe Laíns --- 26-05-2022. 0.4.0 ===== - Set sane default arguments for release builds. Filipe Laíns --- 06-05-2022. 0.3.0 ===== - Initial cross-platform support. - Bundling libraries is still only supported on Linux. - Add initial documentation. - The build directory is now located in the project source. Filipe Laíns, Rafael Silva --- 23-03-2022. 0.2.1 ===== - Fix getting the project version dynamically from Meson. Filipe Laíns --- 26-02-2022. 0.2.0 ===== - Select the correct ABI and Python tags. - Force Meson to use the correct Python executable. - Replace auditwheel with in-house vendoring mechanism. Filipe Laíns --- 24-01-2022. 0.1.2 ===== - Fix auditwheel not being run. Filipe Laíns --- 12-11-2021. 0.1.1 ===== - Fix minor compatibility issue with Python < 3.9. Filipe Laíns --- 28-10-2021. 0.1.0 ===== - Initial release. Filipe Laíns --- 28-10-2021. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/LICENSE0000644000000000000000000000220314607715450012261 0ustar00Copyright © 2022 the meson-python contributors Copyright © 2021 Quansight Labs and Filipe Laíns Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/LICENSES/MIT.txt0000644000000000000000000000220314607715450013653 0ustar00Copyright © 2022 the meson-python contributors Copyright © 2021 Quansight Labs and Filipe Laíns Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/README.rst0000644000000000000000000000172214607715450012750 0ustar00.. SPDX-FileCopyrightText: 2021 The meson-python developers .. SPDX-License-Identifier: MIT meson-python ============ ``meson-python`` is a Python build back-end built on top of the Meson__ build system. It enables using Meson for the configuration and build steps of Python packages. Meson is an open source build system meant to be both extremely fast, and, even more importantly, as user friendly as possible. ``meson-python`` is best suited for building Python packages containing extension modules implemented in languages such as C, C++, Cython, Fortran, Pythran, or Rust. Consult the documentation__ for more details. Questions regarding the use of ``meson-python`` can be directed to the discussions__ space on GitHub. Bug reports and feature requests can be filed as GitHub issues__. __ https://mesonbuild.com/ __ https://mesonbuild.com/meson-python/ __ https://github.com/mesonbuild/meson-python/discussions/ __ https://github.com/mesonbuild/meson-python/issues/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/alpine-3.docker0000644000000000000000000000031714607715450014454 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20240305 FROM alpine:3 RUN apk add --no-cache python3-dev py3-pip build-base ninja-is-really-ninja git patchelf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/archlinux.docker0000644000000000000000000000033414607715450015040 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20221203 FROM archlinux:latest RUN pacman -Syu --noconfirm && pacman -S --noconfirm python python-pip gcc ninja git patchelf ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/debian-11.docker0000644000000000000000000000036714607715450014512 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20240204 FROM debian:bullseye RUN apt-get update && apt-get install -y git ninja-build patchelf python3-pip python3-venv && rm -rf /var/lib/apt/lists/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/debian-12.docker0000644000000000000000000000036714607715450014513 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT # 20240204 FROM debian:bookworm RUN apt-get update && apt-get install -y git ninja-build patchelf python3-pip python3-venv && rm -rf /var/lib/apt/lists/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/debian-unstable.docker0000644000000000000000000000036714607715450016106 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20230816 FROM debian:unstable RUN apt-get update && apt-get install -y git ninja-build patchelf python3-pip python3-venv && rm -rf /var/lib/apt/lists/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/fedora-37.docker0000644000000000000000000000034314607715450014532 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20240204 FROM fedora:37 RUN dnf -y update && dnf -y install python3-devel python3-pip gcc ninja-build git patchelf && dnf clean all ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/manylinux.docker0000644000000000000000000000032114607715450015063 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20221209 FROM quay.io/pypa/manylinux_2_28_x86_64 RUN dnf -y update && dnf -y install ninja-build && dnf clean all ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/miniconda.docker0000644000000000000000000000035114607715450015003 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20240204 FROM continuumio/miniconda3 RUN apt-get update && apt-get install -y gcc ninja-build git patchelf && rm -rf /var/lib/apt/lists/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/ci/opensuse-15.docker0000644000000000000000000000044114607715450015126 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # 20230816 FROM opensuse/leap:latest RUN zypper --non-interactive install python311 python311-pip python311-devel gcc ninja git patchelf && zypper clean --all && ln -s python3.11 /usr/bin/python3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/codecov.yml0000644000000000000000000000037614607715450013432 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT comment: false coverage: status: project: default: target: auto threshold: 10% patch: default: informational: true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/about.rst0000644000000000000000000000403714607715450014057 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT License ======= ``meson-python`` is distributed under the terms of the `MIT License`__. ``meson-python`` is tightly coupled to the Meson build system, which is distributed under the the terms of the `Apache License 2.0`__. __ https://github.com/mesonbuild/meson-python/blob/main/LICENSE __ https://github.com/mesonbuild/meson/blob/master/COPYING Maintainers =========== The current maintainers of ``meson-python`` are: - `Ralf Gommers `_ - `Daniele Nicolodi `_ - `Henry Schreiner `_ - `Thomas Li `_ Emeritus maintainers: - `Filipe Laíns `_ Funding ======= Ralf Gommers contributes to the development of ``meson-python`` as part of their job at `Quansight`_. Initial creation of ``meson-python`` by Filipe Laíns was also funded by `Quansight`_. .. _Quansight: https://www.quansight.com/ Packages ======== ``meson-python`` packages are distributed via `PyPI`_ as a source distribution and a single pure Python wheel that works across all supported Python versions. Distributors are recommended to fetch release sources from the corresponding tags on the Git repository_ or from source distributions on `PyPI`_. Git tags are PGP-signed with one of the following keys: - |3DCE51D60930EBA47858BA4146F633CBB0EB4BF2|_ Filipe Laíns - |52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5|_ Ralf Gommers .. _repository: https://github.com/mesonbuild/meson-python .. _PyPI: https://pypi.org/project/meson-python/ .. |3DCE51D60930EBA47858BA4146F633CBB0EB4BF2| replace:: ``3DCE51D60930EBA47858BA4146F633CBB0EB4BF2`` .. _3DCE51D60930EBA47858BA4146F633CBB0EB4BF2: https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3dce51d60930eba47858ba4146f633cbb0eb4bf2 .. |52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5| replace:: ``52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5`` .. _52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5: https://github.com/rgommers.gpg ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1713347710.4643157 meson_python-0.16.0/docs/changelog.rst0000644000000000000000000002672414607716176014711 0ustar00.. SPDX-FileCopyrightText: 2021 The meson-python developers .. .. SPDX-License-Identifier: MIT .. Contributors list for the latest release can be generated with git log --format='%aN' $PREV..HEAD | sort -u | awk '$1=$1' RS='' FS='\n' OFS=', ' +++++++++ Changelog +++++++++ 0.16.0 ====== - Correctly detect a wheel shipping shared libraries as being platform dependent also when it does not ship compiled executables or Python extension modules. - Use 11.0 as minimum macOS platform ABI tag on arm64: lower versions do not exist on arm64. - Improve parsing of the ``$ARCHFLAGS`` environment variable. Correctly handle repeated ``-arch`` flags. - Do not break when trying to log filename containing Unicode characters that cannot be encoded in the encoding used by the standard output stream. - Drop dependency on ``colorama`` on Windows. - Suppress all uses of ANSI terminal escapes when logging to a stream that does not support them. - Fix ANSI escape coloring of error messages. - Respect the ``exclude_dirs`` and ``exclude_files`` arguments passed to the ``install_subdir()`` Meson function in editable installs too. - Make ``pkgutil.iter_packages()`` work properly for modules loaded from editable installs. - Add support for the ``custom_target()`` Meson function installing a directory. - In editable installs, when a rebuild is triggered on module import, emit a message indicating that the package is being rebuilt but suppress any output when there is no work to do. Daniele Nicolodi, Loïc Estève, Ralf Gommers --- 16-04-2024 0.15.0 ====== - Enable compression for wheel files. The may result in several times smaller wheels. - Require Meson 1.2.3 or later on Python 3.12 or later. Meson 1.2.3 does not require anymore ``distutils``, allowing to remove the dependency on ``setuptools`` on Python 3.12 or later. - Unconditionally require ``patchelf`` on Linux. The ``patchelf`` package is added to the build dependencies if a suitable ``patchelf`` executable is not find on the ``$PATH``. This avoids cases where ``meson setup`` was run twice during the build process to determine whether ``patchelf`` is required. - Allow to configure the ``meson`` executable to use for the build process through the ``$MESON`` environment variable or the ``meson`` key under ``[tool.meson-python]`` in ``pyproject.toml``. - Fix wheel platform tag generation on FreeBSD. - Extend support to other UNIX-like systems and make the tests pass on FreeBSD. - Fix package name normalization in package metadata and improve package name validation. - Fix ``RPATH`` handling when the build ``RPATH`` points to subdirectories of the build directory. - Fix support for the Python limited C API when compiling for PyPy. - Rename the ``builddir`` config-setting to ``build-dir``. For backwards compatibility, the ``buildir`` config-setting remains supported as an alias. Christoph Reiter, Daniele Nicolodi, Elliott Sales de Andrade, Ralf Gommers, Yue Yang --- 26-10-2023 0.14.0 ====== - Do not run ``meson install`` to build a wheel. This was unnecessary as files are added to the wheel from the build and source directories. This does not affect the handling of ``meson install`` options, which are interpreted by ``meson-python`` itself. - Obey the ``--skip-subprojects`` when specified for the ``meson install`` command. - Implement support for the ``exclude_directories`` and ``exclude_files`` arguments to Meson ``install_subdir()`` function and similar installation functions. This requires Meson version 1.1.0 or later. - Implement support for building wheels targeting the Python limited API. Extension modules targeting the Python limited API can be easily built starting with the upcoming Meson 1.3.0 release. - When ``pyproject.toml`` does not contain a ``version`` field and ``version`` is not declared dynamic, raise an error instead of silently using the version declared in ``meson.build``. - Fix the mtime of source files in the sdist tarball. - Add ``objc`` and ``objcpp`` compilers to the cross file generated when the ``$ARCHFLAGS`` is set. - Extensive documentation improvements. Charles Brunet, Daniele Nicolodi, Henry Schreiner, Michał Górny, Ralf Gommers --- 05-09-2023 0.13.2 ====== - Fix system name in cross file generated when using ``$ARCHFLAGS``. - Fix handling of ``null`` Meson install tags. Charles Brunet, Daniele Nicolodi --- 22-06-2023. 0.13.1 ====== - Fix regression in cross-compilation via ``$ARCHFLAGS`` on macOS where the cross file was written in the build directory before it was created, resulting in an error. - Do not require setting ``$_PYTHON_HOST_PLATFORM`` when cross-compiling via ``$ARCHFLAGS`` on macOS. - Add the ``--quiet`` option when invoking ``meson install``. The installation paths are a detail of the ``meson-python`` implementation and are generally not interesting for the user. - Fix terminal logging when overriding the current line when listing files added to the wheel. - Improve the error message emitted when a package split between the ``purelib`` and ``platlib`` wheel locations is detected. Daniele Nicolodi, Ralf Gommers --- 28-04-2023. 0.13.0 ====== - Add support for editable installs. - Adjust the default build options passed to ``meson setup``. - Make sure that the directory where the wheel or sdist build artifacts are created exists. Fixes building with PDM. - Fix the specification of the C++ compiler for cross-compilation with ``$ARCHFLAGS`` on macOS. - Pass the ``--reconfigure`` option to ``meson setup`` if and only if the specified build directory exists and is a valid Meson build directory. - Pass the ``--no-rebuild`` option to ``meson install``. - Allow to select the files to be included in the wheel via Meson install tags passing the ``--tags`` option to ``meson install`` via ``pyproject.toml`` or config settings. - Do not use the ``meson compile`` indirection to build the project, except on Windows, where it is required to setup the Visual Studio environment. - Do not add ``ninja`` to the build dependencies if ``$NINJA`` is set but it does not point to a ``ninja`` executable with the required minimum version. - Verify at run time that Meson satisfies the minimum required version. - Place native and cross files in the build directory instead of in the source directory. - Drop the ``typing-extensions`` package dependency. - Add dependency on ``setuptools`` on Python 3.12 and later. This fixes build error due to Meson depending on the ``distutils`` standard library module removed in Python 3.12. - Bump the required ``pyproject-metadata`` version to 0.7.1. - Allows some more cross-compilation setups by not checking extension modules filename suffixes against the suffixes accepted by the current interpreter. - Raise an error when a file that would be installed by Meson cannot be mapped to a wheel location. - Raise an error when a package is split between ``platlib`` and ``purelib``. - Do not generate a warning when ``pyproject.toml`` does not contain a ``project`` section and Python package metadata is derived from ``meson.build``. - Improve reporting of ``pyproject.toml`` validation errors. - Fix validation of tool specific options in ``pyproject.toml``. In particular, allows to specify an incomplete set of options in the ``tool.meson-python.args`` table. Daniele Nicolodi, Doron Behar, Eli Schwartz, Filipe Laíns, Lars Pastewka, Luigi Giugliano, Matthias Köppe, Peter Urban, Ralf Gommers, Stefan van der Walt, Thomas Li --- 18-04-2023. 0.12.1 ====== - Fix regression where the ``$MACOSX_DEPLOYMENT_TARGET`` environment variable was accidentally renamed to ``$MACOS_DEPLOYMENT_TARGET``. Filipe Laíns, Stefan van der Walt --- 17-02-2023. 0.12.0 ====== - Require the ``typing_extensions`` package for Python < 3.10 rather than for Python < 3.8 only. - Emit an error message and raise ``SystemExit`` on expected errors. - Revise error messages for consistency. - Support setuptools-style macOS cross compilation via ``$ARCHFLAGS``. - Allow to overwrite macOS platform tag via ``$_PYTHON_HOST_PLATFORM``. - Include an hint with the most similar known option names in the error message emitted when an unknown config setting is encountered. Daniele Nicolodi, Filipe Laíns, Henry Schreiner, Matthias Köppe, Thomas A Caswell --- 22-12-2022. 0.11.0 ====== - Project moved to the ``mesonbuild`` organization. - Determine wheel tags by introspecting the Python interpreter. - Allow users to pass options directly to Meson via the ``dist``, ``setup``, ``compile``, and ``install`` entries in the ``tools.meson-python.args`` table in ``pyproject.toml``, or via the ``dist-args``, ``setup-args``, ``compile-args``, and ``install-args`` config settings. - Use the system ``ninja`` if possible. Return ``ninja`` as a build dependency otherwise. - Include files generated by ``mesonadd_dist_script`` in the sdist. - Use ``tomllib`` on Python 3.11 or later. - Drop the ``wheel`` package dependency. - Fix bug where the ``entry_points.txt`` file was not generated. - Fix bug where Cygwin Python extensions were not being noticed. Ben Greiner, Daniele Nicolodi, Filipe Laíns, Henry Schreiner, Matthias Köppe, Ralf Gommers, Sam Thursfield, Thomas Li --- 21-11-2022. 0.10.0 ====== - Ignore the minor version on macOS 11 or later, to match the behavior of ``pypa/packaging``. Filipe Laíns, Ralf Gommers --- 05-10-2022. 0.9.0 ===== - More fixes on ABI tag detection. - Fix incorrect tag on 32-bit Python running on a x86_64 host. - Fix sdist permissions. - Fix incorrect PyPy tags. - Fix ``install_subdirs`` not being included in wheels. - Take ``MACOSX_DEPLOYMENT_TARGET`` into account for the platform tag. - Don't set the rpath on binaries if unneeded. Eli Schwartz, Filipe Laíns, Matthias Köppe, Peyton Murray, Ralf Gommers, Thomas Kluyver, Thomas Li --- 29-09-2022. 0.8.1 ===== - Fix ``UnboundLocalError`` in tag detection code. Filipe Laíns, Ralf Gommers --- 28-07-2022. 0.8.0 ===== - Fix sometimes the incorrect ABI tags being generated. - Add workaround for macOS 11 and 12 installations that are missing a minor version in the platform string. Filipe Laíns --- 26-07-2022. 0.7.0 ===== - Fix the wrong Python and ABI tags being generated in Meson 0.63.0. - Fix project license not being included in the project metadata. Filipe Laíns, Ralf Gommers --- 22-07-2022. 0.6.0 ===== - Project re-licensed to MIT. - Error out when running in an unsupported interpreter. - Fix slightly broken Debian heuristics. - Update ``pep621`` dependency to ``pyproject-metadata``. Filipe Laíns, Ralf Gommers, Thomas A Caswell --- 21-06-2022. 0.5.0 ===== - Improvements in dependency detections. - Include uncommited changes in sdists. Filipe Laíns --- 26-05-2022. 0.4.0 ===== - Set sane default arguments for release builds. Filipe Laíns --- 06-05-2022. 0.3.0 ===== - Initial cross-platform support. - Bundling libraries is still only supported on Linux. - Add initial documentation. - The build directory is now located in the project source. Filipe Laíns, Rafael Silva --- 23-03-2022. 0.2.1 ===== - Fix getting the project version dynamically from Meson. Filipe Laíns --- 26-02-2022. 0.2.0 ===== - Select the correct ABI and Python tags. - Force Meson to use the correct Python executable. - Replace auditwheel with in-house vendoring mechanism. Filipe Laíns --- 24-01-2022. 0.1.2 ===== - Fix auditwheel not being run. Filipe Laíns --- 12-11-2021. 0.1.1 ===== - Fix minor compatibility issue with Python < 3.9. Filipe Laíns --- 28-10-2021. 0.1.0 ===== - Initial release. Filipe Laíns --- 28-10-2021. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/conf.py0000644000000000000000000000570014607715450013510 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. import datetime import os import sys sys.path.insert(0, os.path.abspath('..')) import mesonpy # -- Project information ----------------------------------------------------- project = 'meson-python' copyright = f'2021\N{EN DASH}{datetime.date.today().year} The meson-python developers' # The short X.Y version version = mesonpy.__version__ # The full version, including alpha/beta/rc tags release = mesonpy.__version__ # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.todo', 'sphinx_copybutton', 'sphinx_design', 'sphinxext.opengraph', 'sphinx.ext.intersphinx', ] try: import sphinxcontrib.spelling extensions.append('sphinxcontrib.spelling') spelling_show_suggestions = True spelling_warning = True except ImportError: pass # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = [] default_role = 'any' todo_include_todos = True intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'furo' html_title = f'meson-python {version}' html_static_path = ['static'] html_css_files = [ 'css/contributors.css', ] html_theme_options = { 'light_css_variables': { 'font-stack': ( 'system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,' 'Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji' ), }, } # Open Graph ogp_site_url = 'https://mesonbuild.com/meson-python/' ogp_site_name = 'meson-python documentation' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named 'default.css' will overwrite the builtin 'default.css'. # html_static_path = ['_static'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/contributing/index.rst0000644000000000000000000000023314607715450016555 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT Development =========== .. toctree:: release-process ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/contributing/release-process.rst0000644000000000000000000000346614607715450020555 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _contributing-release-process: *************** Release Process *************** All releases are PGP signed with one of the keys listed in the `installation page`_. Before releasing please make sure your PGP key is listed there, and preferably signed by one of the other key holders. If your key is not signed by one of the other key holders, please make sure the PR that added your key to the :doc:`../about` page was approved by at least one other maintainer. After that is done, you may release the project by following these steps: #. Release to the Git repository on GitHub: #. Create the release commit #. Bump the versions in ``meson.build`` and ``mesonpy/__init__.py``. #. Create ``CHANGELOG.rst`` section for the new release and fill it. #. The commit message should read: ``REL: set version to X.Y.Z`` #. Create a GPG-signed tag for the release: .. code-block:: console $ git tag -s X.Y.Z The tag title should follow the ``meson-python X.Y.Z`` format, and the tag body should be a plain text version of the change-log for the current release. #. Push the commit and tag to the repository: .. code-block:: console $ git push $ git push --tags #. Release to `PyPI `_ #. Build the Python artifacts: .. code-block:: console $ python -m build #. Push the artifacts to PyPI: .. code-block:: console $ twine upload dist/* There is no need to GPG-sign the artifacts: PyPI no longer supports uploading GPG signatures. If you have any questions, please look at previous releases and/or ping the other maintainers. .. _installation page: installation ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/examples/spam/meson.build0000644000000000000000000000142714607715450017133 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('spam', 'c', version: '1.0.0') py = import('python').find_installation() # Specify directories to be included - usually this is where your header files live. # Note that specifying the path to Python.h is not necessary with meson-python. includes = include_directories('src') srcs = [ 'src/spammodule.c', ] # If some files (such as .py files) need to be copied to site-packages, # this is where they get specified. Files get copied to # /site-packages/ py.install_sources( 'src/__init__.py', subdir: 'spam', pure: false, ) py.extension_module( '_spam', srcs, install: true, subdir: 'spam', include_directories: includes, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/examples/spam/pyproject.toml0000644000000000000000000000043714607715450017705 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] requires = [ "meson-python", ] build-backend = "mesonpy" [project] name = "spam" description = "Example C extension for Python" version = "0.0.1" requires-python = ">=3.8.0" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/examples/spam/src/__init__.py0000644000000000000000000000020214607715450017657 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from ._spam import add # noqa: F401 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/examples/spam/src/spammodule.c0000644000000000000000000000116514607715450020071 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #define PY_SSIZE_T_CLEAN #include static PyObject * add(PyObject *self, PyObject *args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) return NULL; return PyLong_FromLong(a + b); } static PyMethodDef methods[] = { {"add", add, METH_VARARGS, "Add two integers."}, {NULL, NULL, 0, NULL} }; static struct PyModuleDef spammodule = { PyModuleDef_HEAD_INIT, "spam", NULL, -1, methods }; PyMODINIT_FUNC PyInit__spam(void) { return PyModule_Create(&spammodule); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/explanations/default-options.rst0000644000000000000000000000777714607715450020605 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _explanations-default-options: ********************* Default build options ********************* Meson offers many `built-in options`__ to control how the project is built and installed. In the vast majority of cases those have good defaults. There are however a few options that ``meson-python`` overrides with its own defaults to adjust the build process to the task of building Python wheels. The default options specified by ``meson-python`` are overridden by package specific options specified in ``pyproject.toml`` and by options provided by the user at build time via the Python build front-end. Refer to the :ref:`how-to-guides-meson-args` guide for details. The options used to build the project are summarized in the *User defined options* section of the output of the ``meson setup`` stage of the build, for example when running ``python -m build -w``. This will look something like: __ https://mesonbuild.com/Builtin-options.html .. code-block:: text User defined options Native files: $builddir/meson-python-native-file.ini buildtype : release b_ndebug : if-release b_vscrt : md where the path to the build directory has been replaced with ``$builddir`` for clarity. The options that ``meson-python`` specifies by default are: .. option:: native-file=$builddir/meson-python-native-file.ini ``meson-python`` uses a native file to point Meson at the ``python`` interpreter that the build must target. This is the Python interpreter that is used to run the Python build front-end. Meson would otherwise look for the first Python interpreter on the ``$PATH``, which may not be the same. Additional ``--native-file`` options can be passed to ``meson setup`` if further adjustments to the native environment need to be made. Meson will merge the contents of all machine files. To ensure everything works as expected, the ``meson-python`` native file is last in the command line, overriding the ``python`` binary path that may have been specified in user supplied native files. .. option:: buildtype=release The Meson default is to produce a debug build with binaries compiled with debug symbols and, when compiling with MSVC, linking to the Visual Studio debug runtime, see below. The main purpose of ``meson-python`` is to build release artifacts, therefore a more appropriate `build type`__ is selected. A release build is compiled without debug symbols and with compiler optimizations. Refer to the `Meson documentation`__ for more details. __ https://mesonbuild.com/Builtin-options.html#details-for-buildtype __ https://mesonbuild.com/Builtin-options.html#core-options .. option:: b_ndebug=if-release For reasons related to backward compatibility, Meson does not disable assertions for release builds. For most users this is a surprising and undesired behavior. This option instructs Meson to pass the ``-DNDEBUG`` option to the compilers, unless the build type is set to something else than release. .. option:: b_vscrt=md With the default options, when compiling a debug build, Meson instructs the MSVC compiler to use the debug version of the Visual Studio runtime library. This causes the MSVC linker to look for the debug build of all the linked DLLs. The Python distribution for Windows does not contain a debug version of the Python DLL and linking fails. These linking failures are surprising and hard to diagnose. To avoid this issue when users explicitly asks for a debug build, ``meson-python`` sets this options to instruct Meson to compile with the release version of the Visual Studio runtime. For more details, refer to the `Meson documentation`__ and to the `Visual Studio documentation`__ . This option is ignored when other compilers are used. __ https://mesonbuild.com/Builtin-options.html#base-options __ https://learn.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=msvc-170 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/explanations/design-old.rst0000644000000000000000000000726114607715450017501 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT :orphan: .. _explanations-design-old: ******************************* How does ``meson-python`` work? ******************************* .. admonition:: Old documentation :class: attention You are looking at the old documentation. We are currently in the process of refactoring the whole documentation and this page was part of the old version. While it still contains lots of relevant information, it is not necessarily in the format we ultimately want to present, and is not well integrated with the other parts of the documentation. How does it work? ================= We implement the Python build system hooks, enabling any standards compliant Python tool (pip_, `pypa/build`_, etc.) to build and install the project. ``meson-python`` will build a Python sdist (source distribution) or wheel (binary distribution) from Meson_ project. Source distribution (sdist) --------------------------- The source distribution is based on ``meson dist``, so make sure all your files are included there. In git projects, Meson_ will not include files that are not checked into git, keep that in mind when developing. By default, all files under version control will be included in the sdist. In order to exclude files, use ``export-ignore`` or ``export-subst`` attributes in ``.gitattributes`` (see the ``git-archive`` documentation for details; ``meson dist`` uses ``git-archive`` under the hood). Local (uncommitted) changes to files that are under version control will be included. This is often needed when applying patches, e.g. for build issues found during packaging, to work around test failures, to amend the license for vendored components in wheels, etc. Binary distribution (wheels) ---------------------------- The binary distribution is built by running Meson_ and introspecting the build and trying to map the files to their correct location. Due to some limitations and/or bugs in Meson_, we might not be able to map some of the files with certainty. In these cases, we will take the safest approach and warn the user. In some cases, we might need to resort to heuristics to perform the mapping, similarly, the user will be warned. These warnings are not necessarily a reason for concern, they are there to help identifying issues. In these cases, we recommend that you check if the files in question were indeed mapped to the expected place, and open a bug report if they weren't. If the project itself includes shared libraries that are needed by other files, those libraries will be included in the wheel, and native files will have their library search path extended to include the directory where the libraries are placed. If the project depends on external shared libraries, those libraries will not be included in the wheel. This can be handled in several ways by the package developer using ``meson-python``: 1. Finding or creating a suitable Python package that provides those shared libraries and can be added to ``dependencies`` in ``pyproject.toml``. 2. Vendoring those libraries into the wheel. Currently ``meson-python`` does not provide an OS-agnostic way of doing that; on Linux ``auditwheel`` can be used, and on macOS ``delocate``. Or, the package developer can copy the shared libraries into the source tree and patch ``meson.build`` files to include them. 3. Documenting that the dependency is assumed to already be installed on the end user's system, and letting the end user install it themselves (e.g., through their Linux distro package manager). .. _pip: https://github.com/pypa/pip .. _pypa/build: https://github.com/pypa/build .. _Meson: https://github.com/mesonbuild/meson ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/how-to-guides/config-settings.rst0000644000000000000000000000371614607715450020546 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-config-settings: *************************** Using build config settings *************************** Build config settings can be used to customize some aspects of the build. See the :doc:`../reference/config-settings` reference for a list of the settings implemented by ``meson-python``. How build config settings are specified depends on the Python package build front-end used. The most popular build front-end are `build`_ and `pip`_. These use the ``--config-settings`` long command line option or the ``-C`` short command line option: .. tab-set:: .. tab-item:: pypa/buid :sync: key_pypa_build .. code-block:: console $ python -m build \ -Csetup-args="-Doption=true" \ -Csetup-args="-Dvalue=1" \ -Ccompile-args="-j6" .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel . \ --config-settings=setup-args="-Doption=disable" \ --config-settings=compile-args="-j6" Refer to the `build`_ and `pip`_ documentation for details. This example uses the ``python -m pip wheel`` command to build a Python wheel that can be later installed or distributed. To build a package and immediately install it, replace ``wheel`` with ``install``. See the :ref:`how-to-guides-meson-args` guide for more examples. .. admonition:: Passing multiple settings :class: caution Please note that ``pip`` prior to 23.1 did not offer a way to set a build config setting to a list of strings: later values for the same key passed to ``--config-settings`` override earlier ones, effectively limiting the number of options that can be passed to each command invoked in the build process to one. This limitation has been lifted in ``pip`` release 23.1. .. _build: https://pypa-build.readthedocs.io/en/stable/ .. _pip: https://pip.pypa.io/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/how-to-guides/debug-builds.rst0000644000000000000000000000423014607715450020001 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-debug-builds: ****************** Using debug builds ****************** For development work on native code in your Python package, you may want to use a debug build. To do so, we need to pass the ``-Dbuildtype=debug`` option, which is equivalent to ``-Ddebug=true -Doptimization=0``, to ``meson setup``. In addition, it is likely most useful to set up an editable build with a fixed build directory. That way, the shared libraries in the installed debug build will contain correct paths, rather than paths pointing to a temporary build directory which ``meson-python`` will otherwise use. IDEs and other tools will then be able to show correct file locations and line numbers during debugging. We can do all that with the following ``pip`` invocation: .. code-block:: console $ pip install -e . --no-build-isolation \ -Csetup-args=-Dbuildtype=debug \ -Cbuild-dir=build-dbg This debug build of your package will work with either a regular or debug build of your Python interpreter. A debug Python interpreter isn't necessary, but may be useful. It can be built from source, or you may be able to get it from your package manager of choice (typically under a package name like ``python-dbg``). Note that using a debug Python interpreter does not yield a debug build of your own package - you must use ``-Dbuildtype=debug`` or an equivalent flag for that. .. warning:: Inside a Conda environment, environment variables like ``CFLAGS`` and ``CXXFLAGS`` are usually set when the environment is activated. These environment variables contain optimization flags like ``-O2``, which will override the optimization level implied by ``-Dbuildtype=debug``. In order to avoid this, unset these variables: .. code-block:: console $ unset CFLAGS $ unset CXXFLAGS Finally, note changing the buildtype from its default value of ``release`` to ``debug`` will also cause ``meson-python`` to enable (or better, not disable) assertions by not defining the ``NDEBUG`` macro (see ``b_ndebug`` under :ref:`explanations-default-options`). ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/how-to-guides/editable-installs.rst0000644000000000000000000001232614607715450021040 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-editable-installs: ***************** Editable installs ***************** Editable installs are a Python package installation mode designed to facilitate package development. When a package is installed in editable mode, edits to the project source code become effective without the need of a new installation step. Editable installs are a build backend independent formalization__ of the *development mode* introduced by setuptools__. __ https://peps.python.org/pep-0660/ __ https://setuptools.pypa.io/en/latest/userguide/development_mode.html While most Python build backends apply development mode or editable installs to the pure Python components, ``meson-python`` extends editable installs to package components that require a compilation step such as extension modules. To install a package in editable mode, pass the ``--editable`` or ``-e`` option to ``pip install``. The editable installation mode implies that the source code of the project being installed is available in a local directory. To install the project in the current directory in editable mode install the project's build dependencies in your development environment and run .. code-block:: console $ python -m pip install --no-build-isolation --editable . This will install a stub in the Python site packages directory that loads the package content from the sources and build directory. The same stub is responsible to rebuild the compiled parts of the package when the package is imported the first time in a given Python interpreter instance. Because of the very fast partial rebuilds allowed by Meson and ``ninja``, the rebuild has an almost negligible impact on the import times. Please note that some kind of changes, such as the addition or modification of `entry points`__, or the addition of new dependencies, and generally all changes involving package metadata, require a new installation step to become effective. __ https://packaging.python.org/en/latest/specifications/entry-points/ An editable install exposes at least all the files that would be available in a regular installation. However, depending on the file and directory organization in your project, it might also expose files that would not be normally available. Build dependencies ------------------ Because packages installed in editable mode are rebuilt on import, all build dependencies need to available at execution time in the development environment. By default, pip builds packages in a isolated environment where build dependencies are installed without affecting the user environment. Packages installed in editable mode using build isolation will fail to rebuild when imported, unless build dependencies are also installed in the development environment. Furthermore, when build using build isolation, a package that depends on headers or other resources provided by its build dependencies, would resolve the path to these in the isolated build environment. The isolated build environment is deleted after the build is completed, resulting in failures when the package in rebuild on import. For these reasons, when installing packages in editable mode, it is recommended to disable build isolation passing the ``--no-build-isolation`` argument to pip. At the time of writing, pip does not offer a command to install a the build dependencies for a package. The build dependencies requirements can be obtained inspecting ``pyproject.toml`` for the package to be installed. These include at least the ``meson-python`` Python package, and the ``meson`` and ``ninja`` Python packages, if the respective commands are not provided by the system, or if they are not the required version: .. code-block:: console $ python -m pip install meson-python meson ninja Build directory --------------- Because the compiled components of the package are loaded directly from the build directory, the build directory needs to be available alongside the source directory at execution time. When building a package in editable mode, ``meson-python`` uses a build directory named as the wheel ABI tag associated to the interpreter for which the package is being build. The build directory is placed in a directory named ``build`` inside the source tree. For example, an editable installation for CPython 3.11 will be associated to a ``build/cp311/`` build directory. This directory structure allows to install the same project in editable mode for multiple interpreters with different ABIs. An alternative build directory can be specified using the :option:`build-dir` config setting. .. _how-to-guides-editable-installs-verbose: Verbose mode ------------ Because editable installation are mostly a package development aid, it might be often useful to be able to inspect the compilation log. Setting the :envvar:`MESONPY_EDITABLE_VERBOSE` environment variable will result in the output of the build process to be emitted when a package is rebuilt on import. To enable this verbose mode permanently for a package, the :option:`editable-verbose` config setting can be set to a non-null value when installing the package: .. code-block:: console $ python -m pip install --no-build-isolation --config-settings=editable-verbose=true --editable . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/how-to-guides/meson-args.rst0000644000000000000000000001467214607715450017521 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-meson-args: ************************** Passing arguments to Meson ************************** ``meson-python`` invokes the ``meson setup``, ``ninja``, and ``meson install`` commands to build the files that will be included in the Python wheel, and ``meson dist`` to collect the files that will be included in the Python sdist. Arguments can be passed to these commands to modify their behavior. Refer to the `Meson documentation`_ and to the `ninja documentation`_ for details. .. _Meson documentation: https://mesonbuild.com/Commands.html .. _ninja documentation: https://ninja-build.org/manual.html#_running_ninja Command line arguments for ``meson`` and ``ninja`` can be specified via tool specific settings in ``pyproject.toml`` as lists of strings for the ``setup``, ``compile``, ``install``, and ``dist`` keys in the ``tool.meson-python.args`` table. For example: .. code-block:: toml [tool.meson-python.args] setup = ['-Doption=false', '-Dfeature=enabled', '-Dvalue=42'] compile = ['-j4'] install = ['--tags=bindings'] dist = ['--include-subprojects'] Or can be specified via configuration settings passed by the Python build front-end as ``setup-args``, ``compile-args``, ``install-args``, and ``dist-args`` :ref:`config settings `. Configuration settings specified via the Python build front-end have precedence over, and can be used to override, the ones specified in ``pyproject.toml``. ``meson-python`` overrides some of the default Meson options with :ref:`settings ` more appropriate for building a Python wheel. User options specified via ``pyproject.toml`` or via Python build front-end config settings override the ``meson-python`` defaults. When building on Windows, ``meson-python`` invokes the ``ninja`` command via the ``meson compile`` wrapper. When the GCC or the LLVM compilers are not found on the ``$PATH``, this activates the Visual Studio environment and allows ``ninja`` to use the MSVC compilers. To activate the Visual Studio environment unconditionally, pass the ``--vsenv`` option to ``meson setup``, see this :ref:`example `. When using the ``meson compile`` wrapper, the user supplied options for the compilation command are passed via the ``--ninja-args`` option. This ensures that the behaviour is independent of how the build is initiated. Refer to the `Meson documentation`__ for more details. __ https://mesonbuild.com/Commands.html#backend-specific-arguments Examples ======== Set the default libraries to static ----------------------------------- Set the default library type to static when building a binary wheel. To set this option permanently in the project's ``pyproject.toml``: .. code-block:: toml [tool.meson-python.args] setup = ['--default-library=static'] To set this option temporarily at build-time: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build -Csetup-args="--default-library=static" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel --config-settings=setup-args="--default-library=static" . Select the build targets to include in the wheel ------------------------------------------------ It is possible to include in the Python wheel only a subset of the installable files using Meson `installation tags`_ via the ``meson install``'s ``--tags`` command line option. When ``--tags`` is specified, only files that have one of the specified the tags are going to be installed. Meson sets predefined tags on some files. Custom installation tags can be set using the ``install_tag`` keyword argument passed to the target definition function. In this example only targets tagged with ``runtime`` or ``python-runtime`` are included in the Python wheel. .. _installation tags: https://mesonbuild.com/Installing.html#installation-tags To set this option permanently in the project's ``pyproject.toml``: .. code-block:: toml [tool.meson-python.args] install = ['--tags=runtime,python-runtime'] To set this option temporarily at build-time: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build -Cinstall-args="--tags=runtime,python-runtime" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel --config-settings=install-args="--tags=runtime,python-runtime" . Set the build optimization level -------------------------------- The default compile optimization level when building a binary wheel is currently set to 2. This can be overwritten by passing the ``-Doptimization`` argument to the ``meson setup`` command. To set this option permanently in the project's ``pyproject.toml``: .. code-block:: toml [tool.meson-python.args] setup = ['-Doptimization=3'] To set this option temporarily at build-time: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build -Csetup-args="-Doptimization=3" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel --config-settings=setup-args="-Doptimization=3" . .. _vsenv-example: Force the use of the MSVC compilers on Windows ---------------------------------------------- The MSVC compilers are not installed in the ``$PATH``. The Visual Studio environment needs to be activated for ``ninja`` to be able to use these compilers. This is taken care of by ``meson compile`` but only when the GCC compilers or the LLVM compilers are not found on the ``$PATH``. Passing the ``--vsenv`` option to ``meson setup`` forces the activation of the Visual Studio environment and generates an error when the activation fails. This option has no effect on other platforms thus, if your project requires to be compiled with MSVC, you can consider to set this option permanently in the project's ``pyproject.toml``: .. code-block:: toml [tool.meson-python.args] setup = ['--vsenv'] To set this option temporarily at build-time: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build -Csetup-args="--vsenv" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel --config-settings=setup-args="--vsenv" . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/index.rst0000644000000000000000000000671114607715450014055 0ustar00.. SPDX-FileCopyrightText: 2022 The meson-python developers .. .. SPDX-License-Identifier: MIT :hide-toc: ************ meson-python ************ .. highlights:: A Python package build backend leveraging the Meson build system. ``meson-python`` implement the Python build system hooks, enabling Python build front-ends such as ``pip`` and ``build`` to build and install Python packages based on a Meson_ build definition. Meson is characterized by build definitions written in a very readable domain-specific language and extremely fast builds. Meson support for Windows, macOS, Linux, and other UNIX-like operative systems, and for all the major compiler tool-chains. It allows to compile and link together code written in many programming languages, including C, C++, Cython, D, Fortran, Objective C, and Rust. It has built-in multi-platform dependency provider that works well with distribution packages, and the capability to build dependencies as sub-projects. If you are not familiar with Meson, we recommend checking the `Meson tutorial`_. ``meson-python`` inherits the strengths of Meson and is thus best suited for Python packages building extension modules in compiled languages. ``meson-python`` is suitable for small packages as well as very complex ones, see our :ref:`projects-using-meson-python` directory. To enable ``pip`` or ``build`` to build a Python source distribution (*sdist*) or a binary Python package (*wheel*) for a Meson project, it is sufficient to add to the root of the source tree next to the top-level ``meson.build`` a ``pyproject.toml`` file specifying ``meson-python`` as the Python build backend: .. code-block:: toml [build-system] build-backend = 'mesonpy' requires = ['meson-python'] The package name and version are extracted from the metadata provided to Meson via the ``project()`` function in the ``meson.build`` file. Package metadata can be overridden and extended using the standard package metadata format in the ``project`` section of ``pyproject.toml``: .. code-block:: toml [project] name = 'example' version = '1.0.0' description = 'Example package using the meson-python build backend' readme = 'README.rst' license = {file = 'LICENSE.txt'} authors = [ {name = 'Au Thor', email = 'author@example.com'}, ] [project.scripts] example = 'example.cli:main' Please refer to the `PyPA documentation`_ for detailed documentation about the ``pyproject.toml`` file. Please refer to our :ref:`tutorial` for guidance about the use of ``meson-python`` and Meson for Python packaging. .. _Meson: https://mesonbuild.com/ .. _PyPA documentation: https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ .. _Meson tutorial: https://mesonbuild.com/Tutorial.html .. toctree:: :hidden: tutorials/introduction how-to-guides/editable-installs how-to-guides/config-settings how-to-guides/meson-args how-to-guides/debug-builds reference/limitations projects-using-meson-python .. toctree:: :caption: Reference :hidden: reference/config-settings reference/pyproject-settings reference/environment-variables explanations/default-options reference/meson-compatibility .. toctree:: :caption: Project :hidden: changelog about contributing/index Discussions Source Code Issue Tracker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/projects-using-meson-python.rst0000644000000000000000000000216314607715450020355 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _projects-using-meson-python: ******** Examples ******** The following project use ``meson-python`` for their build system known to be adhering to best practices :`SciPy `_: Probably the most complex project using Meson and ``meson-python``. It combines CPython extensions and libraries written in C, C++, Fortran, Cython_, and Pythran_. :`scikit-image `_: Another complex project using ``meson-python``. :`siphash24 `_: A very simple project. It demonstrates how Meson makes it trivial to compile a CPython extension written in `Cython`_ via a simple template engine and link it to a library compiled from a Meson subproject. Also an example of how to use `cibuildwheel`_ to produce Python wheels for several platforms. .. _Cython: https://github.com/cython/cython .. _Pythran: https://github.com/serge-sans-paille/pythran .. _cibuildwheel: https://github.com/pypa/cibuildwheel ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/reference/config-settings.rst0000644000000000000000000000323214607715450020002 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-config-settings: ********************* Build config settings ********************* This page lists the build configuration settings, that is, the settings you can pass when building the project. Please refer to the :ref:`how-to-guides-config-settings` and :ref:`how-to-guides-meson-args` guides for information on how to use them. .. option:: build-dir By default ``meson-python`` uses a temporary build directory. This settings allows to select the Meson build directory and prevents it to be deleted when ``meson-python`` terminates. If the directory does not exists, it will be created. If the directory exists and contains a valid Meson build directory setup, the project will be reconfigured using ``meson setup --reconfigure``. The same build directory can be used by subsequent invocations of ``meson-python``. This avoids having to rebuild the whole project when testing changes during development. For backward compatibility reasons, the alternative ``builddir`` spelling is also accepted. .. option:: dist-args Extra arguments to be passed to the ``meson dist`` command. .. option:: setup-args Extra arguments to be passed to the ``meson setup`` command. .. option:: compile-args Extra arguments to be passed to the ``ninja`` command. .. option:: install-args Extra arguments to be passed to the ``meson install`` command. .. option:: editable-verbose Enable :ref:`verbose mode ` when building for an :ref:`editable install `. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/reference/environment-variables.rst0000644000000000000000000001173314607715450021216 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-environment-variables: ********************* Environment variables ********************* Environment variables can be used to influence ``meson-python``'s behavior, as well as the behavior of Meson and other tools that may be used during the build. This page lists all the environment variables directly used by ``meson-python``. Meson recommends using command line arguments instead of environment variables, but does support a number of environment variables for compatibility with other build systems: - `Compiler and linker flag variables `__ - `Compiler and linker selection variables `__ Other environment variables may influence how other tools used during the setup or build steps operate. For example, ``pkg-config`` supports ``PKG_CONFIG_PATH`` which influences the search path for ``.pc`` files describing the available dependencies. .. warning:: Conda sets a number of environment variables during environment activation for compiler/linker selection (``CC``, ``CXX``, ``FC``, ``LD``) and compile/link flags (``CFLAGS``, ``CXXFLAGS``, ``FFLAGS``, ``LDFLAGS``) when compilers are installed in a conda environment. This may have unexpected side effects (see for example the note in :ref:`how-to-guides-debug-builds`). Environment variables used by meson-python ========================================== .. envvar:: ARCHFLAGS This environmental variable is used for supporting architecture cross compilation on macOS in a way compatible with setuptools_. It is ignored on all other platforms. It can be set to ``-arch arm64`` or to ``-arch x86_64`` for compiling for the arm64 and the x86_64 architectures respectively. Setting this environment variable to any other value is not supported. The macOS toolchain allows architecture cross compilation passing the ``-arch`` flat to the compilers. ``meson-python`` inspects the content of this environment variable and synthesizes a Meson `cross build definition file`_ with the appropriate content, and passes it to ``meson setup`` via the ``--cross-file`` option. Support for this environment variable is maintained only for compatibility with existing tools, cibuildwheel_ in particular, and is not the recommended solution for cross compilation. .. _setuptools: https://setuptools.pypa.io/en/latest/setuptools.html .. _cross build definition file: https://mesonbuild.com/Cross-compilation.html .. _cibuildwheel: https://cibuildwheel.readthedocs.io/en/stable/ .. envvar:: FORCE_COLOR Setting this environment variable to any value forces the use of ANSI escape sequences to colorize the ``meson-python``'s console output. Setting both ``NO_COLOR`` and ``FORCE_COLOR`` environment variables is an error. .. envvar:: MACOSX_DEPLOYMENT_TARGET This environment variables is used of specifying the target macOS platform major version to the Xcode development tools. If this environment variable is set, ``meson-python`` will use the specified macOS version for the Python wheel platform tag instead than the macOS version of the build machine. This variable must be set to macOS major versions only: ``10.9`` to ``10.15``, ``11``, ``12``, ``13``, ... Please note that the macOS versioning changed from macOS 11 onward. For macOS 10, the versioning scheme is ``10.$major.$minor``. From macOS 11 onward, it is ``$major.$minor.$bugfix``. Wheel tags and deployment targets are currently designed to specify compatibility only with major version number granularity. Another way of specifying the target macOS platform is to use the ``-mmacosx-version-min`` compile and link flags. However, it is not possible for ``meson-python`` to detect this, and it will not set the Python wheel platform tag accordingly. .. envvar:: MESON Specifies the ``meson`` executable or script to use. It overrides ``tool.meson-python.meson``. See :ref:`reference-pyproject-settings` for more details. .. envvar:: MESONPY_EDITABLE_VERBOSE Setting this environment variable to any value enables directing to the console the messages emitted during project rebuild triggered by imports of editable wheels generated by ``meson-python``. Refer to the :ref:`how-to-guides-editable-installs` guide for more information. .. envvar:: NINJA Specifies the ninja_ executable to use. It can also be used to select ninja_ alternatives like samurai_. .. _ninja: https://ninja-build.org .. _samurai: https://github.com/michaelforney/samurai .. envvar:: NO_COLOR Setting this environment variable to any value disables the use of ANSI terminal escape sequences to colorize ``meson-python``'s console output. Setting both ``NO_COLOR`` and ``FORCE_COLOR`` environment variables is an error. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/reference/limitations.rst0000644000000000000000000000311714607715450017235 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-limitations: *********** Limitations *********** Non-package data files ====================== It is possible to encapsulate arbitrary data files into Python wheels. ``meson-python`` will add to the wheel any data file installed into the Meson's ``{datadir}`` location, for example via Meson's |install_data()|_ function. However, when the resulting wheel is installed, these files are unpacked into a platform-specific location and there is no supported facility to reliably find them at run time. It is recommended to include data files than need to be accessible at run-time inside the package alongside the Python code, and use :mod:`importlib.resources` (or the `importlib-resources`_ backport) to access them. Shared libraries on Windows =========================== On Windows, ``meson-python`` cannot encapsulate shared libraries installed as part of the Meson project into the Python wheel for Python extension modules or executables, in a way suitable for them to be found at run-time. This limitation can be overcome with static linking or using `delvewheel`_ to post-process the Python wheel to bundle the required shared libraries and include the setup code to properly set the library search path. .. _install_data(): https://mesonbuild.com/Reference-manual_functions.html#install_data .. _importlib-resources: https://importlib-resources.readthedocs.io/en/latest/index.html .. _delvewheel: https://github.com/adang1345/delvewheel .. |install_data()| replace:: ``install_data()`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/reference/meson-compatibility.rst0000644000000000000000000000360714607715450020675 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _meson-compatibility: ******************* Meson compatibility ******************* ``meson-python`` tightly integrates with Meson to produce Python wheels and sdists. Therefore, correct operation depends on functionality implemented by Meson. ``meson-python`` strives to maintain compatibility with as old as possible Meson releases. However, some functionality is available only with more recent Meson versions. .. option:: 0.63.3 Meson is 0.63.3 is the minimum required version. .. option:: 1.1.0 Meson 1.1.0 or later is required to support the ``exclude_files`` and ``exclude_directories`` arguments to Meson ``install_subdir()`` and similar installation functions. On older Meson versions, these arguments have no effect. .. option:: 1.2.3 Meson 1.2.3 or later is required to support Python 3.12 or later. Since version 1.2.3, Meson does not rely anymore on the ``distutils`` module, which was removed from the standard library in Python 3.12. When installed on Python 3.12, ``meson-python`` depends on Meson 1.2.3 or later. .. option:: 1.3.0 Meson 1.3.0 or later is required for compiling extension modules targeting the Python limited API. Build front-ends by default build packages in an isolated Python environment where build dependencies are installed. Most often, unless a package or its build dependencies declare explicitly a version constraint, this results in the most recent version of the build dependencies to be installed. However, if a package uses functionalities implemented only in combination with a specific Meson version, it is recommended to explicitly declare a version requirement in ``pyproject.toml``. For example: .. code-block:: toml [build-system] build-backend = 'mesonpy' requires = [ 'meson-python', 'meson >= 1.1.0', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/reference/pyproject-settings.rst0000644000000000000000000000373314607715450020562 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _reference-pyproject-settings: **************** Project settings **************** This page lists the configuration settings supported by ``meson-python`` in the ``pyproject.toml`` file. Please refer to the :ref:`how-to-guides-meson-args` guide for for information on how to use them and examples. .. option:: tool.meson-python.limited-api A boolean indicating whether the extension modules contained in the Python package target the `Python limited API`__. Extension modules can be compiled for the Python limited API specifying the ``limited_api`` argument to the |extension_module()|__ function in the Meson Python module. When this setting is set to true, the value ``abi3`` is used for the Python wheel filename ABI tag. This setting is automatically reverted to false when the ``-Dpython.allow_limited_api=false`` option is passed to ``meson setup``. .. option:: tool.meson-python.meson A string specifying the ``meson`` executable or script to use. If it is a path to an existing file with a name ending in ``.py``, it will be invoked as a Python script using the same Python interpreter that is used to run ``meson-python`` itself. It can be overridden by the :envvar:`MESON` environment variable. .. option:: tool.meson-python.args.dist Extra arguments to be passed to the ``meson dist`` command. .. option:: tool.meson-python.args.setup Extra arguments to be passed to the ``meson setup`` command. .. option:: tool.meson-python.args.compile Extra arguments to be passed to the ``ninja`` command. .. option:: tool.meson-python.args.install Extra arguments to be passed to the ``meson install`` command. __ https://docs.python.org/3/c-api/stable.html?highlight=limited%20api#stable-application-binary-interface __ https://mesonbuild.com/Python-module.html#extension_module .. |extension_module()| replace:: ``extension_module()`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/spelling_wordlist.txt0000644000000000000000000000033014607715450016510 0ustar00auditwheel backend backends backport config CPython Cygwin distro eg executables frontend Github macOS nox Numpy pre pluggy pypa pyproject pytest rpath sdist sdists setuptools todo toml uncommited vendored vendoring ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/spelling_wordlist.txt.license0000644000000000000000000000013414607715450020133 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/static/css/contributors.css0000644000000000000000000000105514607715450017536 0ustar00/* * SPDX-FileCopyrightText: 2023 The meson-python developers * * SPDX-License-Identifier: MIT */ .sphinx-contributors--avatars .sphinx-contributors_contributor__image { border-radius: 50%; max-width: 80px; margin: auto; } .sphinx-contributors--avatars .sphinx-contributors_contributor__username { font-size: 80%; text-align: center; } .sphinx-contributors--avatars .sphinx-contributors_contributor { flex-grow: 1; } .sphinx-contributors--avatars .sphinx-contributors_list { justify-content: flex-start; gap: 10px; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/docs/tutorials/introduction.rst0000644000000000000000000002254614607715450017521 0ustar00.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _tutorial: ******** Tutorial ******** If you are new to Python packaging, don't worry! We will give you a quick introduction to what steps releasing a Python package consists of, and walk you through them to get started. Creating a Meson project ======================== To get started, we need a project to publish. As ``meson-python`` is built on top of Meson_, we will create a really simple Meson project. You may already have a Meson project you wish to publish, in that case, you can simply skip this step. The module ---------- First, we create a simple Python module. We will go for a native module, as that's really where ``meson-python`` shines against other Python build backends. .. code-block:: c :caption: our_first_module.c #include static PyObject* foo(PyObject* self) { return PyUnicode_FromString("bar"); } static PyMethodDef methods[] = { {"foo", (PyCFunction)foo, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "our_first_module", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_our_first_module(void) { return PyModule_Create(&module); } Here, we have a create a small module named ``our_first_module``, which has a function ``foo`` that simply returns ``"bar"``. .. admonition:: Using the C API :class: seealso If you need help writing a native module using Python's C API, we recommend checking out the following resources. - `The official Python C API documentation `_ - `RealPython's "Building a Python C Extension Module" introductory tutorial `_ - `pysheeet's "C Extensions" page `_ - `pysheeet-kr's "Python C API cheatsheet" page `_ The Meson build description --------------------------- Now, we need to create the Meson build description file. This tells Meson what we want it to build, and how to do it. .. code-block:: meson :caption: meson.build project('purelib-and-platlib', 'c') py = import('python').find_installation(pure: false) py.extension_module( 'our_first_module', 'our_first_module.c', install: true, ) Here, we use Meson's `Python module`_ to build our ``our_first_module`` module. We make sure to install it, by passing ``install: true`` to ``extension_module``, as ``meson-python`` will only include in the binary distribution artifacts targets that Meson would install onto system. Having non installed targets allows you to build targets for use within the build, or for tests. Configuring our Python package ============================== Now, we need to tell Python packaging tooling what build backend to use to build our package. We do this by creating a ``build-system`` section in the ``pyproject.toml`` file, which is the file used to configure Python packaging tooling. Inside the ``build-system`` section, we need to define two keys, ``build-backend`` and ``requires``. ``build-backend`` defines which build backend should be used for the project - set it to ``'mesonpy'`` to use ``meson-python``. ``requires`` lets us specify which packages need to be installed for the build process, it should include ``meson-python`` and any other dependencies you might need (e.g., ``Cython``). .. code-block:: toml :caption: pyproject.toml [build-system] build-backend = 'mesonpy' requires = ['meson-python'] After we specify which backend to use, we'll want to define the package metadata. This is done in the ``project`` section, and the format is pretty self-explanatory: .. code-block:: toml :caption: pyproject.toml ... [project] name = 'our-first-project' version = '0.0.1' description = 'Our first Python project, using meson-python!' readme = 'README.md' requires-python = '>=3.8' license = {file = 'LICENSE.txt'} authors = [ {name = 'Bowsette Koopa', email = 'bowsette@example.com'}, ] .. admonition:: Declaring project metadata :class: seealso Our example doesn't make use of all the fields available in the ``[project]`` section. Check out the `PyPA documentation on project metadata`_ for more examples and details. Testing the project ------------------- Now we should have a valid Python project, so let's test it. We will install it with pip_: .. code-block:: console $ pip install . $ pip list ... our-first-project 0.0.1 ... After this, we should be able to import and try out our module. .. code-block:: console $ python >>> import our_first_module >>> our_first_module.foo() 'bar' Creating your first release =========================== Now that we have a valid Python project, we can release it. To release the project we first need to generate the distribution artifacts, these are files in a standardized format that Python package installers understand. There are two kind of artifacts, `source distributions`_, which are commonly referred to as *sdists*, and `binary distributions`_, which use a custom format named *wheel*, so they're generally referred to as *wheels*. What are the roles of sdists and wheels? ---------------------------------------- As you might have figured out by the name, sdists contain the source code of the project, and wheels contain a compiled [#pure-wheels]_ version of the project, ready to be copied to the file system. If your project uses Python extension modules, your wheels will be specific to both the platform and the Python version [#stable-abi]_. While distributing wheels is not mandatory, they make the user experience much nicer. Unless you have any reason not to, we highly recommend you distribute wheels for at least the most common systems. When wheels are not available for a system, the project can still be installed, be it needs to be build from the sdist, which involves fetching all the build dependencies and going through the likely expensive build process. .. [#pure-wheels] Projects that don't have any compiled code will have a platform-independent -- *pure* -- wheel. .. [#stable-abi] Unless you are using the `stable ABI`_, which limits you to a subset of the Python C API, with the trade-off that your native code will be compatible with multiple Python versions. Building the project -------------------- Before continuing, ensure you have committed the three files we created so far to your Git repository - ``meson-python`` will only take into account the files that Git knows about. To generate the distribution artifacts we will use the `pypa/build`_ tool. It will create a temporary virtual environment, install all the required build dependencies, and ask ``meson-python`` to build the artifacts. .. code-block:: console $ pip install build $ python -m build If the build succeeded, you'll have the binary artifacts in the ``dist`` folder. .. admonition:: Building wheels for multiple platforms :class: tip If our project only contains pure-Python (``.py``) code, the wheel we just built will work on all platforms, as it is a pure wheel, but if the project contains native code, it will be specific for our machine's platform. When releasing, you'll usually want to build for at least most of the other more popular platforms (Linux, Windows, macOS, etc.). To make that work easier, we recommend checking out the cibuildwheel_ project, which allows you to automate it. Distributing the project ------------------------ Now that we have the distribution artifacts, we can upload them to a repository. We will upload them to the `Python Package Index`_ (PyPI), which is repository that comes enabled by default in most tools. For this, we will use Twine_. .. code-block:: console $ pip install twine $ twine upload dist/* .. admonition:: Upload to the `Test PyPI`_ :class: tip If you don't want to upload to the real index, you can upload to the `Test PyPI`_ instead. .. code-block:: console $ twine upload -r testpypi dist/* You can find more about how to use the `Test PyPI`_ in `its PyPA documentation page `_. After this, your package should be available on PyPI_, and installable with pip_. .. code-block:: console $ pip install our-first-project .. _Meson: https://mesonbuild.com/ .. _Python module: https://mesonbuild.com/Python-module.html .. _PyPA documentation on project metadata: https://packaging.python.org/en/latest/specifications/declaring-project-metadata/ .. _source distributions: https://packaging.python.org/en/latest/specifications/source-distribution-format/ .. _binary distributions: https://packaging.python.org/en/latest/specifications/binary-distribution-format/ .. _stable ABI: https://docs.python.org/3/c-api/stable.html#stable-application-binary-interface .. _pypa/build: https://github.com/pypa/build .. _cibuildwheel: https://github.com/pypa/cibuildwheel .. _Python Package Index: https://pypi.org/ .. _pronounced "pie pea eye": https://pypi.org/help/#pronunciation .. _Twine: https://github.com/pypa/twine .. _Test PyPI: https://test.pypi.org/ .. _PyPI: https://pypi.org/ .. _pip: https://github.com/pypa/pip ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/meson.build0000644000000000000000000000063014607715450013420 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('meson-python', version: '0.16.0') py = import('python').find_installation() py.install_sources( 'mesonpy/__init__.py', 'mesonpy/_compat.py', 'mesonpy/_editable.py', 'mesonpy/_rpath.py', 'mesonpy/_tags.py', 'mesonpy/_util.py', 'mesonpy/_wheelfile.py', subdir: 'mesonpy', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/mesonpy/__init__.py0000644000000000000000000012521614607715450015071 0ustar00# SPDX-FileCopyrightText: 2021 Filipe Laíns # SPDX-FileCopyrightText: 2021 Quansight, LLC # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT """Meson Python build backend Implements PEP 517 hooks. """ from __future__ import annotations import argparse import collections import contextlib import difflib import functools import importlib.machinery import io import itertools import json import os import pathlib import platform import re import shutil import subprocess import sys import sysconfig import tarfile import tempfile import textwrap import time import typing import warnings if sys.version_info < (3, 11): import tomli as tomllib else: import tomllib import packaging.utils import packaging.version import pyproject_metadata import mesonpy._compat import mesonpy._rpath import mesonpy._tags import mesonpy._util import mesonpy._wheelfile from mesonpy._compat import cached_property, read_binary if typing.TYPE_CHECKING: # pragma: no cover from typing import Any, Callable, DefaultDict, Dict, List, Literal, Optional, Sequence, TextIO, Tuple, Type, TypeVar, Union from mesonpy._compat import Collection, Iterator, Mapping, ParamSpec, Path, Self P = ParamSpec('P') T = TypeVar('T') MesonArgsKeys = Literal['dist', 'setup', 'compile', 'install'] MesonArgs = Mapping[MesonArgsKeys, List[str]] __version__ = '0.16.0' _NINJA_REQUIRED_VERSION = '1.8.2' _MESON_REQUIRED_VERSION = '0.63.3' # keep in sync with the version requirement in pyproject.toml _MESON_ARGS_KEYS = ['dist', 'setup', 'compile', 'install'] _SUFFIXES = importlib.machinery.all_suffixes() _EXTENSION_SUFFIX_REGEX = re.compile(r'^[^.]+\.(?:(?P[^.]+)\.)?(?:so|pyd|dll)$') assert all(re.match(_EXTENSION_SUFFIX_REGEX, f'foo{x}') for x in importlib.machinery.EXTENSION_SUFFIXES) # Map Meson installation path placeholders to wheel installation paths. # See https://docs.python.org/3/library/sysconfig.html#installation-paths _INSTALLATION_PATH_MAP = { '{bindir}': 'scripts', '{py_purelib}': 'purelib', '{py_platlib}': 'platlib', '{moduledir_shared}': 'platlib', '{includedir}': 'headers', '{datadir}': 'data', # custom location '{libdir}': 'mesonpy-libs', '{libdir_shared}': 'mesonpy-libs', } def _map_to_wheel(sources: Dict[str, Dict[str, Any]]) -> DefaultDict[str, List[Tuple[pathlib.Path, str]]]: """Map files to the wheel, organized by wheel installation directory.""" wheel_files: DefaultDict[str, List[Tuple[pathlib.Path, str]]] = collections.defaultdict(list) packages: Dict[str, str] = {} for key, group in sources.items(): for src, target in group.items(): destination = pathlib.Path(target['destination']) anchor = destination.parts[0] dst = pathlib.Path(*destination.parts[1:]) path = _INSTALLATION_PATH_MAP.get(anchor) if path is None: raise BuildError(f'Could not map installation path to an equivalent wheel directory: {str(destination)!r}') if path == 'purelib' or path == 'platlib': package = destination.parts[1] other = packages.setdefault(package, path) if other != path: this = os.fspath(pathlib.Path(path, *destination.parts[1:])) that = os.fspath(other / next(d for d, s in wheel_files[other] if d.parts[0] == destination.parts[1])) raise BuildError( f'The {package} package is split between {path} and {other}: ' f'{this!r} and {that!r}, a "pure: false" argument may be missing in meson.build. ' f'It is recommended to set it in "import(\'python\').find_installation()"') if key == 'install_subdirs' or key == 'targets' and os.path.isdir(src): assert os.path.isdir(src) exclude_files = {os.path.normpath(x) for x in target.get('exclude_files', [])} exclude_dirs = {os.path.normpath(x) for x in target.get('exclude_dirs', [])} for root, dirnames, filenames in os.walk(src): for name in dirnames.copy(): dirsrc = os.path.join(root, name) relpath = os.path.relpath(dirsrc, src) if relpath in exclude_dirs: dirnames.remove(name) # sort to process directories determninistically dirnames.sort() for name in sorted(filenames): filesrc = os.path.join(root, name) relpath = os.path.relpath(filesrc, src) if relpath in exclude_files: continue filedst = dst / relpath wheel_files[path].append((filedst, filesrc)) else: wheel_files[path].append((dst, src)) return wheel_files class style: ERROR = '\33[31m' # red WARNING = '\33[93m' # bright yellow INFO = '\33[36m\33[1m' # cyan, bold RESET = '\33[0m' @staticmethod def strip(string: str) -> str: """Strip ANSI escape sequences from string.""" return re.sub(r'\033\[[;?0-9]*[a-zA-Z]', '', string) @functools.lru_cache() def _use_ansi_escapes() -> bool: """Determine whether logging should use ANSI escapes.""" # We print log messages and error messages that may contain file # names containing characters that cannot be represented in the # stdout encoding. Use replacement markers for those instead than # raising UnicodeEncodeError. sys.stdout.reconfigure(errors='replace') # type: ignore[attr-defined] if 'NO_COLOR' in os.environ: return False if 'FORCE_COLOR' in os.environ or sys.stdout.isatty() and os.environ.get('TERM') != 'dumb': if sys.platform == 'win32' and not os.environ.get('ANSICON'): return mesonpy._util.setup_windows_console() return True return False def _log(string: str , **kwargs: Any) -> None: if not _use_ansi_escapes(): string = style.strip(string) print(string, **kwargs) def _showwarning( message: Union[Warning, str], category: Type[Warning], filename: str, lineno: int, file: Optional[TextIO] = None, line: Optional[str] = None, ) -> None: # pragma: no cover """Callable to override the default warning handler, to have colored output.""" _log(f'{style.WARNING}meson-python: warning:{style.RESET} {message}') class _clicounter: def __init__(self, total: int) -> None: self._total = total self._count = itertools.count(start=1) def __enter__(self) -> Self: return self def update(self, description: str) -> None: line = f'[{next(self._count)}/{self._total}] {description}' if _use_ansi_escapes(): print('\r', line, sep='', end='\33[0K', flush=True) else: print(line) def __exit__(self, exc_type: Any, exc_value: Any, exc_tb: Any) -> None: if _use_ansi_escapes(): print() class Error(RuntimeError): def __str__(self) -> str: return str(self.args[0]) class ConfigError(Error): """Error in the backend configuration.""" class BuildError(Error): """Error when building the wheel.""" class MesonBuilderError(Error): """Error when building the Meson package.""" class Metadata(pyproject_metadata.StandardMetadata): def __init__(self, name: str, *args: Any, **kwargs: Any): super().__init__(name, *args, **kwargs) # Local fix for https://github.com/FFY00/python-pyproject-metadata/issues/60 self.name = self._validate_name(name) @staticmethod def _validate_name(name: str) -> str: # See https://packaging.python.org/en/latest/specifications/core-metadata/#name if not re.match(r'^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', name, re.IGNORECASE): raise pyproject_metadata.ConfigurationError( f'Invalid project name "{name}". A valid name consists only of ASCII letters and ' f'numbers, period, underscore and hyphen. It must start and end with a letter or number') return name @classmethod def from_pyproject(cls, data: Mapping[str, Any], project_dir: Path) -> Metadata: # type: ignore[override] # The class method from the pyproject_metadata base class is not # typed in a subclassing friendly way, thus annotations to ignore # typing are needed. metadata = super().from_pyproject(data, project_dir) # Check for missing version field. if not metadata.version and 'version' not in metadata.dynamic: raise pyproject_metadata.ConfigurationError( 'Required "project.version" field is missing and not declared as dynamic') # Check for unsupported dynamic fields. unsupported_dynamic = set(metadata.dynamic) - {'version', } if unsupported_dynamic: fields = ', '.join(f'"{x}"' for x in unsupported_dynamic) raise pyproject_metadata.ConfigurationError(f'Unsupported dynamic fields: {fields}') return metadata # type: ignore[return-value] # Local fix for a bug in pyproject-metadata. See # https://github.com/mesonbuild/meson-python/issues/454 def _update_dynamic(self, value: Any) -> None: if value and 'version' in self.dynamic: self.dynamic.remove('version') @property def canonical_name(self) -> str: # See https://packaging.python.org/en/latest/specifications/name-normalization/#normalization return packaging.utils.canonicalize_name(self.name) @property def distribution_name(self) -> str: """Name to be used in wheel and sdist file names.""" return self.canonical_name.replace('-', '_') def _is_native(file: Path) -> bool: """Check if file is a native file.""" with open(file, 'rb') as f: if sys.platform == 'darwin': return f.read(4) in ( b'\xfe\xed\xfa\xce', # 32-bit b'\xfe\xed\xfa\xcf', # 64-bit b'\xcf\xfa\xed\xfe', # arm64 b'\xca\xfe\xba\xbe', # universal / fat (same as java class so beware!) ) elif sys.platform == 'win32' or sys.platform == 'cygwin': return f.read(2) == b'MZ' else: # Assume that any other platform uses ELF binaries. return f.read(4) == b'\x7fELF' # ELF class _WheelBuilder(): """Helper class to build wheels from projects.""" def __init__( self, metadata: Metadata, manifest: Dict[str, List[Tuple[pathlib.Path, str]]], limited_api: bool, ) -> None: self._metadata = metadata self._manifest = manifest self._limited_api = limited_api @property def _has_internal_libs(self) -> bool: return bool(self._manifest.get('mesonpy-libs')) @property def _has_extension_modules(self) -> bool: # Assume that all code installed in {platlib} is Python ABI dependent. return bool(self._manifest.get('platlib')) @cached_property def _pure(self) -> bool: """Whether the wheel is architecture independent""" if self._manifest['platlib'] or self._manifest['mesonpy-libs']: return False for _, file in self._manifest['scripts']: if _is_native(file): return False return True @property def tag(self) -> mesonpy._tags.Tag: """Wheel tags.""" if self._pure: return mesonpy._tags.Tag('py3', 'none', 'any') if not self._has_extension_modules: # The wheel has platform dependent code (is not pure) but # does not contain any extension module (does not # distribute any file in {platlib}) thus use generic # implementation and ABI tags. return mesonpy._tags.Tag('py3', 'none', None) return mesonpy._tags.Tag(None, self._stable_abi, None) @property def name(self) -> str: """Wheel name, this includes the basename and tag.""" return f'{self._metadata.distribution_name}-{self._metadata.version}-{self.tag}' @property def _distinfo_dir(self) -> str: return f'{self._metadata.distribution_name}-{self._metadata.version}.dist-info' @property def _data_dir(self) -> str: return f'{self._metadata.distribution_name}-{self._metadata.version}.data' @property def _libs_dir(self) -> str: return f'.{self._metadata.distribution_name}.mesonpy.libs' @property def _license_file(self) -> Optional[pathlib.Path]: license_ = self._metadata.license if license_: return license_.file return None @property def wheel(self) -> bytes: """Return WHEEL file for dist-info.""" return textwrap.dedent(''' Wheel-Version: 1.0 Generator: meson Root-Is-Purelib: {is_purelib} Tag: {tag} ''').strip().format( is_purelib='true' if self._pure else 'false', tag=self.tag, ).encode() @property def entrypoints_txt(self) -> bytes: """dist-info entry_points.txt.""" data = self._metadata.entrypoints.copy() data.update({ 'console_scripts': self._metadata.scripts, 'gui_scripts': self._metadata.gui_scripts, }) text = '' for entrypoint in data: if data[entrypoint]: text += f'[{entrypoint}]\n' for name, target in data[entrypoint].items(): text += f'{name} = {target}\n' text += '\n' return text.encode() @cached_property def _stable_abi(self) -> Optional[str]: if self._limited_api: # PyPy does not use a special extension module filename # suffix for modules targeting the stable API. if '__pypy__' not in sys.builtin_module_names: # Verify stable ABI compatibility: examine files installed # in {platlib} that look like extension modules, and raise # an exception if any of them has a Python version # specific extension filename suffix ABI tag. for path, _ in self._manifest['platlib']: match = _EXTENSION_SUFFIX_REGEX.match(path.name) if match: abi = match.group('abi') if abi is not None and abi != 'abi3': raise BuildError( f'The package declares compatibility with Python limited API but extension ' f'module {os.fspath(path)!r} is tagged for a specific Python version.') return 'abi3' return None def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path, destination: pathlib.Path) -> None: """Add a file to the wheel.""" if self._has_internal_libs: if _is_native(origin): # When an executable, libray, or Python extension module is # dynamically linked to a library built as part of the project, # Meson adds a library load path to it pointing to the build # directory, in the form of a relative RPATH entry. meson-python # relocates the shared libraries to the $project.mesonpy.libs # folder. Rewrite the RPATH to point to that folder instead. libspath = os.path.relpath(self._libs_dir, destination.parent) mesonpy._rpath.fix_rpath(origin, libspath) try: wheel_file.write(origin, destination.as_posix()) except FileNotFoundError: # work around for Meson bug, see https://github.com/mesonbuild/meson/pull/11655 if not os.fspath(origin).endswith('.pdb'): raise def _wheel_write_metadata(self, whl: mesonpy._wheelfile.WheelFile) -> None: # add metadata whl.writestr(f'{self._distinfo_dir}/METADATA', bytes(self._metadata.as_rfc822())) whl.writestr(f'{self._distinfo_dir}/WHEEL', self.wheel) if self.entrypoints_txt: whl.writestr(f'{self._distinfo_dir}/entry_points.txt', self.entrypoints_txt) # add license (see https://github.com/mesonbuild/meson-python/issues/88) if self._license_file: whl.write(self._license_file, f'{self._distinfo_dir}/{os.path.basename(self._license_file)}') def build(self, directory: Path) -> pathlib.Path: wheel_file = pathlib.Path(directory, f'{self.name}.whl') with mesonpy._wheelfile.WheelFile(wheel_file, 'w') as whl: self._wheel_write_metadata(whl) with _clicounter(sum(len(x) for x in self._manifest.values())) as counter: root = 'purelib' if self._pure else 'platlib' for path, entries in self._manifest.items(): for dst, src in entries: counter.update(src) if path == root: pass elif path == 'mesonpy-libs': # custom installation path for bundled libraries dst = pathlib.Path(self._libs_dir, dst) else: dst = pathlib.Path(self._data_dir, path, dst) self._install_path(whl, src, dst) return wheel_file class _EditableWheelBuilder(_WheelBuilder): @property def _top_level_modules(self) -> Collection[str]: modules = set() for type_ in self._manifest: for path, _ in self._manifest[type_]: name, dot, ext = path.parts[0].partition('.') if dot: # module suffix = dot + ext if suffix in _SUFFIXES: modules.add(name) else: # package modules.add(name) return modules def build(self, directory: Path, source_dir: pathlib.Path, build_dir: pathlib.Path, # type: ignore[override] build_command: List[str], verbose: bool = False) -> pathlib.Path: wheel_file = pathlib.Path(directory, f'{self.name}.whl') with mesonpy._wheelfile.WheelFile(wheel_file, 'w') as whl: self._wheel_write_metadata(whl) whl.writestr( f'{self._distinfo_dir}/direct_url.json', source_dir.as_uri().encode('utf-8')) # install loader module loader_module_name = f'_{self._metadata.distribution_name}_editable_loader' whl.writestr( f'{loader_module_name}.py', read_binary('mesonpy', '_editable.py') + textwrap.dedent(f''' install( {self._metadata.name!r}, {self._top_level_modules!r}, {os.fspath(build_dir)!r}, {build_command!r}, {verbose!r}, )''').encode('utf-8')) # install .pth file whl.writestr( f'{self._metadata.canonical_name}-editable.pth', f'import {loader_module_name}'.encode('utf-8')) return wheel_file def _validate_pyproject_config(pyproject: Dict[str, Any]) -> Dict[str, Any]: def _table(scheme: Dict[str, Callable[[Any, str], Any]]) -> Callable[[Any, str], Dict[str, Any]]: def func(value: Any, name: str) -> Dict[str, Any]: if not isinstance(value, dict): raise ConfigError(f'Configuration entry "{name}" must be a table') table = {} for key, val in value.items(): check = scheme.get(key) if check is None: raise ConfigError(f'Unknown configuration entry "{name}.{key}"') table[key] = check(val, f'{name}.{key}') return table return func def _strings(value: Any, name: str) -> List[str]: if not isinstance(value, list) or not all(isinstance(x, str) for x in value): raise ConfigError(f'Configuration entry "{name}" must be a list of strings') return value def _bool(value: Any, name: str) -> bool: if not isinstance(value, bool): raise ConfigError(f'Configuration entry "{name}" must be a boolean') return value def _string_or_path(value: Any, name: str) -> str: if not isinstance(value, str): raise ConfigError(f'Configuration entry "{name}" must be a string') if os.path.isfile(value): value = os.path.abspath(value) return value scheme = _table({ 'meson': _string_or_path, 'limited-api': _bool, 'args': _table({ name: _strings for name in _MESON_ARGS_KEYS }), }) table = pyproject.get('tool', {}).get('meson-python', {}) return scheme(table, 'tool.meson-python') def _validate_config_settings(config_settings: Dict[str, Any]) -> Dict[str, Any]: """Validate options received from build frontend.""" def _string(value: Any, name: str) -> str: if not isinstance(value, str): raise ConfigError(f'Only one value for "{name}" can be specified') return value def _bool(value: Any, name: str) -> bool: return True def _string_or_strings(value: Any, name: str) -> List[str]: return list([value,] if isinstance(value, str) else value) options = { 'builddir': _string, 'build-dir': _string, 'editable-verbose': _bool, 'dist-args': _string_or_strings, 'setup-args': _string_or_strings, 'compile-args': _string_or_strings, 'install-args': _string_or_strings, } assert all(f'{name}-args' in options for name in _MESON_ARGS_KEYS) config = {} for key, value in config_settings.items(): parser = options.get(key) if parser is None: matches = difflib.get_close_matches(key, options.keys(), n=2) if matches: alternatives = ' or '.join(f'"{match}"' for match in matches) raise ConfigError(f'Unknown option "{key}". Did you mean {alternatives}?') else: raise ConfigError(f'Unknown option "{key}"') config[key] = parser(value, key) # Check backward compatibility aliases. aliases = { 'build-dir': 'builddir', } for key, alt in aliases.items(): if key in config and alt in config: raise ConfigError(f'Option "{alt}" is a backward compatibility alias for "{key}". Only one can be used') if alt in config: config[key] = config[alt] return config class Project(): """Meson project wrapper to generate Python artifacts.""" def __init__( self, source_dir: Path, build_dir: Path, meson_args: Optional[MesonArgs] = None, editable_verbose: bool = False, ) -> None: self._source_dir = pathlib.Path(source_dir).absolute() self._build_dir = pathlib.Path(build_dir).absolute() self._editable_verbose = editable_verbose self._meson_native_file = self._build_dir / 'meson-python-native-file.ini' self._meson_cross_file = self._build_dir / 'meson-python-cross-file.ini' self._meson_args: MesonArgs = collections.defaultdict(list) self._limited_api = False # load pyproject.toml pyproject = tomllib.loads(self._source_dir.joinpath('pyproject.toml').read_text()) # load meson args from pyproject.toml pyproject_config = _validate_pyproject_config(pyproject) for key, value in pyproject_config.get('args', {}).items(): self._meson_args[key].extend(value) # meson arguments from the command line take precedence over # arguments from the configuration file thus are added later if meson_args: for key, value in meson_args.items(): self._meson_args[key].extend(value) # determine command to invoke meson self._meson = _get_meson_command(pyproject_config.get('meson')) self._ninja = _env_ninja_command() if self._ninja is None: raise ConfigError(f'Could not find ninja version {_NINJA_REQUIRED_VERSION} or newer.') os.environ.setdefault('NINJA', self._ninja) # make sure the build dir exists self._build_dir.mkdir(exist_ok=True, parents=True) # setuptools-like ARCHFLAGS environment variable support if sysconfig.get_platform().startswith('macosx-'): archflags = os.environ.get('ARCHFLAGS', '').strip() if archflags: # parse the ARCHFLAGS environment variable parser = argparse.ArgumentParser(add_help=False, allow_abbrev=False) parser.add_argument('-arch', action='append') args, unknown = parser.parse_known_args(archflags.split()) if unknown: raise ConfigError(f'Unknown flag specified in $ARCHFLAGS={archflags!r}') arch, *other = set(args.arch) if other: raise ConfigError(f'Multi-architecture builds are not supported but $ARCHFLAGS={archflags!r}') macver, _, nativearch = platform.mac_ver() if arch != nativearch: x = os.environ.setdefault('_PYTHON_HOST_PLATFORM', f'macosx-{macver}-{arch}') if not x.endswith(arch): raise ConfigError(f'$ARCHFLAGS={archflags!r} and $_PYTHON_HOST_PLATFORM={x!r} do not agree') family = 'aarch64' if arch == 'arm64' else arch cross_file_data = textwrap.dedent(f''' [binaries] c = ['cc', '-arch', {arch!r}] cpp = ['c++', '-arch', {arch!r}] objc = ['cc', '-arch', {arch!r}] objcpp = ['c++', '-arch', {arch!r}] [host_machine] system = 'darwin' cpu = {arch!r} cpu_family = {family!r} endian = 'little' ''') self._meson_cross_file.write_text(cross_file_data) self._meson_args['setup'].extend(('--cross-file', os.fspath(self._meson_cross_file))) # write the native file native_file_data = textwrap.dedent(f''' [binaries] python = '{sys.executable}' ''') self._meson_native_file.write_text(native_file_data) # reconfigure if we have a valid Meson build directory. Meson # uses the presence of the 'meson-private/coredata.dat' file # in the build directory as indication that the build # directory has already been configured and arranges this file # to be created as late as possible or deleted if something # goes wrong during setup. reconfigure = self._build_dir.joinpath('meson-private/coredata.dat').is_file() # run meson setup self._configure(reconfigure=reconfigure) # package metadata if 'project' in pyproject: self._metadata = Metadata.from_pyproject(pyproject, self._source_dir) # set version from meson.build if version is declared as dynamic if 'version' in self._metadata.dynamic: version = self._meson_version if version == 'undefined': raise pyproject_metadata.ConfigurationError( 'Field "version" declared as dynamic but version is not defined in meson.build') self._metadata.version = packaging.version.Version(version) else: # if project section is missing, use minimal metdata from meson.build name, version = self._meson_name, self._meson_version if version == 'undefined': raise pyproject_metadata.ConfigurationError( 'Section "project" missing in pyproject.toml and version is not defined in meson.build') self._metadata = Metadata(name=name, version=packaging.version.Version(version)) # verify that we are running on a supported interpreter if self._metadata.requires_python: self._metadata.requires_python.prereleases = True if platform.python_version().rstrip('+') not in self._metadata.requires_python: raise MesonBuilderError( f'Package requires Python version {self._metadata.requires_python}, ' f'running on {platform.python_version()}') # limited API self._limited_api = pyproject_config.get('limited-api', False) if self._limited_api: # check whether limited API is disabled for the Meson project options = self._info('intro-buildoptions') value = next((option['value'] for option in options if option['name'] == 'python.allow_limited_api'), None) if not value: self._limited_api = False def _run(self, cmd: Sequence[str]) -> None: """Invoke a subprocess.""" # Flush the line to ensure that the log line with the executed # command line appears before the command output. Without it, # the lines appear in the wrong order in pip output. _log('{style.INFO}+ {cmd}{style.RESET}'.format(style=style, cmd=' '.join(cmd)), flush=True) r = subprocess.run(cmd, cwd=self._build_dir) if r.returncode != 0: raise SystemExit(r.returncode) def _configure(self, reconfigure: bool = False) -> None: """Configure Meson project.""" setup_args = [ os.fspath(self._source_dir), os.fspath(self._build_dir), # default build options '-Dbuildtype=release', '-Db_ndebug=if-release', '-Db_vscrt=md', # user build options *self._meson_args['setup'], # pass native file last to have it override the python # interpreter path that may have been specified in user # provided native files f'--native-file={os.fspath(self._meson_native_file)}', ] if reconfigure: setup_args.insert(0, '--reconfigure') self._run(self._meson + ['setup', *setup_args]) @property def _build_command(self) -> List[str]: assert self._ninja is not None # help mypy out if sys.platform == 'win32': # On Windows use 'meson compile' to setup the MSVC compiler # environment. Using the --ninja-args option allows to # provide the exact same semantics for the compile arguments # provided by the users. cmd = self._meson + ['compile'] args = list(self._meson_args['compile']) if args: cmd.append(f'--ninja-args={args!r}') return cmd return [self._ninja, *self._meson_args['compile']] @functools.lru_cache(maxsize=None) def build(self) -> None: """Build the Meson project.""" self._run(self._build_command) @functools.lru_cache() def _info(self, name: str) -> Any: """Read info from meson-info directory.""" info = self._build_dir.joinpath('meson-info', f'{name}.json') return json.loads(info.read_text()) @property def _manifest(self) -> DefaultDict[str, List[Tuple[pathlib.Path, str]]]: """The files to be added to the wheel, organized by wheel path.""" # Obtain the list of files Meson would install. install_plan = self._info('intro-install_plan') # Parse the 'meson install' args to extract --tags and --skip-subprojects parser = argparse.ArgumentParser(add_help=False) parser.add_argument('--tags') parser.add_argument('--skip-subprojects', nargs='?', const='*', default='') args, _ = parser.parse_known_args(self._meson_args['install']) install_tags = {t.strip() for t in args.tags.split(',')} if args.tags else None skip_subprojects = {p for p in (p.strip() for p in args.skip_subprojects.split(',')) if p} # Filter the install plan accordingly. sources: DefaultDict[str, Dict[str, Dict[str, str]]] = collections.defaultdict(dict) for key, targets in install_plan.items(): for target, details in targets.items(): if install_tags is not None and details['tag'] not in install_tags: continue subproject = details.get('subproject') if subproject is not None and (subproject in skip_subprojects or '*' in skip_subprojects): continue sources[key][target] = details # Map Meson installation locations to wheel paths. return _map_to_wheel(sources) @property def _meson_name(self) -> str: """Name in meson.build.""" name = self._info('intro-projectinfo')['descriptive_name'] assert isinstance(name, str) return name @property def _meson_version(self) -> str: """Version in meson.build.""" name = self._info('intro-projectinfo')['version'] assert isinstance(name, str) return name def sdist(self, directory: Path) -> pathlib.Path: """Generates a sdist (source distribution) in the specified directory.""" # generate meson dist file self._run(self._meson + ['dist', '--allow-dirty', '--no-tests', '--formats', 'gztar', *self._meson_args['dist']]) # move meson dist file to output path dist_name = f'{self._metadata.distribution_name}-{self._metadata.version}' meson_dist_name = f'{self._meson_name}-{self._meson_version}' meson_dist_path = pathlib.Path(self._build_dir, 'meson-dist', f'{meson_dist_name}.tar.gz') sdist = pathlib.Path(directory, f'{dist_name}.tar.gz') with tarfile.open(meson_dist_path, 'r:gz') as meson_dist, mesonpy._util.create_targz(sdist) as tar: for member in meson_dist.getmembers(): # calculate the file path in the source directory assert member.name, member.name member_parts = member.name.split('/') if len(member_parts) <= 1: continue path = self._source_dir.joinpath(*member_parts[1:]) if not path.exists() and member.isfile(): # File doesn't exists on the source directory but exists on # the Meson dist, so it is generated file, which we need to # include. # See https://mesonbuild.com/Reference-manual_builtin_meson.html#mesonadd_dist_script # MESON_DIST_ROOT could have a different base name # than the actual sdist basename, so we need to rename here file = meson_dist.extractfile(member.name) member.name = str(pathlib.Path(dist_name, *member_parts[1:]).as_posix()) tar.addfile(member, file) continue if not path.is_file(): continue info = tarfile.TarInfo(member.name) file_stat = os.stat(path) info.mtime = member.mtime info.size = file_stat.st_size info.mode = int(oct(file_stat.st_mode)[-3:], 8) # rewrite the path if necessary, to match the sdist distribution name if dist_name != meson_dist_name: info.name = pathlib.Path( dist_name, path.relative_to(self._source_dir) ).as_posix() with path.open('rb') as f: tar.addfile(info, fileobj=f) # add PKG-INFO to dist file to make it a sdist pkginfo_info = tarfile.TarInfo(f'{dist_name}/PKG-INFO') pkginfo_info.mtime = time.time() # type: ignore[assignment] metadata = bytes(self._metadata.as_rfc822()) pkginfo_info.size = len(metadata) tar.addfile(pkginfo_info, fileobj=io.BytesIO(metadata)) return sdist def wheel(self, directory: Path) -> pathlib.Path: """Generates a wheel in the specified directory.""" self.build() builder = _WheelBuilder(self._metadata, self._manifest, self._limited_api) return builder.build(directory) def editable(self, directory: Path) -> pathlib.Path: """Generates an editable wheel in the specified directory.""" self.build() builder = _EditableWheelBuilder(self._metadata, self._manifest, self._limited_api) return builder.build(directory, self._source_dir, self._build_dir, self._build_command, self._editable_verbose) @contextlib.contextmanager def _project(config_settings: Optional[Dict[Any, Any]] = None) -> Iterator[Project]: """Create the project given the given config settings.""" settings = _validate_config_settings(config_settings or {}) meson_args = typing.cast('MesonArgs', {name: settings.get(f'{name}-args', []) for name in _MESON_ARGS_KEYS}) source_dir = os.path.curdir build_dir = settings.get('build-dir') editable_verbose = bool(settings.get('editable-verbose')) with contextlib.ExitStack() as ctx: if build_dir is None: build_dir = ctx.enter_context(tempfile.TemporaryDirectory(prefix='.mesonpy-', dir=source_dir)) yield Project(source_dir, build_dir, meson_args, editable_verbose) def _parse_version_string(string: str) -> Tuple[int, ...]: """Parse version string.""" try: return tuple(map(int, string.split('.')[:3])) except ValueError: return (0, ) def _get_meson_command( meson: Optional[str] = None, *, version: str = _MESON_REQUIRED_VERSION ) -> List[str]: """Return the command to invoke meson.""" # The MESON env var, if set, overrides the config value from pyproject.toml. # The config value, if given, is an absolute path or the name of an executable. meson = os.environ.get('MESON', meson or 'meson') # If the specified Meson string ends in `.py`, we run it with the current # Python executable. This avoids problems for users on Windows, where # making a script executable isn't enough to get it to run when invoked # directly. For packages that vendor a forked Meson, the `meson.py` in the # root of the Meson repo can be used this way. if meson.endswith('.py'): cmd = [sys.executable, meson] else: cmd = [meson] # The meson Python package is a dependency of the meson-python Python # package, however, it may occur that the meson Python package is installed # but the corresponding meson command is not available in $PATH. Implement # a runtime check to verify that the build environment is setup correcly. required_version = _parse_version_string(version) meson_version = subprocess.run(cmd + ['--version'], check=False, text=True, capture_output=True).stdout if _parse_version_string(meson_version) < required_version: raise ConfigError(f'Could not find meson version {version} or newer, found {meson_version}.') return cmd def _env_ninja_command(*, version: str = _NINJA_REQUIRED_VERSION) -> Optional[str]: """Returns the path to ninja, or None if no ninja found.""" required_version = _parse_version_string(version) env_ninja = os.environ.get('NINJA') ninja_candidates = [env_ninja] if env_ninja else ['ninja', 'ninja-build', 'samu'] for ninja in ninja_candidates: ninja_path = shutil.which(ninja) if ninja_path is not None: version = subprocess.run([ninja_path, '--version'], check=False, text=True, capture_output=True).stdout if _parse_version_string(version) >= required_version: return ninja_path return None def _add_ignore_files(directory: pathlib.Path) -> None: directory.joinpath('.gitignore').write_text(textwrap.dedent(''' # This file is generated by meson-python. It will not be recreated if deleted or modified. * '''), encoding='utf-8') directory.joinpath('.hgignore').write_text(textwrap.dedent(''' # This file is generated by meson-python. It will not be recreated if deleted or modified. syntax: glob **/* '''), encoding='utf-8') def _pyproject_hook(func: Callable[P, T]) -> Callable[P, T]: @functools.wraps(func) def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: warnings.showwarning = _showwarning try: return func(*args, **kwargs) except (Error, pyproject_metadata.ConfigurationError) as exc: prefix = f'{style.ERROR}meson-python: error:{style.RESET} ' _log('\n' + textwrap.indent(str(exc), prefix)) raise SystemExit(1) from exc return wrapper @_pyproject_hook def get_requires_for_build_sdist(config_settings: Optional[Dict[str, str]] = None) -> List[str]: dependencies = [] if os.environ.get('NINJA') is None and _env_ninja_command() is None: dependencies.append(f'ninja >= {_NINJA_REQUIRED_VERSION}') return dependencies @_pyproject_hook def get_requires_for_build_wheel(config_settings: Optional[Dict[str, str]] = None) -> List[str]: dependencies = [] if os.environ.get('NINJA') is None and _env_ninja_command() is None: dependencies.append(f'ninja >= {_NINJA_REQUIRED_VERSION}') if sys.platform.startswith('linux') and not shutil.which('patchelf'): dependencies.append('patchelf >= 0.11.0') return dependencies get_requires_for_build_editable = get_requires_for_build_wheel @_pyproject_hook def build_sdist( sdist_directory: str, config_settings: Optional[Dict[Any, Any]] = None, ) -> str: out = pathlib.Path(sdist_directory) with _project(config_settings) as project: return project.sdist(out).name @_pyproject_hook def build_wheel( wheel_directory: str, config_settings: Optional[Dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: out = pathlib.Path(wheel_directory) with _project(config_settings) as project: return project.wheel(out).name @_pyproject_hook def build_editable( wheel_directory: str, config_settings: Optional[Dict[Any, Any]] = None, metadata_directory: Optional[str] = None, ) -> str: # Force set a permanent build directory. if not config_settings: config_settings = {} if 'build-dir' not in config_settings and 'builddir' not in config_settings: build_dir = pathlib.Path('build') build_dir.mkdir(exist_ok=True) if not next(build_dir.iterdir(), None): _add_ignore_files(build_dir) config_settings['build-dir'] = os.fspath(build_dir / str(mesonpy._tags.get_abi_tag())) out = pathlib.Path(wheel_directory) with _project(config_settings) as project: return project.editable(out).name ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/mesonpy/_compat.py0000644000000000000000000000264214607715450014751 0ustar00# SPDX-FileCopyrightText: 2021 Filipe Laíns # SPDX-FileCopyrightText: 2021 Quansight, LLC # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import functools import importlib.resources import os import sys import typing if sys.version_info >= (3, 9): from collections.abc import Collection, Iterable, Iterator, Mapping, Sequence else: from typing import Collection, Iterable, Iterator, Mapping, Sequence if sys.version_info >= (3, 8): from functools import cached_property else: cached_property = lambda x: property(functools.lru_cache(maxsize=None)(x)) # noqa: E731 if sys.version_info >= (3, 9): def read_binary(package: str, resource: str) -> bytes: return importlib.resources.files(package).joinpath(resource).read_bytes() else: read_binary = importlib.resources.read_binary if typing.TYPE_CHECKING: from typing import Union if sys.version_info >= (3, 10): from typing import ParamSpec else: from typing_extensions import ParamSpec if sys.version_info >= (3, 11): from typing import Self else: from typing_extensions import Self Path = Union[str, os.PathLike] __all__ = [ 'cached_property', 'read_binary', 'Collection', 'Iterable', 'Iterator', 'Mapping', 'Path', 'ParamSpec', 'Self', 'Sequence', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/mesonpy/_editable.py0000644000000000000000000003277414607715450015250 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # This file should be standalone! It is copied during the editable hook installation. from __future__ import annotations import ast import functools import importlib.abc import importlib.machinery import importlib.util import inspect import json import os import pathlib import subprocess import sys import typing if typing.TYPE_CHECKING: from collections.abc import Sequence, Set from types import ModuleType from typing import Any, Dict, Iterator, List, Optional, Tuple, Union from typing_extensions import Buffer NodeBase = Dict[str, Union['Node', str]] PathStr = Union[str, os.PathLike[str]] else: NodeBase = dict if sys.version_info >= (3, 12): from importlib.resources.abc import Traversable, TraversableResources elif sys.version_info >= (3, 9): from importlib.abc import Traversable, TraversableResources else: class Traversable: pass class TraversableResources: pass MARKER = 'MESONPY_EDITABLE_SKIP' VERBOSE = 'MESONPY_EDITABLE_VERBOSE' class MesonpyOrphan(Traversable): def __init__(self, name: str): self._name = name @property def name(self) -> str: return self._name def is_dir(self) -> bool: return False def is_file(self) -> bool: return False def iterdir(self) -> Iterator[Traversable]: raise FileNotFoundError() def open(self, *args, **kwargs): # type: ignore raise FileNotFoundError() def joinpath(self, *descendants: PathStr) -> Traversable: if not descendants: return self name = os.fspath(descendants[-1]).split('/')[-1] return MesonpyOrphan(name) def __truediv__(self, child: PathStr) -> Traversable: return self.joinpath(child) def read_bytes(self) -> bytes: raise FileNotFoundError() def read_text(self, encoding: Optional[str] = None) -> str: raise FileNotFoundError() class MesonpyTraversable(Traversable): def __init__(self, name: str, tree: Node): self._name = name self._tree = tree @property def name(self) -> str: return self._name def is_dir(self) -> bool: return True def is_file(self) -> bool: return False def iterdir(self) -> Iterator[Traversable]: for name, node in self._tree.items(): yield MesonpyTraversable(name, node) if isinstance(node, dict) else pathlib.Path(node) # type: ignore def open(self, *args, **kwargs): # type: ignore raise IsADirectoryError() @staticmethod def _flatten(names: Tuple[PathStr, ...]) -> Iterator[str]: for name in names: yield from os.fspath(name).split('/') def joinpath(self, *descendants: PathStr) -> Traversable: if not descendants: return self names = self._flatten(descendants) name = next(names) node = self._tree.get(name) if isinstance(node, dict): return MesonpyTraversable(name, node).joinpath(*names) if isinstance(node, str): return pathlib.Path(node).joinpath(*names) return MesonpyOrphan(name).joinpath(*names) def __truediv__(self, child: PathStr) -> Traversable: return self.joinpath(child) def read_bytes(self) -> bytes: raise IsADirectoryError() def read_text(self, encoding: Optional[str] = None) -> str: raise IsADirectoryError() class MesonpyReader(TraversableResources): def __init__(self, name: str, tree: Node): self._name = name self._tree = tree def files(self) -> Traversable: return MesonpyTraversable(self._name, self._tree) class ExtensionFileLoader(importlib.machinery.ExtensionFileLoader): def __init__(self, name: str, path: str, tree: Node): super().__init__(name, path) self._tree = tree def get_resource_reader(self, name: str) -> TraversableResources: return MesonpyReader(name, self._tree) class SourceFileLoader(importlib.machinery.SourceFileLoader): def __init__(self, name: str, path: str, tree: Node): super().__init__(name, path) self._tree = tree def set_data(self, path: Union[bytes, str], data: Buffer, *, _mode: int = ...) -> None: # disable saving bytecode pass def get_resource_reader(self, name: str) -> TraversableResources: return MesonpyReader(name, self._tree) class SourcelessFileLoader(importlib.machinery.SourcelessFileLoader): def __init__(self, name: str, path: str, tree: Node): super().__init__(name, path) self._tree = tree def get_resource_reader(self, name: str) -> TraversableResources: return MesonpyReader(name, self._tree) LOADERS = \ [(ExtensionFileLoader, s) for s in importlib.machinery.EXTENSION_SUFFIXES] + \ [(SourceFileLoader, s) for s in importlib.machinery.SOURCE_SUFFIXES] + \ [(SourcelessFileLoader, s) for s in importlib.machinery.BYTECODE_SUFFIXES] def build_module_spec(cls: type, name: str, path: str, tree: Optional[Node]) -> importlib.machinery.ModuleSpec: loader = cls(name, path, tree) spec = importlib.machinery.ModuleSpec(name, loader, origin=path) spec.has_location = True if loader.is_package(name): spec.submodule_search_locations = [os.path.join(__file__, name)] return spec class Node(NodeBase): """Tree structure to store a virtual filesystem view.""" def __missing__(self, key: str) -> Node: value = self[key] = Node() return value def __setitem__(self, key: Union[str, Tuple[str, ...]], value: Union[Node, str]) -> None: node = self if isinstance(key, tuple): for k in key[:-1]: node = typing.cast(Node, node[k]) key = key[-1] dict.__setitem__(node, key, value) def __getitem__(self, key: Union[str, Tuple[str, ...]]) -> Union[Node, str]: node = self if isinstance(key, tuple): for k in key[:-1]: node = typing.cast(Node, node[k]) key = key[-1] return dict.__getitem__(node, key) def get(self, key: Union[str, Tuple[str, ...]]) -> Optional[Union[Node, str]]: # type: ignore[override] node = self if isinstance(key, tuple): for k in key[:-1]: v = dict.get(node, k) if v is None: return None node = typing.cast(Node, v) key = key[-1] return dict.get(node, key) def walk(src: str, exclude_files: Set[str], exclude_dirs: Set[str]) -> Iterator[str]: for root, dirnames, filenames in os.walk(src): for name in dirnames.copy(): dirsrc = os.path.join(root, name) relpath = os.path.relpath(dirsrc, src) if relpath in exclude_dirs: dirnames.remove(name) # sort to process directories determninistically dirnames.sort() for name in sorted(filenames): filesrc = os.path.join(root, name) relpath = os.path.relpath(filesrc, src) if relpath in exclude_files: continue yield relpath def collect(install_plan: Dict[str, Dict[str, Any]]) -> Node: tree = Node() for key, data in install_plan.items(): for src, target in data.items(): path = pathlib.Path(target['destination']) if path.parts[0] in {'{py_platlib}', '{py_purelib}'}: if key == 'install_subdirs' or key == 'targets' and os.path.isdir(src): exclude_files = {os.path.normpath(x) for x in target.get('exclude_files', [])} exclude_dirs = {os.path.normpath(x) for x in target.get('exclude_dirs', [])} for entry in walk(src, exclude_files, exclude_dirs): tree[(*path.parts[1:], *entry.split(os.sep))] = os.path.join(src, entry) else: tree[path.parts[1:]] = src return tree def find_spec(fullname: str, tree: Node) -> Optional[importlib.machinery.ModuleSpec]: namespace = False parts = fullname.split('.') # look for a package package = tree.get(tuple(parts)) if isinstance(package, Node): for loader, suffix in LOADERS: src = package.get('__init__' + suffix) if isinstance(src, str): return build_module_spec(loader, fullname, src, package) else: namespace = True # look for a module for loader, suffix in LOADERS: src = tree.get((*parts[:-1], parts[-1] + suffix)) if isinstance(src, str): return build_module_spec(loader, fullname, src, None) # namespace if namespace: spec = importlib.machinery.ModuleSpec(fullname, None, is_package=True) assert isinstance(spec.submodule_search_locations, list) # make mypy happy spec.submodule_search_locations.append(os.path.join(__file__, fullname)) return spec return None class MesonpyMetaFinder(importlib.abc.MetaPathFinder): def __init__(self, package: str, names: Set[str], path: str, cmd: List[str], verbose: bool = False): self._name = package self._top_level_modules = names self._build_path = path self._build_cmd = cmd self._verbose = verbose self._loaders: List[Tuple[type, str]] = [] def __repr__(self) -> str: return f'{self.__class__.__name__}({self._name!r}, {self._build_path!r})' def find_spec( self, fullname: str, path: Optional[Sequence[Union[bytes, str]]] = None, target: Optional[ModuleType] = None ) -> Optional[importlib.machinery.ModuleSpec]: if fullname.split('.', 1)[0] not in self._top_level_modules: return None if self._build_path in os.environ.get(MARKER, '').split(os.pathsep): return None tree = self._rebuild() return find_spec(fullname, tree) def _work_to_do(self, env: dict[str, str]) -> bool: if sys.platform == 'win32': # On Windows the build command is 'meson compile' eventually with a --ninja-args= option. if self._build_cmd[-1].startswith('--ninja-args='): ninja_args = ast.literal_eval(self._build_cmd[-1].split('=', 1)[1]) + ['-n'] dry_run_build_cmd = self._build_cmd[:-1] + [f'--ninja-args={ninja_args!r}'] else: dry_run_build_cmd = self._build_cmd + ['--ninja-args=-n'] else: dry_run_build_cmd = self._build_cmd + ['-n'] # Check adapted from # https://github.com/mesonbuild/meson/blob/a35d4d368a21f4b70afa3195da4d6292a649cb4c/mesonbuild/mtest.py#L1635-L1636 p = subprocess.run(dry_run_build_cmd, cwd=self._build_path, env=env, capture_output=True) return b'ninja: no work to do.' not in p.stdout and b'samu: nothing to do' not in p.stdout @functools.lru_cache(maxsize=1) def _rebuild(self) -> Node: # skip editable wheel lookup during rebuild: during the build # the module we are rebuilding might be imported causing a # rebuild loop. env = os.environ.copy() env[MARKER] = os.pathsep.join((env.get(MARKER, ''), self._build_path)) if self._verbose or bool(env.get(VERBOSE, '')): # We want to show some output only if there is some work to do if self._work_to_do(env): build_command = ' '.join(self._build_cmd) print(f'meson-python: building {self._name}: {build_command}', flush=True) subprocess.run(self._build_cmd, cwd=self._build_path, env=env) else: subprocess.run(self._build_cmd, cwd=self._build_path, env=env, stdout=subprocess.DEVNULL) install_plan_path = os.path.join(self._build_path, 'meson-info', 'intro-install_plan.json') with open(install_plan_path, 'r', encoding='utf8') as f: install_plan = json.load(f) return collect(install_plan) def _path_hook(self, path: str) -> MesonpyPathFinder: if os.altsep: path.replace(os.altsep, os.sep) path, _, key = path.rpartition(os.sep) if path == __file__: tree = self._rebuild() node = tree.get(tuple(key.split('.'))) if isinstance(node, Node): return MesonpyPathFinder(node) raise ImportError class MesonpyPathFinder(importlib.abc.PathEntryFinder): def __init__(self, tree: Node): self._tree = tree def find_spec(self, fullname: str, target: Optional[ModuleType] = None) -> Optional[importlib.machinery.ModuleSpec]: return find_spec(fullname, self._tree) def iter_modules(self, prefix: str) -> Iterator[Tuple[str, bool]]: yielded = set() for name, node in self._tree.items(): modname = inspect.getmodulename(name) if modname == '__init__' or modname in yielded: continue if isinstance(node, Node): modname = name for _, suffix in LOADERS: src = node.get('__init__' + suffix) if isinstance(src, str): yielded.add(modname) yield prefix + modname, True elif modname and '.' not in modname: yielded.add(modname) yield prefix + modname, False def install(package: str, names: Set[str], path: str, cmd: List[str], verbose: bool) -> None: finder = MesonpyMetaFinder(package, names, path, cmd, verbose) sys.meta_path.insert(0, finder) sys.path_hooks.insert(0, finder._path_hook) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/mesonpy/_rpath.py0000644000000000000000000000420514607715450014601 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import os import subprocess import sys import typing if typing.TYPE_CHECKING: from typing import List from mesonpy._compat import Iterable, Path if sys.platform == 'linux': def _get_rpath(filepath: Path) -> List[str]: r = subprocess.run(['patchelf', '--print-rpath', os.fspath(filepath)], capture_output=True, text=True) return r.stdout.strip().split(':') def _set_rpath(filepath: Path, rpath: Iterable[str]) -> None: subprocess.run(['patchelf','--set-rpath', ':'.join(rpath), os.fspath(filepath)], check=True) def fix_rpath(filepath: Path, libs_relative_path: str) -> None: old_rpath = _get_rpath(filepath) new_rpath = [] for path in old_rpath: if path.startswith('$ORIGIN/'): path = '$ORIGIN/' + libs_relative_path new_rpath.append(path) if new_rpath != old_rpath: _set_rpath(filepath, new_rpath) elif sys.platform == 'darwin': def _get_rpath(filepath: Path) -> List[str]: rpath = [] r = subprocess.run(['otool', '-l', os.fspath(filepath)], capture_output=True, text=True) rpath_tag = False for line in [x.split() for x in r.stdout.split('\n')]: if line == ['cmd', 'LC_RPATH']: rpath_tag = True elif len(line) >= 2 and line[0] == 'path' and rpath_tag: rpath.append(line[1]) rpath_tag = False return rpath def _replace_rpath(filepath: Path, old: str, new: str) -> None: subprocess.run(['install_name_tool', '-rpath', old, new, os.fspath(filepath)], check=True) def fix_rpath(filepath: Path, libs_relative_path: str) -> None: for path in _get_rpath(filepath): if path.startswith('@loader_path/'): _replace_rpath(filepath, path, '@loader_path/' + libs_relative_path) else: def fix_rpath(filepath: Path, libs_relative_path: str) -> None: raise NotImplementedError(f'Bundling libraries in wheel is not supported on {sys.platform}') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/mesonpy/_tags.py0000644000000000000000000001476214607715450014432 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import os import platform import sys import sysconfig import typing if typing.TYPE_CHECKING: # pragma: no cover from typing import Optional, Union # https://peps.python.org/pep-0425/#python-tag INTERPRETERS = { 'python': 'py', 'cpython': 'cp', 'pypy': 'pp', 'ironpython': 'ip', 'jython': 'jy', } _32_BIT_INTERPRETER = sys.maxsize <= 2**32 def get_interpreter_tag() -> str: name = sys.implementation.name name = INTERPRETERS.get(name, name) version = sys.version_info return f'{name}{version[0]}{version[1]}' def _get_config_var(name: str, default: Union[str, int, None] = None) -> Union[str, int, None]: value: Union[str, int, None] = sysconfig.get_config_var(name) if value is None: return default return value def _get_cpython_abi() -> str: version = sys.version_info debug = pymalloc = '' if _get_config_var('Py_DEBUG', hasattr(sys, 'gettotalrefcount')): debug = 'd' if version < (3, 8) and _get_config_var('WITH_PYMALLOC', True): pymalloc = 'm' return f'cp{version[0]}{version[1]}{debug}{pymalloc}' def get_abi_tag() -> str: # The best solution to obtain the Python ABI is to parse the # $SOABI or $EXT_SUFFIX sysconfig variables as defined in PEP-314. # PyPy reports a $SOABI that does not agree with $EXT_SUFFIX. # Using $EXT_SUFFIX will not break when PyPy will fix this. # See https://foss.heptapod.net/pypy/pypy/-/issues/3816 and # https://github.com/pypa/packaging/pull/607. try: empty, abi, ext = str(sysconfig.get_config_var('EXT_SUFFIX')).split('.') except ValueError as exc: # CPython <= 3.8.7 on Windows does not implement PEP3149 and # uses '.pyd' as $EXT_SUFFIX, which does not allow to extract # the interpreter ABI. Check that the fallback is not hit for # any other Python implementation. if sys.implementation.name != 'cpython': raise NotImplementedError from exc return _get_cpython_abi() # The packaging module initially based his understanding of the # $SOABI variable on the inconsistent value reported by PyPy, and # did not strip architecture information from it. Therefore the # ABI tag for later Python implementations (all the ones not # explicitly handled below) contains architecture information too. # Unfortunately, fixing this now would break compatibility. if abi.startswith('cpython'): abi = 'cp' + abi.split('-')[1] elif abi.startswith('cp'): abi = abi.split('-')[0] elif abi.startswith('pypy'): abi = '_'.join(abi.split('-')[:2]) elif abi.startswith('graalpy'): abi = '_'.join(abi.split('-')[:3]) return abi.replace('.', '_').replace('-', '_') def _get_macosx_platform_tag() -> str: ver, _, arch = platform.mac_ver() # Override the architecture with the one provided in the # _PYTHON_HOST_PLATFORM environment variable. This environment # variable affects the sysconfig.get_platform() return value and # is used to cross-compile python extensions on macOS for a # different architecture. We base the platform tag computation on # platform.mac_ver() but respect the content of the environment # variable. try: arch = os.environ.get('_PYTHON_HOST_PLATFORM', '').split('-')[2] except IndexError: pass # Override the macOS version if one is provided via the # MACOSX_DEPLOYMENT_TARGET environment variable. try: version = tuple(map(int, os.environ.get('MACOSX_DEPLOYMENT_TARGET', '').split('.')))[:2] except ValueError: version = tuple(map(int, ver.split('.')))[:2] # Python built with older macOS SDK on macOS 11, reports an # unexising macOS 10.16 version instead of the real version. # # The packaging module introduced a workaround # https://github.com/pypa/packaging/commit/67c4a2820c549070bbfc4bfbf5e2a250075048da # # This results in packaging versions up to 21.3 generating # platform tags like "macosx_10_16_x86_64" and later versions # generating "macosx_11_0_x86_64". Using the latter would be more # correct but prevents the resulting wheel from being installed on # systems using packaging 21.3 or earlier (pip 22.3 or earlier). # # Fortunately packaging versions carrying the workaround still # accepts "macosx_10_16_x86_64" as a compatible platform tag. We # can therefore ignore the issue and generate the slightly # incorrect tag. # The minimum macOS ABI version on arm64 is 11.0. The macOS SDK # on arm64 silently bumps any compatibility version specified via # the MACOSX_DEPLOYMENT_TARGET environment variable to 11.0. # Despite the platform ABI tag being intended to be a minimum # compatibility version, pip refuses to install wheels with a # platform tag specifying an ABI version lower than 11.0. Use # 11.0 as minimum ABI version on arm64. if arch == 'arm64' and version < (11, 0): version = (11, 0) major, minor = version if major >= 11: # For macOS reelases up to 10.15, the major version number is # actually part of the OS name and the minor version is the # actual OS release. Starting with macOS 11, the major # version number is the OS release and the minor version is # the patch level. Reset the patch level to zero. minor = 0 if _32_BIT_INTERPRETER: # 32-bit Python running on a 64-bit kernel. if arch == 'ppc64': arch = 'ppc' if arch == 'x86_64': arch = 'i386' return f'macosx_{major}_{minor}_{arch}' def get_platform_tag() -> str: platform = sysconfig.get_platform() if platform.startswith('macosx'): return _get_macosx_platform_tag() if _32_BIT_INTERPRETER: # 32-bit Python running on a 64-bit kernel. if platform == 'linux-x86_64': return 'linux_i686' if platform == 'linux-aarch64': return 'linux_armv7l' return platform.replace('-', '_').replace('.', '_').lower() class Tag: def __init__(self, interpreter: Optional[str] = None, abi: Optional[str] = None, platform: Optional[str] = None): self.interpreter = interpreter or get_interpreter_tag() self.abi = abi or get_abi_tag() self.platform = platform or get_platform_tag() def __str__(self) -> str: return f'{self.interpreter}-{self.abi}-{self.platform}' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/mesonpy/_util.py0000644000000000000000000000324314607715450014441 0ustar00# SPDX-FileCopyrightText: 2021 Filipe Laíns # SPDX-FileCopyrightText: 2021 Quansight, LLC # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import contextlib import gzip import os import tarfile import typing from typing import IO if typing.TYPE_CHECKING: # pragma: no cover from mesonpy._compat import Iterator, Path @contextlib.contextmanager def chdir(path: Path) -> Iterator[Path]: """Context manager helper to change the current working directory -- cd.""" old_cwd = os.getcwd() os.chdir(os.fspath(path)) try: yield path finally: os.chdir(old_cwd) @contextlib.contextmanager def create_targz(path: Path) -> Iterator[tarfile.TarFile]: """Opens a .tar.gz file in the file system for edition..""" os.makedirs(os.path.dirname(path), exist_ok=True) file = typing.cast(IO[bytes], gzip.GzipFile( path, mode='wb', )) tar = tarfile.TarFile( mode='w', fileobj=file, format=tarfile.PAX_FORMAT, # changed in 3.8 to GNU ) with contextlib.closing(file), tar: yield tar def setup_windows_console() -> bool: from ctypes import byref, windll # type: ignore from ctypes.wintypes import DWORD STD_OUTPUT_HANDLE = -11 ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x04 kernel = windll.kernel32 stdout = kernel.GetStdHandle(STD_OUTPUT_HANDLE) mode = DWORD() if not kernel.GetConsoleMode(stdout, byref(mode)): return False if not kernel.SetConsoleMode(stdout, mode.value | ENABLE_VIRTUAL_TERMINAL_PROCESSING): return False return True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/mesonpy/_wheelfile.py0000644000000000000000000001030114607715450015421 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import base64 import csv import hashlib import io import os import re import stat import time import typing import zipfile if typing.TYPE_CHECKING: # pragma: no cover from types import TracebackType from typing import List, Optional, Tuple, Type, Union from mesonpy._compat import Path MIN_TIMESTAMP = 315532800 # 1980-01-01 00:00:00 UTC WHEEL_FILENAME_REGEX = re.compile(r'^(?P[^-]+)-(?P[^-]+)(:?-(?P[^-]+))?-(?P[^-]+-[^-]+-[^-]+).whl$') def _b64encode(data: bytes) -> bytes: return base64.urlsafe_b64encode(data).rstrip(b'=') class WheelFile: """Implement the wheel package binary distribution format. https://packaging.python.org/en/latest/specifications/binary-distribution-format/ """ def __new__(cls, filename: Path, mode: str = 'r', compression: int = zipfile.ZIP_DEFLATED) -> 'WheelFile': if mode == 'w': return super().__new__(WheelFileWriter) raise NotImplementedError @staticmethod def timestamp(mtime: Optional[float] = None) -> Tuple[int, int, int, int, int, int]: timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', mtime or time.time())) # The ZIP file format does not support timestamps before 1980. timestamp = max(timestamp, MIN_TIMESTAMP) return time.gmtime(timestamp)[0:6] @staticmethod def hash(data: bytes) -> str: return 'sha256=' + _b64encode(hashlib.sha256(data).digest()).decode('ascii') def writestr(self, zinfo_or_arcname: Union[str, zipfile.ZipInfo], data: bytes) -> None: raise NotImplementedError def write(self, filename: Path, arcname: Optional[str] = None) -> None: raise NotImplementedError def close(self) -> None: raise NotImplementedError def __enter__(self) -> WheelFile: return self def __exit__(self, exc_type: Type[BaseException], exc_val: BaseException, exc_tb: TracebackType) -> None: self.close() class WheelFileWriter(WheelFile): def __init__(self, filepath: Path, mode: str, compression: int = zipfile.ZIP_DEFLATED): filename = os.path.basename(filepath) match = WHEEL_FILENAME_REGEX.match(filename) if not match: raise ValueError(f'invalid wheel filename: {filename!r}') self.name = match.group('name') self.version = match.group('version') self.entries: List[Tuple[str, str, int]] = [] self.archive = zipfile.ZipFile(filepath, mode='w', compression=compression, allowZip64=True) def writestr(self, zinfo_or_arcname: Union[str, zipfile.ZipInfo], data: bytes) -> None: if isinstance(data, str): data = data.encode('utf-8') if isinstance(zinfo_or_arcname, zipfile.ZipInfo): zinfo = zinfo_or_arcname else: zinfo = zipfile.ZipInfo(zinfo_or_arcname, date_time=self.timestamp()) zinfo.external_attr = 0o664 << 16 self.archive.writestr( zinfo, data, compress_type=self.archive.compression, compresslevel=self.archive.compresslevel) self.entries.append((zinfo.filename, self.hash(data), len(data))) def write(self, filename: Path, arcname: Optional[str] = None) -> None: with open(filename, 'rb') as f: st = os.fstat(f.fileno()) data = f.read() zinfo = zipfile.ZipInfo(arcname or str(filename), date_time=self.timestamp(st.st_mtime)) zinfo.external_attr = (stat.S_IMODE(st.st_mode) | stat.S_IFMT(st.st_mode)) << 16 self.writestr(zinfo, data) def close(self) -> None: record = f'{self.name}-{self.version}.dist-info/RECORD' data = io.StringIO() writer = csv.writer(data, delimiter=',', quotechar='"', lineterminator='\n') writer.writerows(self.entries) writer.writerow((record, '', '')) zi = zipfile.ZipInfo(record, date_time=self.timestamp()) zi.external_attr = 0o664 << 16 self.archive.writestr( zi, data.getvalue(), compress_type=self.archive.compression, compresslevel=self.archive.compresslevel) self.archive.close() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/noxfile.py0000644000000000000000000000331514607715450013277 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import os.path import nox nox.options.sessions = ['docs', 'mypy', 'test'] nox.options.reuse_existing_virtualenvs = True @nox.session() def docs(session): """ Build the docs. Pass "serve" to serve. """ session.install('.[docs]') session.install('sphinx-autobuild') session.install('sphinxcontrib-spelling >= 7.0.0') session.chdir('docs') spelling_args = ('-b', 'spelling') sphinx_build_args = ('.', '_build') if not session.posargs: # run spell-checking session.run('sphinx-build', *spelling_args, *sphinx_build_args) # run normal build session.run('sphinx-build', *sphinx_build_args) else: if 'serve' in session.posargs: session.run('sphinx-autobuild', *sphinx_build_args) else: print('Unsupported argument to docs') @nox.session(python='3.7') def mypy(session): session.install('mypy==0.991') session.run('mypy', '-p', 'mesonpy') @nox.session(python=['3.7', '3.8', '3.9', '3.10', '3.11', 'pypy3.8', 'pypy3.9']) def test(session): htmlcov_output = os.path.join(session.virtualenv.location, 'htmlcov') xmlcov_output = os.path.join(session.virtualenv.location, f'coverage-{session.python}.xml') session.install('.[test]') # optional github actions integration if os.environ.get('GITHUB_ACTIONS') == 'true': session.install('pytest-github-actions-annotate-failures') session.run( 'pytest', '--showlocals', '-vv', '--cov', f'--cov-report=html:{htmlcov_output}', f'--cov-report=xml:{xmlcov_output}', *session.posargs ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/pyproject.toml0000644000000000000000000000527714607715450014206 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' backend-path = ['.'] requires = [ 'meson >= 0.63.3; python_version < "3.12"', 'meson >= 1.2.3; python_version >= "3.12"', 'packaging >= 19.0', 'pyproject-metadata >= 0.7.1', 'tomli >= 1.0.0; python_version < "3.11"', ] [project] name = 'meson-python' description = 'Meson Python build backend (PEP 517)' readme = 'README.rst' requires-python = '>= 3.7' license = { file = 'LICENSES/MIT.txt' } keywords = ['meson', 'build', 'backend', 'pep517', 'package'] maintainers = [ { name = 'Ralf Gommers', email = 'ralf.gommers@gmail.com' }, { name = 'Daniele Nicolodi', email = 'daniele@grinta.net' }, { name = 'Henry Schreiner', email = 'HenrySchreinerIII@gmail.com' }, { name = 'Thomas Li', email = '47963215+lithomas1@users.noreply.github.com' }, ] classifiers = [ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', 'Topic :: Software Development :: Build Tools', ] dependencies = [ 'meson >= 0.63.3; python_version < "3.12"', 'meson >= 1.2.3; python_version >= "3.12"', 'packaging >= 19.0', 'pyproject-metadata >= 0.7.1', 'tomli >= 1.0.0; python_version < "3.11"', ] dynamic = [ 'version', ] [project.optional-dependencies] test = [ 'build', 'pytest >= 6.0', 'pytest-cov[toml]', 'pytest-mock', 'cython >= 3.0.3', # required for Python 3.12 support 'wheel', 'typing-extensions >= 3.7.4; python_version < "3.11"', ] docs = [ 'furo >= 2023.5.20', 'sphinx ~= 6.2', 'sphinx-copybutton >= 0.5.0', 'sphinx-design >= 0.1.0', 'sphinxext-opengraph >= 0.7.0', ] [project.urls] homepage = 'https://github.com/mesonbuild/meson-python' repository = 'https://github.com/mesonbuild/meson-python' documentation = 'https://mesonbuild.com/meson-python/' changelog = 'https://mesonbuild.com/meson-python/changelog.html' [tool.mypy] show_error_codes = true ignore_missing_imports = true strict = true [tool.ruff] line-length = 127 extend-ignore = [ 'B019', ] select = [ 'B', # flake8-bugbear 'C4', # flake8-comprehensions 'E', # pycodestyle 'F', # pyflakes 'I', # isort 'W', # pycodestyle 'RUF100', # ruff ] exclude = [ 'docs/conf.py', ] [tool.ruff.lint.isort] lines-between-types = 1 lines-after-imports = 2 known-first-party = [ 'mesonpy', ] [tool.coverage.run] disable_warnings = [ 'couldnt-parse', ] [tool.coverage.html] show_contexts = true [tool.pytest.ini_options] minversion = '6.0' addopts = ['-ra', '--strict-markers', '--strict-config'] log_cli_level = 'info' norecursedirs = 'tests/packages/*' testpaths = ['tests'] xfail_strict = true filterwarnings = [ 'error', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/__init__.py0000644000000000000000000000013414607715450014530 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/conftest.py0000644000000000000000000001302614607715450014622 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import contextlib import os import os.path import pathlib import re import shutil import subprocess import sys import tempfile import warnings from venv import EnvBuilder import pytest import mesonpy from mesonpy._util import chdir def adjust_packaging_platform_tag(platform: str) -> str: if platform.startswith(('manylinux', 'musllinux')): # The packaging module generates overly specific platforms tags on # Linux. The platforms tags on Linux evolved over time. # meson-python uses more relaxed platform tags to maintain # compatibility with old wheel installation tools. The relaxed # platform tags match the ones generated by the wheel package. # https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/ return re.sub(r'^(many|musl)linux(1|2010|2014|_\d+_\d+)_(.*)$', r'linux_\3', platform) if platform.startswith('macosx'): # Python built with older macOS SDK on macOS 11, reports an # unexising macOS 10.16 version instead of the real version. # The packaging module introduced a workaround in version # 22.0. Too maintain compatibility with older packaging # releases we don't implement it. Reconcile this. from platform import mac_ver version = tuple(map(int, mac_ver()[0].split('.')))[:2] if version == (10, 16): return re.sub(r'^macosx_\d+_\d+_(.*)$', r'macosx_10_16_\1', platform) return platform package_dir = pathlib.Path(__file__).parent / 'packages' @contextlib.contextmanager def in_git_repo_context(path=os.path.curdir): # Resist the tentation of using pathlib.Path here: it is not # supporded by subprocess in Python 3.7. path = os.path.abspath(path) shutil.rmtree(os.path.join(path, '.git'), ignore_errors=True) try: subprocess.run(['git', 'init', '-b', 'main', path], check=True) subprocess.run(['git', 'config', 'user.email', 'author@example.com'], cwd=path, check=True) subprocess.run(['git', 'config', 'user.name', 'A U Thor'], cwd=path, check=True) subprocess.run(['git', 'add', '*'], cwd=path, check=True) subprocess.run(['git', 'commit', '-q', '-m', 'Test'], cwd=path, check=True) yield finally: # PermissionError raised on Windows. with contextlib.suppress(PermissionError): shutil.rmtree(os.path.join(path, '.git')) @pytest.fixture(scope='session') def tmp_path_session(tmp_path_factory): return pathlib.Path(tempfile.mkdtemp( prefix='mesonpy-test-', dir=tmp_path_factory.mktemp('test'), )) class VEnv(EnvBuilder): def __init__(self, env_dir): super().__init__(symlinks=True, with_pip=True) # This warning is mistakenly generated by CPython 3.11.0 # https://github.com/python/cpython/pull/98743 with warnings.catch_warnings(): if sys.version_info[:3] == (3, 11, 0): warnings.filterwarnings('ignore', 'check_home argument is deprecated and ignored.', DeprecationWarning) self.create(env_dir) def ensure_directories(self, env_dir): context = super().ensure_directories(env_dir) # Store the path to the venv Python interpreter. There does # not seem to be a way to do this without subclassing. self.executable = context.env_exe return context def python(self, *args: str): return subprocess.check_output([self.executable, *args]).decode() def pip(self, *args: str): return self.python('-m', 'pip', *args) @pytest.fixture() def venv(tmp_path_factory): path = pathlib.Path(tmp_path_factory.mktemp('mesonpy-test-venv')) return VEnv(path) def generate_package_fixture(package): @pytest.fixture def fixture(): with chdir(package_dir / package) as new_path: yield new_path return fixture def generate_sdist_fixture(package): @pytest.fixture(scope='session') def fixture(tmp_path_session): with chdir(package_dir / package), in_git_repo_context(): return tmp_path_session / mesonpy.build_sdist(tmp_path_session) return fixture def generate_wheel_fixture(package): @pytest.fixture(scope='session') def fixture(tmp_path_session): with chdir(package_dir / package), in_git_repo_context(): return tmp_path_session / mesonpy.build_wheel(tmp_path_session) return fixture def generate_editable_fixture(package): @pytest.fixture(scope='session') def fixture(tmp_path_session): shutil.rmtree(package_dir / package / '.mesonpy' / 'editable', ignore_errors=True) with chdir(package_dir / package), in_git_repo_context(): return tmp_path_session / mesonpy.build_editable(tmp_path_session) return fixture # inject {package,sdist,wheel}_* fixtures (https://github.com/pytest-dev/pytest/issues/2424) for package in os.listdir(package_dir): normalized = package.replace('-', '_') globals()[f'package_{normalized}'] = generate_package_fixture(package) globals()[f'sdist_{normalized}'] = generate_sdist_fixture(package) globals()[f'wheel_{normalized}'] = generate_wheel_fixture(package) globals()[f'editable_{normalized}'] = generate_editable_fixture(package) @pytest.fixture(autouse=True, scope='session') def disable_pip_version_check(): # Cannot use the 'monkeypatch' fixture because of scope mismatch. mpatch = pytest.MonkeyPatch() yield mpatch.setenv('PIP_DISABLE_PIP_VERSION_CHECK', '1') mpatch.undo() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/complex/__init__.py0000644000000000000000000000013414607715450021424 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/complex/more/__init__.py0000644000000000000000000000016714607715450022374 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def test(): return 44 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/complex/more/baz.pyx0000644000000000000000000000017114607715450021574 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def answer(): return 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/complex/more/meson.build0000644000000000000000000000027514607715450022425 0ustar00# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT py.extension_module( 'baz', 'baz.pyx', install: true, subdir: 'complex/more', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/complex/namespace/bar.py0000644000000000000000000000017114607715450022366 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def bar(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/complex/namespace/foo.py0000644000000000000000000000017114607715450022405 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'foo' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/foo.py0000644000000000000000000000017014607715450017001 0ustar00# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/meson.build0000644000000000000000000000216214607715450020011 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('complex', 'c', 'cython', version: '1.0.0') # Work around Python bug on mingw-w64, fixed in Python 3.12 # https://github.com/python/cpython/pull/100137 # The same work-around is also included in Meson 1.1.0 and later. if meson.version().version_compare('< 1.1') if host_machine.system() == 'windows' and meson.get_compiler('c').get_id() == 'gcc' add_project_arguments('-DMS_WIN64=', language: 'c') endif endif py = import('python').find_installation() py.install_sources( 'move.py', subdir: 'complex/more', pure: false, ) install_data( 'foo.py', rename: 'bar.py', install_dir: py.get_install_dir(pure: false) / 'complex', ) install_subdir( 'complex', install_dir: py.get_install_dir(pure: false), exclude_files: ['more/meson.build', 'more/baz.pyx'], ) py.extension_module( 'test', 'test.pyx', install: true, subdir: 'complex', ) py.extension_module( 'baz', 'complex/more/baz.pyx', install: true, subdir: 'complex/more', ) subdir('complex/more') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/move.py0000644000000000000000000000017114607715450017165 0ustar00# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT def test(): return True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/pyproject.toml0000644000000000000000000000024214607715450020560 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/complex/test.pyx0000644000000000000000000000017114607715450017366 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def answer(): return 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/configure-data/configure_data.py.in0000644000000000000000000000021314607715450023014 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def message(): return 'meson says: @MSG@' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/configure-data/meson.build0000644000000000000000000000055414607715450021235 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('configure-data', version: '1.0.0') py = import('python').find_installation() configure_file( input: 'configure_data.py.in', output: 'configure_data.py', configuration: configuration_data({'MSG': 'hello!'}), install_dir: py.get_install_dir(), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/configure-data/pyproject.toml0000644000000000000000000000024214607715450022001 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/custom-target-dir/codegen.py0000644000000000000000000000047614607715450021536 0ustar00#!/usr/bin/env python3 # # SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT import os import sys outdir = os.path.join(sys.argv[1], 'generated') os.makedirs(outdir, exist_ok=True) for name in 'one.py', 'two.py': with open(os.path.join(outdir, name), 'w'): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/custom-target-dir/meson.build0000644000000000000000000000052114607715450021711 0ustar00# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT project('custom-target-dir', version: '1.0.0') py = import('python').find_installation() custom_target( command: ['codegen.py', '@OUTDIR@'], output: 'generated', install: true, install_dir: py.get_install_dir() / 'package', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/custom-target-dir/pyproject.toml0000644000000000000000000000024214607715450022463 0ustar00# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/detect-compiler/detect_compiler.c0000644000000000000000000000133414607715450022566 0ustar00// SPDX-FileCopyrightText: 2023 The meson-python developers // // SPDX-License-Identifier: MIT #include #if defined _MSC_VER # define _COMPILER "msvc" #elif defined __clang__ # define _COMPILER "clang" #elif defined __GNUC__ # define _COMPILER "gcc" #else # define _COMPILER "unknown" #endif static PyObject* compiler(PyObject* self) { return PyUnicode_FromString(_COMPILER); } static PyMethodDef methods[] = { {"compiler", (PyCFunction)compiler, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "detect_compiler", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_detect_compiler(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/detect-compiler/meson.build0000644000000000000000000000040414607715450021417 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('detect-compiler', 'c', version: '1.0') py = import('python').find_installation() py.extension_module('detect_compiler', 'detect_compiler.c', install: true) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/detect-compiler/pyproject.toml0000644000000000000000000000024214607715450022171 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/dist-script/meson.build0000644000000000000000000000024614607715450020610 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('dist-script', 'c', version: '1.0.0') meson.add_dist_script('') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/dist-script/pyproject.toml0000644000000000000000000000024214607715450021356 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/dynamic-version/meson.build0000644000000000000000000000021214607715450021443 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('dynamic-version', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/dynamic-version/pyproject.toml0000644000000000000000000000034314607715450022222 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'dynamic-version' dynamic = [ 'version', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/encoding/meson.build0000644000000000000000000000032214607715450020124 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('encoding', version: '1.0.0') py = import('python').find_installation() py.install_sources('テスト.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/encoding/pyproject.toml0000644000000000000000000000024214607715450020677 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000012700000000000010215 xustar0065 path=meson_python-0.16.0/tests/packages/encoding/テスト.py 22 mtime=1713347368.0 meson_python-0.16.0/tests/packages/encoding/???.py0000644000000000000000000000013414607715450016711 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/executable/example.c0000644000000000000000000000022614607715450020117 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/executable/meson.build0000644000000000000000000000031414607715450020460 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('executable', 'c', version: '1.0.0') executable( 'example', 'example.c', install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/executable/pyproject.toml0000644000000000000000000000024214607715450021232 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/executable-bit/example-script.py0000755000000000000000000000016714607715450022412 0ustar00#!python # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT print('hello!') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/executable-bit/example.c0000644000000000000000000000022614607715450020673 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/executable-bit/executable_module.py0000755000000000000000000000025714607715450023143 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' if __name__ == '__main__': print('foo?', foo()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/executable-bit/meson.build0000644000000000000000000000062614607715450021242 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('executable-bit', 'c', version: '1.0.0') py = import('python').find_installation() executable( 'example', 'example.c', install: true, ) install_data( 'example-script.py', rename: 'example-script', install_dir: get_option('bindir'), ) py.install_sources('executable_module.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/executable-bit/pyproject.toml0000644000000000000000000000024214607715450022006 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/full-metadata/LICENSE0000644000000000000000000000001514607715450017720 0ustar00some license ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/full-metadata/README.md0000644000000000000000000000024714607715450020201 0ustar00 # full-metadata An example package with all of the PEP 621 metadata! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/full-metadata/meson.build0000644000000000000000000000021014607715450021052 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('full-metadata', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/full-metadata/pyproject.toml0000644000000000000000000000217614607715450021641 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'full-metadata' version = '1.2.3' description = 'Some package with all of the PEP 621 metadata' readme = 'README.md' requires-python = '>=3.7' license = {file = 'LICENSE'} keywords = ['full', 'metadata'] authors = [ {email = 'jhon.doe@example.com'}, {name = 'Jane Doe'} ] maintainers = [ {name = 'Jane Doe', email = 'jane.doe@example.com'} ] classifiers = [ 'Development Status :: 4 - Beta', 'Programming Language :: Python', ] dependencies = [ 'a', 'b > 1', 'c > 2; os_name != "nt"', ] [project.optional-dependencies] test = [ 'd < 3', 'e[all]' ] [project.urls] homepage = 'https://example.com' documentation = 'https://readthedocs.org' repository = 'https://github.com/mesonbuild/meson-python' changelog = 'https://github.com/mesonbuild/meson-python/blob/master/CHANGELOG.rst' [project.scripts] example-cli = 'example:cli' [project.gui-scripts] example-gui = 'example:gui' [project.entry-points.'something.custom'] example = 'example:custom' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/generated-files/example-script.py0000755000000000000000000000016714607715450022553 0ustar00#!python # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT print('hello!') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/generated-files/example.c0000644000000000000000000000022614607715450021034 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/generated-files/executable_module.py0000755000000000000000000000025714607715450023304 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' if __name__ == '__main__': print('foo?', foo()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/generated-files/generate_version.py0000644000000000000000000000171014607715450023145 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import argparse import os def write_version_info(path): # A real project would call something to generate this dummy_version = '1.0.0' dummy_hash = '013j2fiejqea' if os.environ.get('MESON_DIST_ROOT'): path = os.path.join(os.environ.get('MESON_DIST_ROOT'), path) with open(path, 'w') as file: file.write(f'__version__="{dummy_version}"\n') file.write( f'__git_version__="{dummy_hash}"\n' ) def main(): parser = argparse.ArgumentParser() parser.add_argument( '-o', '--outfile', type=str, help='Path to write version info to' ) args = parser.parse_args() if not args.outfile.endswith('.py'): raise ValueError( f'Output file must be a Python file. ' f'Got: {args.outfile} as filename instead' ) write_version_info(args.outfile) main() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/generated-files/meson.build0000644000000000000000000000162514607715450021403 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('executable-bit', 'c', version: '1.0.0') fs = import('fs') py = import('python').find_installation() executable( 'example', 'example.c', install: true, ) install_data( 'example-script.py', rename: 'example-script', install_dir: get_option('bindir'), ) py.install_sources('executable_module.py') version_gen = files('generate_version.py') if fs.exists('_version_meson.py') py.install_sources('_version_meson.py') else custom_target( 'write_version_file', output: '_version_meson.py', command: [py, version_gen, '-o', '@OUTPUT@'], build_by_default: true, build_always_stale: true, install: true, install_dir: py.get_install_dir(pure: false), ) meson.add_dist_script(py, version_gen, '-o', '_version_meson.py') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/generated-files/pyproject.toml0000644000000000000000000000024214607715450022147 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/imports-itself-during-build/meson.build0000644000000000000000000000053614607715450023711 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('imports-itself-during-build', 'c', version: '1.0.0') py = import('python').find_installation() py.install_sources('pure.py') py.extension_module( 'plat', 'plat.c', install: true, ) run_command(py, '-c', 'import pure', check: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/imports-itself-during-build/plat.c0000644000000000000000000000076514607715450022657 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* data(PyObject* self) { return PyUnicode_FromString("ABC"); } static PyMethodDef methods[] = { {"data", (PyCFunction)data, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "plat", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_plat(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/imports-itself-during-build/pure.py0000644000000000000000000000017114607715450023067 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/imports-itself-during-build/pyproject.toml0000644000000000000000000000024214607715450024455 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/meson.build0000644000000000000000000000111214607715450021270 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('install-subdir', version: '1.0.0') py = import('python').find_installation() install_subdir( 'subdir', exclude_files: 'excluded.py', exclude_directories: 'excluded', install_dir: py.get_install_dir(pure: false), ) install_subdir( 'strip', strip_directory: true, exclude_files: 'excluded.py', install_dir: py.get_install_dir(pure: false) / 'test', ) install_subdir( 'nested', exclude_files: 'deep/excluded.py', install_dir: py.get_install_dir(pure: false), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/nested/deep/deep.py0000644000000000000000000000013414607715450022617 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/nested/deep/excluded.py0000644000000000000000000000013414607715450023477 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/nested/nested.py0000644000000000000000000000013414607715450022247 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/pyproject.toml0000644000000000000000000000024214607715450022045 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/strip/excluded.py0000644000000000000000000000013414607715450022441 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/strip/module.py0000644000000000000000000000013414607715450022131 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/subdir/__init__.py0000644000000000000000000000013414607715450022532 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/subdir/excluded/__init__.py0000644000000000000000000000013414607715450024327 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/subdir/excluded.py0000644000000000000000000000013414607715450022570 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/install-subdir/subdir/test.py0000644000000000000000000000013414607715450021752 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/library/example.c0000644000000000000000000000026614607715450017446 0ustar00// SPDX-FileCopyrightText: 2021 The meson-python developers // // SPDX-License-Identifier: MIT #include int sum(int, int); int main() { printf("sum: %d", sum(1, 2)); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/library/examplelib.c0000644000000000000000000000021114607715450020123 0ustar00// SPDX-FileCopyrightText: 2021 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b) { return a + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/library/examplelib.h0000644000000000000000000000016714607715450020142 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/library/meson.build0000644000000000000000000000053514607715450020010 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('library', 'c', version: '1.0.0') install_headers('examplelib.h') example_lib = shared_library( 'example', 'examplelib.c', install: true, ) executable( 'example', 'example.c', link_with: example_lib, install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/library/pyproject.toml0000644000000000000000000000024214607715450020555 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/license-file/meson.build0000644000000000000000000000020714607715450020677 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('license-file', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/license-file/pyproject.toml0000644000000000000000000000040514607715450021451 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'license-file' version = '1.0.0' license = { file = 'something/LICENSE.custom' } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/license-file/something/LICENSE.custom0000644000000000000000000000000714607715450023046 0ustar00Hello! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/limited-api/meson.build0000644000000000000000000000060314607715450020536 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('limited-api', 'c', version: '1.0.0') py = import('python').find_installation(pure: false) py.extension_module( 'module', 'module.c', limited_api: '3.7', install: true, ) if get_option('extra') py.extension_module( 'extra', 'module.c', install: true, ) endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/limited-api/meson.options0000644000000000000000000000021414607715450021130 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT option('extra', type: 'boolean', value: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/limited-api/module.c0000644000000000000000000000110714607715450020025 0ustar00// SPDX-FileCopyrightText: 2023 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* add(PyObject *self, PyObject *args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) return NULL; return PyLong_FromLong(a + b); } static PyMethodDef methods[] = { {"add", add, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "plat", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_module(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/limited-api/pyproject.toml0000644000000000000000000000031214607715450021305 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python] limited-api = true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/link-against-local-lib/examplemod.c0000644000000000000000000000126314607715450022715 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include #include "lib/examplelib.h" static PyObject* example_sum(PyObject* self, PyObject *args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } long result = sum(a, b); return PyLong_FromLong(result); } static PyMethodDef methods[] = { {"example_sum", (PyCFunction)example_sum, METH_VARARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "example", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_example(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/link-against-local-lib/lib/examplelib.c0000644000000000000000000000021114607715450023442 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b) { return a + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/link-against-local-lib/lib/examplelib.h0000644000000000000000000000016714607715450023461 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/link-against-local-lib/lib/meson.build0000644000000000000000000000026314607715450023325 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT example_lib = shared_library( 'example', 'examplelib.c', install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/link-against-local-lib/meson.build0000644000000000000000000000054614607715450022563 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('link-against-local-lib', 'c', version: '1.0.0') subdir('lib') py = import('python').find_installation() py.extension_module( 'example', 'examplemod.c', link_with: example_lib, link_args: ['-Wl,-rpath,custom-rpath'], install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/link-against-local-lib/pyproject.toml0000644000000000000000000000024214607715450023326 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/missing-dynamic-version/meson.build0000644000000000000000000000020014607715450023107 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('missing-dynamic-version') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/missing-dynamic-version/pyproject.toml0000644000000000000000000000034414607715450023672 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'missing-dynamic-version' dynamic = ['version'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/missing-meson-version/meson.build0000644000000000000000000000017614607715450022620 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('missing-meson-version') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/missing-meson-version/pyproject.toml0000644000000000000000000000024214607715450023364 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/missing-version/meson.build0000644000000000000000000000021214607715450021470 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('missing-version', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/missing-version/pyproject.toml0000644000000000000000000000030614607715450022246 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'missing-version' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/module-types/file.py0000644000000000000000000000013414607715450020115 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/module-types/meson.build0000644000000000000000000000066614607715450021000 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('module-types', 'c', version: '1.0.0') py = import('python').find_installation() py.install_sources('file.py') py.install_sources( 'package' / '__init__.py', subdir: 'package', ) py.install_sources( 'namespace' / 'data.py', subdir: 'namespace', ) py.extension_module( 'native', 'native.c', install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/module-types/namespace/data.py0000644000000000000000000000013414607715450022043 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/module-types/native.c0000644000000000000000000000076614607715450020271 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* foo(PyObject* self) { return PyUnicode_FromString("bar"); } static PyMethodDef methods[] = { {"foo", (PyCFunction)foo, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "native", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_native(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/module-types/package/__init__.py0000644000000000000000000000013414607715450022330 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/module-types/pyproject.toml0000644000000000000000000000024214607715450021540 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/pure/meson.build0000644000000000000000000000031114607715450017307 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('pure', version: '1.0.0') py = import('python').find_installation() py.install_sources('pure.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/pure/pure.py0000644000000000000000000000017114607715450016476 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/pure/pyproject.toml0000644000000000000000000000024214607715450020064 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/purelib-and-platlib/meson.build0000644000000000000000000000054114607715450022170 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('purelib-and-platlib', 'c', version: '1.0.0') py = import('python').find_installation() py.install_sources( 'pure.py', install_tag: 'purelib', ) py.extension_module( 'plat', 'plat.c', install: true, install_tag: 'platlib', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/purelib-and-platlib/plat.c0000644000000000000000000000076214607715450021137 0ustar00// SPDX-FileCopyrightText: 2021 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* foo(PyObject* self) { return PyUnicode_FromString("bar"); } static PyMethodDef methods[] = { {"foo", (PyCFunction)foo, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "plat", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_plat(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/purelib-and-platlib/pure.py0000644000000000000000000000017114607715450021352 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/purelib-and-platlib/pyproject.toml0000644000000000000000000000024214607715450022740 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/purelib-platlib-split/meson.build0000644000000000000000000000054214607715450022562 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('purelib-platlib-split', version: '1.0.0') py = import('python').find_installation() py.install_sources( 'pure.py', subdir: 'purelib-platlib-split', ) py.install_sources( 'plat.py', subdir: 'purelib-platlib-split', pure: false, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/purelib-platlib-split/plat.py0000644000000000000000000000017114607715450021730 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/purelib-platlib-split/pure.py0000644000000000000000000000017114607715450021743 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/purelib-platlib-split/pyproject.toml0000644000000000000000000000024214607715450023331 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/meson.build0000644000000000000000000000111714607715450020412 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('scipy-like', 'c', 'cython', version: '2.3.4') # Work around Python bug on mingw-w64, fixed in Python 3.12 # https://github.com/python/cpython/pull/100137 # The same work-around is also included in Meson 1.1.0 and later. if meson.version().version_compare('< 1.1') if host_machine.system() == 'windows' and meson.get_compiler('c').get_id() == 'gcc' add_project_arguments('-DMS_WIN64=', language: 'c') endif endif py = import('python').find_installation() subdir('mypkg') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/mypkg/__init__.py0000644000000000000000000000017114607715450021507 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/mypkg/cy_extmod.pyx0000644000000000000000000000025114607715450022132 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from libc.math cimport sin cdef double f(double x): return sin(x * x) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/mypkg/extmod.c0000644000000000000000000000076414607715450021052 0ustar00// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* foo(PyObject* self) { return PyUnicode_FromString("bar"); } static PyMethodDef methods[] = { {"foo", (PyCFunction)foo, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "extmod", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_plat(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/mypkg/meson.build0000644000000000000000000000153014607715450021540 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT generate_version = custom_target( 'generate-config-file', install: true, build_always_stale: true, build_by_default: true, output: '__config__.py', input: '../tools/generate_config.py', command: [py, '@INPUT@', '@OUTPUT@'], install_dir: py.get_install_dir(pure: false) / 'mypkg', ) py.extension_module( 'extmod', 'extmod.c', install: true, subdir: 'mypkg', ) py.extension_module( 'cy_extmod', 'cy_extmod.pyx', install: true, subdir: 'mypkg', ) py.install_sources( '__init__.py', pure: false, subdir: 'mypkg', ) # Still broken, see gh-105 and https://github.com/mesonbuild/meson/issues/10639 install_subdir( 'submod', install_dir: py.get_install_dir(pure: false) / 'mypkg', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/mypkg/submod/__init__.py0000644000000000000000000000013414607715450022777 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/mypkg/submod/unknown_filetype.npq0000644000000000000000000000027314607715450025012 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # Unknown file types (e.g. `.npy` or `.npz` data files) can be present in # a Python package. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/pyproject.toml0000644000000000000000000000040214607715450021160 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = "mypkg" description = "A typical Python package layout" dynamic = ['version'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/scipy-like/tools/generate_config.py0000644000000000000000000000033314607715450023100 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import sys from pathlib import Path outfile = Path(sys.argv[1]) outfile.write_text('# Some build-time configuration data') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/simple/__init__.py0000644000000000000000000000020214607715450017573 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT from .test import data # noqa: F401 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/simple/data.txt0000644000000000000000000000000414607715450017134 0ustar00ABC ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/simple/data.txt.license0000644000000000000000000000013414607715450020561 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/simple/meson.build0000644000000000000000000000037014607715450017632 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('simple', version: '1.0.0') py = import('python').find_installation() py.install_sources('__init__.py', 'test.py', 'data.txt', subdir: 'simple') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/simple/pyproject.toml0000644000000000000000000000024214607715450020402 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/simple/test.py0000644000000000000000000000034414607715450017022 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib def data(): with pathlib.Path(__file__).parent.joinpath('data.txt').open() as f: return f.read().rstrip() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subdirs/meson.build0000644000000000000000000000111214607715450020007 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('subdirs', version: '1.0.0') py = import('python').find_installation() # in Meson >= 0.64 this could be replace with a single # py.install_sources() with the 'preserve_path: true' argument. py.install_sources( 'subdirs/__init__.py', subdir: 'subdirs', ) py.install_sources( 'subdirs/a/__init__.py', subdir: 'subdirs/a', ) py.install_sources( 'subdirs/a/b/c.py', subdir: 'subdirs/a/b', ) py.install_sources( 'subdirs/b/c.py', subdir: 'subdirs/b', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subdirs/pyproject.toml0000644000000000000000000000024214607715450020564 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subdirs/subdirs/__init__.py0000644000000000000000000000013414607715450021434 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subdirs/subdirs/a/__init__.py0000644000000000000000000000013414607715450021654 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subdirs/subdirs/a/b/c.py0000644000000000000000000000013414607715450020560 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subdirs/subdirs/b/c.py0000644000000000000000000000013414607715450020340 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subproject/meson.build0000644000000000000000000000035014607715450020517 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('subproject', version: '1.0.0') subproject('dep') py = import('python').find_installation() py.install_sources('subproject.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subproject/pyproject.toml0000644000000000000000000000024214607715450021271 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subproject/subproject.py0000644000000000000000000000013414607715450021107 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subproject/subprojects/dep/dep.py0000644000000000000000000000013414607715450022612 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/subproject/subprojects/dep/meson.build0000644000000000000000000000026514607715450023637 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('dep') py = import('python').find_installation() py.install_sources('dep.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/unknown-user-args-meson-args/pyproject.toml0000644000000000000000000000031114607715450024564 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python.args] unknown = [] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/unknown-user-args-top-level/pyproject.toml0000644000000000000000000000030414607715450024422 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python] unknown = {} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/unsupported-python-version/meson.build0000644000000000000000000000022514607715450023732 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('unsupported-python-version', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/unsupported-python-version/pyproject.toml0000644000000000000000000000037714607715450024514 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'unsupported-python-version' version = '1.2.3' requires-python = '==1.0.0' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/user-args/meson.build0000644000000000000000000000031614607715450020251 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('user-args', version: '1.0.0') py = import('python').find_installation() py.install_sources('pure.py') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/user-args/pure.py0000644000000000000000000000017114607715450017433 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/user-args/pyproject.toml0000644000000000000000000000044614607715450021027 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python.args] dist = ['config-dist'] setup = ['config-setup'] compile = ['config-compile'] install = ['config-install'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/vendored-meson/meson.build0000644000000000000000000000044514607715450021271 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('vendored-meson', version: '1.0.0') py = import('python').find_installation() if not get_option('custom-meson-used') error('Expected option "custom-meson-used" was not specified') endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/vendored-meson/meson_options.txt0000644000000000000000000000023014607715450022554 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT option('custom-meson-used', type: 'boolean', value: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/vendored-meson/pyproject.toml0000644000000000000000000000032614607715450022041 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python] meson = 'third-party/meson.py' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/packages/vendored-meson/third-party/meson.py0000644000000000000000000000042014607715450023062 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT import sys from mesonbuild import mesonmain if 'setup' in sys.argv: sys.argv.append('-Dcustom-meson-used=true') if __name__ == '__main__': sys.exit(mesonmain.main()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_consistency.py0000644000000000000000000000135414607715450016376 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import sys if sys.version_info >= (3, 11): import tomllib else: import tomli as tomllib def test_pyproject_dependencies(): pyproject = pathlib.Path(__file__).parent.parent.joinpath('pyproject.toml') with open(pyproject, 'rb') as f: data = tomllib.load(f) build_dependencies = data['build-system']['requires'] project_dependencies = data['project']['dependencies'] # verify that all build dependencies are project dependencies assert not set(build_dependencies) - set(project_dependencies), \ 'pyproject.toml is inconsistent: not all "build-system.requires" are in "project.dependencies"' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_editable.py0000644000000000000000000002627514607715450015617 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import io import os import pathlib import pkgutil import sys from contextlib import redirect_stdout import pytest import mesonpy from mesonpy import _editable from .test_wheel import EXT_SUFFIX def test_walk(package_complex): entries = _editable.walk( os.fspath(package_complex / 'complex'), [os.path.normpath('more/meson.build'), os.path.normpath('more/baz.pyx')], [os.path.normpath('namespace')], ) assert {pathlib.Path(x) for x in entries} == { pathlib.Path('__init__.py'), pathlib.Path('more/__init__.py'), } def test_nodes_tree(): tree = _editable.Node() tree[('aa', 'bb', 'cc')] = 'path1' tree[('aa', 'dd')] = 'path2' assert tree['aa']['bb']['cc'] == 'path1' assert tree['aa']['dd'] == 'path2' assert tree[('aa', 'bb', 'cc')] == 'path1' assert tree.get(('aa', 'bb', 'cc')) == 'path1' assert tree['aa'] == tree[('aa', )] assert tree.get(('aa', 'gg')) is None assert tree[('aa', 'gg')] == _editable.Node() def test_collect(package_complex): root = os.fspath(package_complex) install_plan = { 'targets': { os.path.join(root, 'build', f'test{EXT_SUFFIX}'): { 'destination': os.path.join('{py_platlib}', 'complex', f'test{EXT_SUFFIX}'), 'tag': 'runtime'}, }, 'install_subdirs': { os.path.join(root, 'complex'): { 'destination': os.path.join('{py_platlib}', 'complex'), 'tag': None} } } tree = _editable.collect(install_plan) assert tree['complex']['__init__.py'] == os.path.join(root, 'complex', '__init__.py') assert tree['complex'][f'test{EXT_SUFFIX}'] == os.path.join(root, 'build', f'test{EXT_SUFFIX}') assert tree['complex']['more']['__init__.py'] == os.path.join(root, 'complex', 'more', '__init__.py') def test_mesonpy_meta_finder(package_complex, tmp_path): # build a package in a temporary directory mesonpy.Project(package_complex, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder('complex', {'complex'}, os.fspath(tmp_path), ['ninja']) # check repr assert repr(finder) == f'MesonpyMetaFinder(\'complex\', {str(tmp_path)!r})' # verify that we can look up a pure module in the source directory spec = finder.find_spec('complex') assert spec.name == 'complex' assert isinstance(spec.loader, _editable.SourceFileLoader) assert spec.origin == os.fspath(package_complex / 'complex/__init__.py') # and an extension module in the build directory spec = finder.find_spec('complex.test') assert spec.name == 'complex.test' assert isinstance(spec.loader, _editable.ExtensionFileLoader) assert spec.origin == os.fspath(tmp_path / f'test{EXT_SUFFIX}') try: # install the finder in the meta path sys.meta_path.insert(0, finder) # verify that we can import the modules import complex assert complex.__spec__.origin == os.fspath(package_complex / 'complex/__init__.py') assert complex.__file__ == os.fspath(package_complex / 'complex/__init__.py') import complex.test assert complex.test.__spec__.origin == os.fspath(tmp_path / f'test{EXT_SUFFIX}') assert complex.test.answer() == 42 import complex.namespace.foo assert complex.namespace.foo.__spec__.origin == os.fspath(package_complex / 'complex/namespace/foo.py') assert complex.namespace.foo.foo() == 'foo' finally: # remove finder from the meta path del sys.meta_path[0] def test_mesonpy_traversable(): tree = _editable.Node() tree[('package', '__init__.py')] = '/tmp/src/package/__init__.py' tree[('package', 'src.py')] = '/tmp/src/package/src.py' tree[('package', 'data.txt')] = '/tmp/src/package/data.txt' tree[('package', 'nested', '__init__.py')] = '/tmp/src/package/nested/__init__.py' tree[('package', 'nested', 'some.py')] = '/tmp/src/package/nested/some.py' tree[('package', 'nested', 'generated.txt')] = '/tmp/build/generated.txt' traversable = _editable.MesonpyTraversable('package', tree['package']) assert {x.name for x in traversable.iterdir()} == {'__init__.py', 'src.py', 'data.txt', 'nested'} nested = traversable / 'nested' assert nested.is_dir() assert {x.name for x in nested.iterdir()} == {'__init__.py', 'some.py', 'generated.txt'} generated = traversable.joinpath('nested', 'generated.txt') assert isinstance(generated, pathlib.Path) assert generated == pathlib.Path('/tmp/build/generated.txt') bad = traversable / 'bad' assert not bad.is_file() assert not bad.is_dir() with pytest.raises(FileNotFoundError): bad.open() def test_resources(tmp_path): # build a package in a temporary directory package_path = pathlib.Path(__file__).parent / 'packages' / 'simple' mesonpy.Project(package_path, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder('simple', {'simple'}, os.fspath(tmp_path), ['ninja']) # verify that we can look up resources spec = finder.find_spec('simple') reader = spec.loader.get_resource_reader('simple') traversable = reader.files() assert {x.name for x in traversable.iterdir()} == {'__init__.py', 'test.py', 'data.txt'} with traversable.joinpath('data.txt').open() as f: text = f.read().rstrip() assert text == 'ABC' @pytest.mark.skipif(sys.version_info < (3, 9), reason='importlib.resources not available') def test_importlib_resources(tmp_path): # build a package in a temporary directory package_path = pathlib.Path(__file__).parent / 'packages' / 'simple' mesonpy.Project(package_path, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder('simple', {'simple'}, os.fspath(tmp_path), ['ninja']) try: # install the finder in the meta path sys.meta_path.insert(0, finder) # verify that we can import the modules import simple assert simple.__spec__.origin == os.fspath(package_path / '__init__.py') assert simple.__file__ == os.fspath(package_path / '__init__.py') assert simple.data() == 'ABC' # load resources via importlib import importlib.resources with importlib.resources.files(simple).joinpath('data.txt').open() as f: text = f.read().rstrip() assert text == 'ABC' assert importlib.resources.files(simple).joinpath('data.txt').read_text().rstrip() == 'ABC' finally: # remove finder from the meta path del sys.meta_path[0] def test_editable_install(venv, editable_simple): venv.pip('install', os.fspath(editable_simple)) assert venv.python('-c', 'import simple; print(simple.data())').strip() == 'ABC' def test_editble_reentrant(venv, editable_imports_itself_during_build): venv.pip('install', os.fspath(editable_imports_itself_during_build)) assert venv.python('-c', 'import plat; print(plat.data())').strip() == 'ABC' path = pathlib.Path(__file__).parent / 'packages' / 'imports-itself-during-build' / 'plat.c' code = path.read_text() try: # edit souce code path.write_text(code.replace('ABC', 'DEF')) # check that the module is rebuilt on import. the build proess # imports python code from the source directory, thus this # test also check that this import does not cause an rebuild # loop assert venv.python('-c', 'import plat; print(plat.data())').strip() == 'DEF' finally: path.write_text(code) def test_editable_pkgutils_walk_packages(package_complex, tmp_path): # build a package in a temporary directory mesonpy.Project(package_complex, tmp_path) finder = _editable.MesonpyMetaFinder('complex', {'complex'}, os.fspath(tmp_path), ['ninja']) try: # install editable hooks sys.meta_path.insert(0, finder) sys.path_hooks.insert(0, finder._path_hook) import complex packages = {m.name for m in pkgutil.walk_packages(complex.__path__, complex.__name__ + '.')} assert packages == { 'complex.bar', 'complex.more', 'complex.more.baz', 'complex.more.move', 'complex.test', } from complex import namespace packages = {m.name for m in pkgutil.walk_packages(namespace.__path__, namespace.__name__ + '.')} assert packages == { 'complex.namespace.bar', 'complex.namespace.foo', } finally: # remove hooks del sys.meta_path[0] del sys.path_hooks[0] def test_custom_target_install_dir(package_custom_target_dir, tmp_path): mesonpy.Project(package_custom_target_dir, tmp_path) finder = _editable.MesonpyMetaFinder('package', {'package'}, os.fspath(tmp_path), ['ninja']) try: sys.meta_path.insert(0, finder) import package.generated.one import package.generated.two # noqa: F401 finally: del sys.meta_path[0] @pytest.mark.parametrize('verbose', [False, True], ids=('', 'verbose')) @pytest.mark.parametrize('args', [[], ['-j1']], ids=('', '-Ccompile-args=-j1')) def test_editable_rebuild(package_purelib_and_platlib, tmp_path, verbose, args): with mesonpy._project({'builddir': os.fspath(tmp_path), 'compile-args': args}) as project: finder = _editable.MesonpyMetaFinder( project._metadata.name, {'plat', 'pure'}, os.fspath(tmp_path), project._build_command, verbose=verbose, ) try: # Install editable hooks sys.meta_path.insert(0, finder) # Import module and trigger rebuild. Importing any module in the # Python package triggers the build. Use the the pure Python one as # Cygwin is not happy when reloading an extension module. stdout = io.StringIO() with redirect_stdout(stdout): import pure assert not verbose or stdout.getvalue().startswith('meson-python: building ') # Reset state. del sys.modules['pure'] finder._rebuild.cache_clear() # Importing again should result in no output. stdout = io.StringIO() with redirect_stdout(stdout): import pure # noqa: F401, F811 assert stdout.getvalue() == '' finally: del sys.meta_path[0] sys.modules.pop('pure', None) def test_editable_verbose(venv, package_complex, editable_complex, monkeypatch): monkeypatch.setenv('MESONPY_EDITABLE_VERBOSE', '1') venv.pip('install', os.fspath(editable_complex)) # Importing the module should not result in any output since the project has already been built assert venv.python('-c', 'import complex').strip() == '' # Touch a compiled source file and make sure that the build info is output on import package_complex.joinpath('test.pyx').touch() output = venv.python('-c', 'import complex').strip() assert output.startswith('meson-python: building complex: ') # Another import without file changes should not show any output assert venv.python('-c', 'import complex') == '' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_examples.py0000644000000000000000000000177114607715450015656 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import subprocess import sys import pytest import mesonpy from mesonpy._util import chdir examples_dir = pathlib.Path(__file__).parent.parent / 'docs' / 'examples' def test_spam(venv, tmp_path): """Test that the wheel for the example builds, installs, and imports.""" with chdir(examples_dir / 'spam'): if sys.version_info < (3, 8): # The test project requires Python >= 3.8. with pytest.raises(SystemExit): mesonpy.build_wheel(tmp_path) else: wheel = mesonpy.build_wheel(tmp_path) subprocess.run( [venv.executable, '-m', 'pip', 'install', tmp_path / wheel], check=True) output = subprocess.run( [venv.executable, '-c', 'import spam; print(spam.add(1, 2))'], check=True, stdout=subprocess.PIPE).stdout assert int(output) == 3 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_metadata.py0000644000000000000000000000310114607715450015605 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import packaging.version import pyproject_metadata import pytest from mesonpy import Metadata def test_package_name(): name = 'package.Test' metadata = Metadata(name='package.Test', version=packaging.version.Version('0.0.1')) assert metadata.name == name assert metadata.canonical_name == 'package-test' def test_package_name_from_pyproject(): name = 'package.Test' pyproject = {'project': { 'name': 'package.Test', 'version': '0.0.1', }} metadata = Metadata.from_pyproject(pyproject, pathlib.Path()) assert metadata.name == name assert metadata.canonical_name == 'package-test' def test_package_name_invalid(): with pytest.raises(pyproject_metadata.ConfigurationError, match='Invalid project name'): Metadata(name='.test', version=packaging.version.Version('0.0.1')) def test_unsupported_dynamic(): pyproject = {'project': { 'name': 'unsupported-dynamic', 'version': '0.0.1', 'dynamic': ['dependencies'], }} with pytest.raises(pyproject_metadata.ConfigurationError, match='Unsupported dynamic fields: "dependencies"'): Metadata.from_pyproject(pyproject, pathlib.Path()) def test_missing_version(package_missing_version): pyproject = {'project': { 'name': 'missing-version', }} with pytest.raises(pyproject_metadata.ConfigurationError, match='Required "project.version" field is missing'): Metadata.from_pyproject(pyproject, pathlib.Path()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_options.py0000644000000000000000000000244614607715450015533 0ustar00# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT import os import subprocess import pytest import mesonpy ninja_ver_str = subprocess.run(['ninja', '--version'], check=True, stdout=subprocess.PIPE, text=True).stdout NINJA_VERSION = tuple(map(int, ninja_ver_str.split('.')[:3])) # Ninja 1.9 does not support the soruce^ syntax to specify a target. @pytest.mark.skipif(NINJA_VERSION < (1, 10), reason='Ninja version too old') @pytest.mark.parametrize( ('args', 'expected'), [ ([], True), (['-Dbuildtype=release'], True), (['-Dbuildtype=debug'], False), ], ids=['', '-Dbuildtype=release', '-Dbuildtype=debug'], ) def test_ndebug(package_purelib_and_platlib, tmp_path, args, expected): with mesonpy._project({'setup-args': args}) as project: command = subprocess.run( # Ask ninja what is the command that would be used to # compile a C source file (the trailing ^ is used to # specify the target that is the first output of the rule # containing the specified source file). ['ninja', '-C', os.fspath(project._build_dir), '-t', 'commands', '../plat.c^'], stdout=subprocess.PIPE, check=True).stdout assert (b'-DNDEBUG' in command) == expected ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_output.py0000644000000000000000000000177514607715450015404 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pytest import mesonpy @pytest.mark.parametrize(('tty', 'env', 'colors'), [ (False, {}, False), (True, {}, True), (False, {'NO_COLOR': ''}, False), (True, {'NO_COLOR': ''}, False), (False, {'FORCE_COLOR': ''}, True), (True, {'FORCE_COLOR': ''}, True), (True, {'FORCE_COLOR': '', 'NO_COLOR': ''}, False), (True, {'TERM': ''}, True), (True, {'TERM': 'dumb'}, False), ]) def test_use_ansi_escapes(mocker, monkeypatch, tty, env, colors): mocker.patch('sys.stdout.isatty', return_value=tty) mocker.patch('mesonpy._util.setup_windows_console', return_value=True) monkeypatch.delenv('NO_COLOR', raising=False) monkeypatch.delenv('FORCE_COLOR', raising=False) for key, value in env.items(): monkeypatch.setenv(key, value) # Clear caching by functools.lru_cache(). mesonpy._use_ansi_escapes.cache_clear() assert mesonpy._use_ansi_escapes() == colors ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_pep517.py0000644000000000000000000000672414607715450015064 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import shutil import subprocess import sys from typing import List import packaging.requirements import pytest import mesonpy @pytest.mark.parametrize('system_patchelf', ['patchelf', None], ids=['patchelf', 'nopatchelf']) @pytest.mark.parametrize('ninja', [None, '1.8.1', '1.8.3'], ids=['noninja', 'oldninja', 'newninja']) def test_get_requires_for_build_wheel(monkeypatch, package_pure, system_patchelf, ninja): # the NINJA environment variable affects the ninja executable lookup and breaks the test monkeypatch.delenv('NINJA', raising=False) def which(prog: str) -> bool: if prog == 'patchelf': return system_patchelf if prog == 'ninja': return ninja and 'ninja' if prog in ('ninja-build', 'samu'): return None # smoke check for the future if we add another usage raise AssertionError(f'Called with {prog}, tests not expecting that usage') subprocess_run = subprocess.run def run(cmd: List[str], *args: object, **kwargs: object) -> subprocess.CompletedProcess: if cmd == ['ninja', '--version']: return subprocess.CompletedProcess(cmd, 0, f'{ninja}\n', '') return subprocess_run(cmd, *args, **kwargs) monkeypatch.setattr(shutil, 'which', which) monkeypatch.setattr(subprocess, 'run', run) expected = set() if ninja is None or mesonpy._parse_version_string(ninja) < (1, 8, 2): expected.add('ninja') if system_patchelf is None and sys.platform.startswith('linux'): expected.add('patchelf') requirements = mesonpy.get_requires_for_build_wheel() # Check that the requirement strings are in the correct format. names = {packaging.requirements.Requirement(x).name for x in requirements} assert names == expected def test_invalid_config_settings(capsys, package_pure, tmp_path_session): for method in mesonpy.build_sdist, mesonpy.build_wheel: with pytest.raises(SystemExit): method(tmp_path_session, {'invalid': ()}) out, err = capsys.readouterr() assert 'Unknown option "invalid"' in out def test_invalid_config_settings_suggest(capsys, package_pure, tmp_path_session): for method in mesonpy.build_sdist, mesonpy.build_wheel: with pytest.raises(SystemExit): method(tmp_path_session, {'setup_args': ()}) out, err = capsys.readouterr() assert 'Unknown option "setup_args". Did you mean "setup-args" or "dist-args"?' in out def test_validate_config_settings_invalid(): with pytest.raises(mesonpy.ConfigError, match='Unknown option "invalid"'): mesonpy._validate_config_settings({'invalid': ()}) def test_validate_config_settings_repeated(): with pytest.raises(mesonpy.ConfigError, match='Only one value for "builddir" can be specified'): mesonpy._validate_config_settings({'builddir': ['one', 'two']}) def test_validate_config_settings_str(): config = mesonpy._validate_config_settings({'setup-args': '-Dfoo=true'}) assert config['setup-args'] == ['-Dfoo=true'] def test_validate_config_settings_list(): config = mesonpy._validate_config_settings({'setup-args': ['-Done=1', '-Dtwo=2']}) assert config['setup-args'] == ['-Done=1', '-Dtwo=2'] def test_validate_config_settings_tuple(): config = mesonpy._validate_config_settings({'setup-args': ('-Done=1', '-Dtwo=2')}) assert config['setup-args'] == ['-Done=1', '-Dtwo=2'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_project.py0000644000000000000000000002102714607715450015502 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import ast import os import shutil import sys import textwrap if sys.version_info < (3, 11): import tomli as tomllib else: import tomllib import pyproject_metadata import pytest import mesonpy from .conftest import in_git_repo_context, package_dir def test_unsupported_python_version(package_unsupported_python_version): with pytest.raises(mesonpy.MesonBuilderError, match='Package requires Python version ==1.0.0'): with mesonpy._project(): pass def test_missing_meson_version(package_missing_meson_version): with pytest.raises(pyproject_metadata.ConfigurationError, match='Section "project" missing in pyproject.toml'): with mesonpy._project(): pass def test_missing_dynamic_version(package_missing_dynamic_version): with pytest.raises(pyproject_metadata.ConfigurationError, match='Field "version" declared as dynamic but'): with mesonpy._project(): pass def test_user_args(package_user_args, tmp_path, monkeypatch): project_run = mesonpy.Project._run cmds = [] args = [] def wrapper(self, cmd): # intercept and filter out test arguments and forward the call if cmd[:2] == ['meson', 'compile']: # when using meson compile instead of ninja directly, the # arguments needs to be unmarshalled from the form used to # pass them to the --ninja-args option assert cmd[-1].startswith('--ninja-args=') cmds.append(cmd[:2]) args.append(ast.literal_eval(cmd[-1].split('=')[1])) elif cmd[:1] == ['meson']: cmds.append(cmd[:2]) args.append(cmd[2:]) else: # direct ninja invocation cmds.append([os.path.basename(cmd[0])]) args.append(cmd[1:]) return project_run(self, [x for x in cmd if not x.startswith(('config-', 'cli-', '--ninja-args'))]) monkeypatch.setattr(mesonpy.Project, '_run', wrapper) config_settings = { 'dist-args': ('cli-dist',), 'setup-args': ('cli-setup',), 'compile-args': ('cli-compile',), 'install-args': ('cli-install',), } with in_git_repo_context(): mesonpy.build_sdist(tmp_path, config_settings) mesonpy.build_wheel(tmp_path, config_settings) # check that the right commands are executed, namely that 'meson # compile' is used on Windows rather than a 'ninja' direct # invocation. assert cmds == [ # sdist: calls to 'meson setup' and 'meson dist' ['meson', 'setup'], ['meson', 'dist'], # wheel: calls to 'meson setup', 'meson compile', and 'meson install' ['meson', 'setup'], ['meson', 'compile'] if sys.platform == 'win32' else ['ninja'], ] # check that the user options are passed to the invoked commands expected = [ # sdist: calls to 'meson setup' and 'meson dist' ['config-setup', 'cli-setup'], ['config-dist', 'cli-dist'], # wheel: calls to 'meson setup', 'meson compile', and 'meson install' ['config-setup', 'cli-setup'], ['config-compile', 'cli-compile'], ['config-install', 'cli-install'], ] for expected_args, cmd_args in zip(expected, args): for arg in expected_args: assert arg in cmd_args @pytest.mark.parametrize('package', ('top-level', 'meson-args')) def test_unknown_user_args(package, tmp_path_session): with pytest.raises(mesonpy.ConfigError): mesonpy.Project(package_dir / f'unknown-user-args-{package}', tmp_path_session) def test_install_tags(package_purelib_and_platlib, tmp_path_session): project = mesonpy.Project( package_purelib_and_platlib, tmp_path_session, meson_args={ 'install': ['--tags', 'purelib'], } ) assert 'platlib' not in project._manifest def test_validate_pyproject_config_one(): pyproject_config = tomllib.loads(textwrap.dedent(''' [tool.meson-python.args] setup = ['-Dfoo=true'] ''')) conf = mesonpy._validate_pyproject_config(pyproject_config) assert conf['args'] == {'setup': ['-Dfoo=true']} def test_validate_pyproject_config_all(): pyproject_config = tomllib.loads(textwrap.dedent(''' [tool.meson-python.args] setup = ['-Dfoo=true'] dist = [] compile = ['-j4'] install = ['--tags=python'] ''')) conf = mesonpy._validate_pyproject_config(pyproject_config) assert conf['args'] == { 'setup': ['-Dfoo=true'], 'dist': [], 'compile': ['-j4'], 'install': ['--tags=python']} def test_validate_pyproject_config_unknown(): pyproject_config = tomllib.loads(textwrap.dedent(''' [tool.meson-python.args] invalid = true ''')) with pytest.raises(mesonpy.ConfigError, match='Unknown configuration entry "tool.meson-python.args.invalid"'): mesonpy._validate_pyproject_config(pyproject_config) def test_validate_pyproject_config_empty(): pyproject_config = tomllib.loads(textwrap.dedent('')) config = mesonpy._validate_pyproject_config(pyproject_config) assert config == {} @pytest.mark.skipif( sys.version_info < (3, 8), reason="unittest.mock doesn't support the required APIs for this test", ) def test_invalid_build_dir(package_pure, tmp_path, mocker): meson = mocker.spy(mesonpy.Project, '_run') # configure the project project = mesonpy.Project(package_pure, tmp_path) assert len(meson.call_args_list) == 1 assert meson.call_args_list[0].args[1][1] == 'setup' assert '--reconfigure' not in meson.call_args_list[0].args[1] project.build() meson.reset_mock() # subsequent builds with the same build directory result in a setup --reconfigure project = mesonpy.Project(package_pure, tmp_path) assert len(meson.call_args_list) == 1 assert meson.call_args_list[0].args[1][1] == 'setup' assert '--reconfigure' in meson.call_args_list[0].args[1] project.build() meson.reset_mock() # corrupting the build direcory setup is run again tmp_path.joinpath('meson-private/coredata.dat').unlink() project = mesonpy.Project(package_pure, tmp_path) assert len(meson.call_args_list) == 1 assert meson.call_args_list[0].args[1][1] == 'setup' assert '--reconfigure' not in meson.call_args_list[0].args[1] project.build() meson.reset_mock() # removing the build directory things should still work shutil.rmtree(tmp_path) project = mesonpy.Project(package_pure, tmp_path) assert len(meson.call_args_list) == 1 assert meson.call_args_list[0].args[1][1] == 'setup' assert '--reconfigure' not in meson.call_args_list[0].args[1] project.build() @pytest.mark.skipif(not os.getenv('CI') or sys.platform != 'win32', reason='Requires MSVC') def test_compiler(venv, package_detect_compiler, tmp_path): # Check that things are setup properly to use the MSVC compiler on # Windows. This effectively means running the compilation step # with 'meson compile' instead of 'ninja' on Windows. Run this # test only on CI where we know that MSVC is available. wheel = mesonpy.build_wheel(tmp_path, {'setup-args': ['--vsenv']}) venv.pip('install', os.fspath(tmp_path / wheel)) compiler = venv.python('-c', 'import detect_compiler; print(detect_compiler.compiler())').strip() assert compiler == 'msvc' @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') @pytest.mark.parametrize('archflags', [ '-arch x86_64', '-arch arm64', '-arch arm64 -arch arm64', ]) def test_archflags_envvar_parsing(package_purelib_and_platlib, monkeypatch, archflags): try: monkeypatch.setenv('ARCHFLAGS', archflags) arch = archflags.split()[-1] with mesonpy._project(): assert mesonpy._tags.Tag().platform.endswith(arch) finally: # revert environment variable setting done by the in-process build os.environ.pop('_PYTHON_HOST_PLATFORM', None) @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') @pytest.mark.parametrize('archflags', [ '-arch arm64 -arch x86_64', '-arch arm64 -DFOO=1', ]) def test_archflags_envvar_parsing_invalid(package_purelib_and_platlib, monkeypatch, archflags): try: monkeypatch.setenv('ARCHFLAGS', archflags) with pytest.raises(mesonpy.ConfigError): with mesonpy._project(): pass finally: # revert environment variable setting done by the in-process build os.environ.pop('_PYTHON_HOST_PLATFORM', None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_sdist.py0000644000000000000000000001371314607715450015165 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import stat import sys import tarfile import textwrap import pytest import mesonpy from .conftest import in_git_repo_context def test_no_pep621(sdist_library): with tarfile.open(sdist_library, 'r:gz') as sdist: sdist_pkg_info = sdist.extractfile('library-1.0.0/PKG-INFO').read().decode() assert sdist_pkg_info == textwrap.dedent('''\ Metadata-Version: 2.1 Name: library Version: 1.0.0 ''') def test_pep621(sdist_full_metadata): with tarfile.open(sdist_full_metadata, 'r:gz') as sdist: sdist_pkg_info = sdist.extractfile('full_metadata-1.2.3/PKG-INFO').read().decode() assert sdist_pkg_info == textwrap.dedent('''\ Metadata-Version: 2.1 Name: full-metadata Version: 1.2.3 Summary: Some package with all of the PEP 621 metadata Keywords: full metadata Home-page: https://example.com Author: Jane Doe Author-Email: Unknown Maintainer-Email: Jane Doe License: some license Classifier: Development Status :: 4 - Beta Classifier: Programming Language :: Python Project-URL: Homepage, https://example.com Project-URL: Documentation, https://readthedocs.org Project-URL: Repository, https://github.com/mesonbuild/meson-python Project-URL: Changelog, https://github.com/mesonbuild/meson-python/blob/master/CHANGELOG.rst Requires-Python: >=3.7 Requires-Dist: a Requires-Dist: b>1 Requires-Dist: c>2; os_name != "nt" Requires-Dist: d<3; extra == "test" Requires-Dist: e[all]; extra == "test" Provides-Extra: test Description-Content-Type: text/markdown # full-metadata An example package with all of the PEP 621 metadata! ''') def test_dynamic_version(sdist_dynamic_version): with tarfile.open(sdist_dynamic_version, 'r:gz') as sdist: sdist_pkg_info = sdist.extractfile('dynamic_version-1.0.0/PKG-INFO').read().decode() assert sdist_pkg_info == textwrap.dedent('''\ Metadata-Version: 2.1 Name: dynamic-version Version: 1.0.0 ''') def test_contents(sdist_library): with tarfile.open(sdist_library, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} assert names == { 'library-1.0.0/example.c', 'library-1.0.0/examplelib.c', 'library-1.0.0/examplelib.h', 'library-1.0.0/meson.build', 'library-1.0.0/pyproject.toml', 'library-1.0.0/PKG-INFO', } # All the archive members have a valid mtime. assert 0 not in mtimes def test_contents_subdirs(sdist_subdirs): with tarfile.open(sdist_subdirs, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} assert names == { 'subdirs-1.0.0/PKG-INFO', 'subdirs-1.0.0/meson.build', 'subdirs-1.0.0/pyproject.toml', 'subdirs-1.0.0/subdirs/__init__.py', 'subdirs-1.0.0/subdirs/a/__init__.py', 'subdirs-1.0.0/subdirs/a/b/c.py', 'subdirs-1.0.0/subdirs/b/c.py', } # All the archive members have a valid mtime. assert 0 not in mtimes def test_contents_unstaged(package_pure, tmp_path): new_data = textwrap.dedent(''' def bar(): return 'foo' ''').strip() with open('pure.py', 'r') as f: old_data = f.read() try: with in_git_repo_context(): with open('pure.py', 'w') as f, open('crap', 'x'): f.write(new_data) sdist_path = mesonpy.build_sdist(os.fspath(tmp_path)) finally: with open('pure.py', 'w') as f: f.write(old_data) os.unlink('crap') with tarfile.open(tmp_path / sdist_path, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} read_data = sdist.extractfile('pure-1.0.0/pure.py').read().replace(b'\r\n', b'\n') assert names == { 'pure-1.0.0/PKG-INFO', 'pure-1.0.0/meson.build', 'pure-1.0.0/pure.py', 'pure-1.0.0/pyproject.toml', } assert read_data == new_data.encode() # All the archive members have a valid mtime. assert 0 not in mtimes @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='Platform does not support executable bit') def test_executable_bit(sdist_executable_bit): expected = { 'executable_bit-1.0.0/PKG-INFO': False, 'executable_bit-1.0.0/example-script.py': True, 'executable_bit-1.0.0/example.c': False, 'executable_bit-1.0.0/executable_module.py': True, 'executable_bit-1.0.0/meson.build': False, 'executable_bit-1.0.0/pyproject.toml': False, } with tarfile.open(sdist_executable_bit, 'r:gz') as sdist: for member in sdist.getmembers(): assert bool(member.mode & stat.S_IXUSR) == expected[member.name] def test_generated_files(sdist_generated_files): with tarfile.open(sdist_generated_files, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} assert names == { 'executable_bit-1.0.0/PKG-INFO', 'executable_bit-1.0.0/example-script.py', 'executable_bit-1.0.0/example.c', 'executable_bit-1.0.0/executable_module.py', 'executable_bit-1.0.0/meson.build', 'executable_bit-1.0.0/pyproject.toml', 'executable_bit-1.0.0/_version_meson.py', 'executable_bit-1.0.0/generate_version.py', } # All the archive members have a valid mtime. assert 0 not in mtimes ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_tags.py0000644000000000000000000001007314607715450014771 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import importlib.machinery import os import pathlib import platform import sys import sysconfig from collections import defaultdict import packaging.tags import pytest import mesonpy import mesonpy._tags from .conftest import adjust_packaging_platform_tag # Test against the wheel tag generated by packaging module. tag = next(packaging.tags.sys_tags()) ABI = tag.abi INTERPRETER = tag.interpreter PLATFORM = adjust_packaging_platform_tag(tag.platform) def get_abi3_suffix(): for suffix in importlib.machinery.EXTENSION_SUFFIXES: if '.abi3' in suffix: # Unix return suffix elif suffix == '.pyd': # Windows return suffix SUFFIX = sysconfig.get_config_var('EXT_SUFFIX') ABI3SUFFIX = get_abi3_suffix() def test_wheel_tag(): assert str(mesonpy._tags.Tag()) == f'{INTERPRETER}-{ABI}-{PLATFORM}' assert str(mesonpy._tags.Tag(abi='abi3')) == f'{INTERPRETER}-abi3-{PLATFORM}' @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') def test_macos_platform_tag(monkeypatch): for minor in range(9, 16): monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'10.{minor}') version = (10, minor) if platform.mac_ver()[2] != 'arm64' else (11, 0) assert next(packaging.tags.mac_platforms(version)) == mesonpy._tags.get_platform_tag() for major in range(11, 20): for minor in range(3): monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'{major}.{minor}') assert next(packaging.tags.mac_platforms((major, minor))) == mesonpy._tags.get_platform_tag() @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') def test_macos_platform_tag_arm64(monkeypatch): monkeypatch.setenv('_PYTHON_HOST_PLATFORM', 'macosx-12.0-arm64') # Verify that the minimum platform ABI version on arm64 is 11.0. monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', '10.12') assert mesonpy._tags.get_platform_tag() == 'macosx_11_0_arm64' monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', '12.34') assert mesonpy._tags.get_platform_tag() == 'macosx_12_0_arm64' @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') def test_python_host_platform(monkeypatch): monkeypatch.setenv('_PYTHON_HOST_PLATFORM', 'macosx-12.0-arm64') assert mesonpy._tags.get_platform_tag().endswith('arm64') monkeypatch.setenv('_PYTHON_HOST_PLATFORM', 'macosx-11.1-x86_64') assert mesonpy._tags.get_platform_tag().endswith('x86_64') def wheel_builder_test_factory(content, pure=True, limited_api=False): manifest = defaultdict(list) manifest.update({key: [(pathlib.Path(x), os.path.join('build', x)) for x in value] for key, value in content.items()}) return mesonpy._WheelBuilder(None, manifest, limited_api) def test_tag_empty_wheel(): builder = wheel_builder_test_factory({}) assert str(builder.tag) == 'py3-none-any' def test_tag_purelib_wheel(): builder = wheel_builder_test_factory({ 'purelib': ['pure.py'], }) assert str(builder.tag) == 'py3-none-any' def test_tag_platlib_wheel(): builder = wheel_builder_test_factory({ 'platlib': [f'extension{SUFFIX}'], }) assert str(builder.tag) == f'{INTERPRETER}-{ABI}-{PLATFORM}' def test_tag_stable_abi(): builder = wheel_builder_test_factory({ 'platlib': [f'extension{ABI3SUFFIX}'], }, limited_api=True) assert str(builder.tag) == f'{INTERPRETER}-abi3-{PLATFORM}' @pytest.mark.xfail(sys.version_info < (3, 8) and sys.platform == 'win32', reason='Extension modules suffix without ABI tags') @pytest.mark.xfail('__pypy__' in sys.builtin_module_names, reason='PyPy does not use special modules suffix for stable ABI') def test_tag_mixed_abi(): builder = wheel_builder_test_factory({ 'platlib': [f'extension{ABI3SUFFIX}', f'another{SUFFIX}'], }, pure=False, limited_api=True) with pytest.raises(mesonpy.BuildError, match='The package declares compatibility with Python limited API but '): assert str(builder.tag) == f'{INTERPRETER}-abi3-{PLATFORM}' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_wheel.py0000644000000000000000000003242014607715450015137 0ustar00# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import re import shutil import stat import subprocess import sys import sysconfig import textwrap import packaging.tags import pytest import wheel.wheelfile import mesonpy from .conftest import adjust_packaging_platform_tag _meson_ver_str = subprocess.run(['meson', '--version'], check=True, stdout=subprocess.PIPE, text=True).stdout MESON_VERSION = tuple(map(int, _meson_ver_str.split('.')[:3])) EXT_SUFFIX = sysconfig.get_config_var('EXT_SUFFIX') if sys.version_info <= (3, 8, 7): if MESON_VERSION >= (0, 99): # Fixed in Meson 1.0, see https://github.com/mesonbuild/meson/pull/10961. from distutils.sysconfig import get_config_var EXT_SUFFIX = get_config_var('EXT_SUFFIX') if sys.platform in {'win32', 'cygwin'}: EXT_IMP_SUFFIX = re.sub(r'.(pyd|dll)$', '.lib' if shutil.which('cl.exe') else '.dll.a', EXT_SUFFIX) LIB_SUFFIX = { 'cygwin': '.dll', 'darwin': '.dylib', 'win32': '.dll', }.get(sys.platform, '.so') # Test against the wheel tag generated by packaging module. tag = next(packaging.tags.sys_tags()) ABI = tag.abi INTERPRETER = tag.interpreter PLATFORM = adjust_packaging_platform_tag(tag.platform) def wheel_contents(artifact): # Sometimes directories have entries, sometimes not, so we filter them out. return { entry for entry in artifact.namelist() if not entry.endswith('/') } def test_scipy_like(wheel_scipy_like): # This test is meant to exercise features commonly needed by a regular # Python package for scientific computing or data science: # - C and Cython extensions, # - including generated code, # - using `install_subdir`, # - packaging data files with extensions not known to Meson artifact = wheel.wheelfile.WheelFile(wheel_scipy_like) expecting = { 'mypkg-2.3.4.dist-info/METADATA', 'mypkg-2.3.4.dist-info/RECORD', 'mypkg-2.3.4.dist-info/WHEEL', 'mypkg/__init__.py', 'mypkg/__config__.py', f'mypkg/extmod{EXT_SUFFIX}', f'mypkg/cy_extmod{EXT_SUFFIX}', 'mypkg/submod/__init__.py', 'mypkg/submod/unknown_filetype.npq', } if sys.platform in {'win32', 'cygwin'}: # Currently Meson is installing .dll.a (import libraries) next # to .pyd extension modules. Those are very small, so it's not # a major issue - just sloppy. Ensure we don't fail on those. expecting.update({ f'mypkg/extmod{EXT_IMP_SUFFIX}', f'mypkg/cy_extmod{EXT_IMP_SUFFIX}', }) assert wheel_contents(artifact) == expecting name = artifact.parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == ABI assert name.group('plat') == PLATFORM def test_purelib_and_platlib(wheel_purelib_and_platlib): artifact = wheel.wheelfile.WheelFile(wheel_purelib_and_platlib) expecting = { f'plat{EXT_SUFFIX}', 'purelib_and_platlib-1.0.0.data/purelib/pure.py', 'purelib_and_platlib-1.0.0.dist-info/METADATA', 'purelib_and_platlib-1.0.0.dist-info/RECORD', 'purelib_and_platlib-1.0.0.dist-info/WHEEL', } if sys.platform in {'win32', 'cygwin'}: # Currently Meson is installing .dll.a (import libraries) next # to .pyd extension modules. Those are very small, so it's not # a major issue - just sloppy. Ensure we don't fail on those. expecting.update({ f'plat{EXT_IMP_SUFFIX}' }) assert wheel_contents(artifact) == expecting def test_pure(wheel_pure): artifact = wheel.wheelfile.WheelFile(wheel_pure) assert wheel_contents(artifact) == { 'pure-1.0.0.dist-info/METADATA', 'pure-1.0.0.dist-info/RECORD', 'pure-1.0.0.dist-info/WHEEL', 'pure.py', } def test_configure_data(wheel_configure_data): artifact = wheel.wheelfile.WheelFile(wheel_configure_data) assert wheel_contents(artifact) == { 'configure_data.py', 'configure_data-1.0.0.dist-info/METADATA', 'configure_data-1.0.0.dist-info/RECORD', 'configure_data-1.0.0.dist-info/WHEEL', } def test_contents_license_file(wheel_license_file): artifact = wheel.wheelfile.WheelFile(wheel_license_file) assert artifact.read('license_file-1.0.0.dist-info/LICENSE.custom').rstrip() == b'Hello!' @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_contents(package_library, wheel_library): artifact = wheel.wheelfile.WheelFile(wheel_library) assert wheel_contents(artifact) == { f'.library.mesonpy.libs/libexample{LIB_SUFFIX}', 'library-1.0.0.data/headers/examplelib.h', 'library-1.0.0.data/scripts/example', 'library-1.0.0.dist-info/METADATA', 'library-1.0.0.dist-info/RECORD', 'library-1.0.0.dist-info/WHEEL', } @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_local_lib(venv, wheel_link_against_local_lib): venv.pip('install', wheel_link_against_local_lib) output = venv.python('-c', 'import example; print(example.example_sum(1, 2))') assert int(output) == 3 @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_rpath(wheel_link_against_local_lib, tmp_path): artifact = wheel.wheelfile.WheelFile(wheel_link_against_local_lib) artifact.extractall(tmp_path) origin = {'linux': '$ORIGIN', 'darwin': '@loader_path'}[sys.platform] expected = {f'{origin}/.link_against_local_lib.mesonpy.libs', 'custom-rpath',} rpath = set(mesonpy._rpath._get_rpath(tmp_path / f'example{EXT_SUFFIX}')) # Verify that rpath is a superset of the expected one: linking to # the Python runtime may require additional rpath entries. assert rpath >= expected @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_uneeded_rpath(wheel_purelib_and_platlib, tmp_path): artifact = wheel.wheelfile.WheelFile(wheel_purelib_and_platlib) artifact.extractall(tmp_path) origin = {'linux': '$ORIGIN', 'darwin': '@loader_path'}[sys.platform] rpath = mesonpy._rpath._get_rpath(tmp_path / f'plat{EXT_SUFFIX}') for path in rpath: assert origin not in path @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_executable_bit(wheel_executable_bit): artifact = wheel.wheelfile.WheelFile(wheel_executable_bit) executable_files = { 'executable_bit-1.0.0.data/purelib/executable_module.py', 'executable_bit-1.0.0.data/scripts/example', 'executable_bit-1.0.0.data/scripts/example-script', } for info in artifact.infolist(): mode = (info.external_attr >> 16) & 0o777 assert bool(mode & stat.S_IXUSR) == (info.filename in executable_files) def test_detect_wheel_tag_module(wheel_purelib_and_platlib): name = wheel.wheelfile.WheelFile(wheel_purelib_and_platlib).parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == ABI assert name.group('plat') == PLATFORM def test_detect_wheel_tag_script(wheel_executable): name = wheel.wheelfile.WheelFile(wheel_executable).parsed_filename assert name.group('pyver') == 'py3' assert name.group('abi') == 'none' assert name.group('plat') == PLATFORM def test_entrypoints(wheel_full_metadata): artifact = wheel.wheelfile.WheelFile(wheel_full_metadata) with artifact.open('full_metadata-1.2.3.dist-info/entry_points.txt') as f: assert f.read().decode().strip() == textwrap.dedent(''' [something.custom] example = example:custom [console_scripts] example-cli = example:cli [gui_scripts] example-gui = example:gui ''').strip() def test_top_level_modules(package_module_types): with mesonpy._project() as project: builder = mesonpy._EditableWheelBuilder(project._metadata, project._manifest, project._limited_api) assert set(builder._top_level_modules) == { 'file', 'package', 'namespace', 'native', } def test_purelib_platlib_split(package_purelib_platlib_split, tmp_path): with pytest.raises(mesonpy.BuildError, match='The purelib-platlib-split package is split'): with mesonpy._project() as project: project.wheel(tmp_path) @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') @pytest.mark.parametrize('arch', ['x86_64', 'arm64']) def test_archflags_envvar(package_purelib_and_platlib, monkeypatch, tmp_path, arch): try: monkeypatch.setenv('ARCHFLAGS', f'-arch {arch}') filename = mesonpy.build_wheel(tmp_path) name = wheel.wheelfile.WheelFile(tmp_path / filename).parsed_filename assert name.group('plat').endswith(arch) finally: # revert environment variable setting done by the in-process build os.environ.pop('_PYTHON_HOST_PLATFORM', None) def test_subprojects(package_subproject, tmp_path): filename = mesonpy.build_wheel(tmp_path) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) assert wheel_contents(artifact) == { 'subproject-1.0.0.dist-info/METADATA', 'subproject-1.0.0.dist-info/RECORD', 'subproject-1.0.0.dist-info/WHEEL', 'subproject.py', 'dep.py', } # Requires Meson 1.2.0, see https://github.com/mesonbuild/meson/pull/11909. @pytest.mark.skipif(MESON_VERSION < (1, 1, 99), reason='Meson version too old') @pytest.mark.parametrize(('arg'), ['--skip-subprojects', '--skip-subprojects=dep']) def test_skip_subprojects(package_subproject, tmp_path, arg): filename = mesonpy.build_wheel(tmp_path, {'install-args': [arg]}) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) assert wheel_contents(artifact) == { 'subproject-1.0.0.dist-info/METADATA', 'subproject-1.0.0.dist-info/RECORD', 'subproject-1.0.0.dist-info/WHEEL', 'subproject.py', } # Requires Meson 1.3.0, see https://github.com/mesonbuild/meson/pull/11745. @pytest.mark.skipif(MESON_VERSION < (1, 2, 99), reason='Meson version too old') def test_limited_api(wheel_limited_api): artifact = wheel.wheelfile.WheelFile(wheel_limited_api) name = artifact.parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == 'abi3' assert name.group('plat') == PLATFORM # Requires Meson 1.3.0, see https://github.com/mesonbuild/meson/pull/11745. @pytest.mark.skipif(MESON_VERSION < (1, 2, 99), reason='Meson version too old') @pytest.mark.xfail('__pypy__' in sys.builtin_module_names, reason='PyPy does not use special modules suffix for stable ABI') def test_limited_api_bad(package_limited_api, tmp_path): with pytest.raises(mesonpy.BuildError, match='The package declares compatibility with Python limited API but '): with mesonpy._project({'setup-args': ['-Dextra=true']}) as project: project.wheel(tmp_path) # Requires Meson 1.3.0, see https://github.com/mesonbuild/meson/pull/11745. @pytest.mark.skipif(MESON_VERSION < (1, 2, 99), reason='Meson version too old') def test_limited_api_disabled(package_limited_api, tmp_path): filename = mesonpy.build_wheel(tmp_path, {'setup-args': ['-Dpython.allow_limited_api=false']}) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) name = artifact.parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == ABI assert name.group('plat') == PLATFORM def test_install_subdir(wheel_install_subdir): artifact = wheel.wheelfile.WheelFile(wheel_install_subdir) # Handling of the exclude_files and exclude_directories requires # Meson 1.1.0, see https://github.com/mesonbuild/meson/pull/11432. # Run the test anyway to ensure that meson-python can produce a # wheel also for older versions of Meson. if MESON_VERSION >= (1, 1, 99): assert wheel_contents(artifact) == { 'install_subdir-1.0.0.dist-info/METADATA', 'install_subdir-1.0.0.dist-info/RECORD', 'install_subdir-1.0.0.dist-info/WHEEL', 'subdir/__init__.py', 'subdir/test.py', 'test/module.py', 'nested/deep/deep.py', 'nested/nested.py', } def test_vendored_meson(wheel_vendored_meson): # This test will error if the vendored meson.py wrapper script in # the test package isn't used. pass def test_encoding(package_encoding, tmp_path): with mesonpy._project() as project: wheelname = project.wheel(tmp_path) artifact = wheel.wheelfile.WheelFile(tmp_path / wheelname) assert wheel_contents(artifact) == { 'encoding-1.0.0.dist-info/METADATA', 'encoding-1.0.0.dist-info/RECORD', 'encoding-1.0.0.dist-info/WHEEL', 'テスト.py', } def test_custom_target_install_dir(package_custom_target_dir, tmp_path): filename = mesonpy.build_wheel(tmp_path) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) assert wheel_contents(artifact) == { 'custom_target_dir-1.0.0.dist-info/METADATA', 'custom_target_dir-1.0.0.dist-info/RECORD', 'custom_target_dir-1.0.0.dist-info/WHEEL', 'package/generated/one.py', 'package/generated/two.py', } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1713347368.0 meson_python-0.16.0/tests/test_wheelfile.py0000644000000000000000000000350314607715450015777 0ustar00# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import contextlib import time import zipfile import wheel.wheelfile import mesonpy._wheelfile def test_basic(tmp_path): path = tmp_path / 'test-1.0-py3-any-none.whl' bar = tmp_path / 'bar' bar.write_bytes(b'bar') with mesonpy._wheelfile.WheelFile(path, 'w') as w: assert w.name == 'test' assert w.version == '1.0' w.writestr('foo', b'test') w.write(bar, 'bar') with contextlib.closing(wheel.wheelfile.WheelFile(path, 'r')) as w: assert set(w.namelist()) == {'foo', 'bar', 'test-1.0.dist-info/RECORD'} with w.open('foo') as foo: assert foo.read() == b'test' with w.open('bar') as bar: assert bar.read() == b'bar' def test_source_date_epoch(tmp_path, monkeypatch): path = tmp_path / 'test-1.0-py3-any-none.whl' epoch = 1668871912 # The ZIP file format timestamps have 2 seconds resolution. assert epoch % 2 == 0 monkeypatch.setenv('SOURCE_DATE_EPOCH', str(epoch)) bar = tmp_path / 'bar' bar.write_bytes(b'bar') with mesonpy._wheelfile.WheelFile(path, 'w') as w: w.writestr('foo', b'test') w.write(bar, 'bar') with wheel.wheelfile.WheelFile(path, 'r') as w: for entry in w.infolist(): assert entry.date_time == time.gmtime(epoch)[:6] def test_compression(tmp_path): # create a wheel and test that everything is compressed path = tmp_path / 'test-1.0-py3-any-none.whl' bar = tmp_path / 'bar' bar.write_bytes(b'bar') with mesonpy._wheelfile.WheelFile(path, 'w') as w: w.writestr('foo', b'test') w.write(bar, 'bar') with zipfile.ZipFile(path, 'r') as w: for entry in w.infolist(): assert entry.compress_type == zipfile.ZIP_DEFLATED ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1713347710.7692592 meson_python-0.16.0/PKG-INFO0000644000000000000000000000775214607716177012376 0ustar00Metadata-Version: 2.1 Name: meson-python Version: 0.16.0 Summary: Meson Python build backend (PEP 517) Keywords: meson build backend pep517 package Home-page: https://github.com/mesonbuild/meson-python Maintainer-Email: Ralf Gommers , Daniele Nicolodi , Henry Schreiner , Thomas Li <47963215+lithomas1@users.noreply.github.com> License: Copyright © 2022 the meson-python contributors Copyright © 2021 Quansight Labs and Filipe Laíns Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Classifier: Development Status :: 5 - Production/Stable Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Build Tools Project-URL: Homepage, https://github.com/mesonbuild/meson-python Project-URL: Repository, https://github.com/mesonbuild/meson-python Project-URL: Documentation, https://mesonbuild.com/meson-python/ Project-URL: Changelog, https://mesonbuild.com/meson-python/changelog.html Requires-Python: >=3.7 Requires-Dist: meson>=0.63.3; python_version < "3.12" Requires-Dist: meson>=1.2.3; python_version >= "3.12" Requires-Dist: packaging>=19.0 Requires-Dist: pyproject-metadata>=0.7.1 Requires-Dist: tomli>=1.0.0; python_version < "3.11" Requires-Dist: build; extra == "test" Requires-Dist: pytest>=6.0; extra == "test" Requires-Dist: pytest-cov[toml]; extra == "test" Requires-Dist: pytest-mock; extra == "test" Requires-Dist: cython>=3.0.3; extra == "test" Requires-Dist: wheel; extra == "test" Requires-Dist: typing-extensions>=3.7.4; python_version < "3.11" and extra == "test" Requires-Dist: furo>=2023.5.20; extra == "docs" Requires-Dist: sphinx~=6.2; extra == "docs" Requires-Dist: sphinx-copybutton>=0.5.0; extra == "docs" Requires-Dist: sphinx-design>=0.1.0; extra == "docs" Requires-Dist: sphinxext-opengraph>=0.7.0; extra == "docs" Provides-Extra: test Provides-Extra: docs Description-Content-Type: text/x-rst .. SPDX-FileCopyrightText: 2021 The meson-python developers .. SPDX-License-Identifier: MIT meson-python ============ ``meson-python`` is a Python build back-end built on top of the Meson__ build system. It enables using Meson for the configuration and build steps of Python packages. Meson is an open source build system meant to be both extremely fast, and, even more importantly, as user friendly as possible. ``meson-python`` is best suited for building Python packages containing extension modules implemented in languages such as C, C++, Cython, Fortran, Pythran, or Rust. Consult the documentation__ for more details. Questions regarding the use of ``meson-python`` can be directed to the discussions__ space on GitHub. Bug reports and feature requests can be filed as GitHub issues__. __ https://mesonbuild.com/ __ https://mesonbuild.com/meson-python/ __ https://github.com/mesonbuild/meson-python/discussions/ __ https://github.com/mesonbuild/meson-python/issues/