././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.gitattributes0000664000000000000000000000051315257562503015762 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT # These test files contain symlinks to outside the repo (hence invalid - on # purpose) so exclude them to prevent warnings. See gh-728 for context. tests/packages/symlinks/baz.py export-ignore tests/packages/symlinks/qux.py export-ignore ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.github/workflows/docs.yml0000664000000000000000000000207015257562503020137 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT name: docs on: push: branches: - main paths: - docs/** - CHANGELOG.rst - README.md pull_request: branches: - main - release-* paths: - docs/** - CHANGELOG.rst - README.md permissions: {} jobs: build: runs-on: ubuntu-latest steps: - uses: actions/setup-python@v7 with: python-version: '3.11' - uses: actions/checkout@v7 with: ref: ${{ github.event.inputs.tag || github.ref }} persist-credentials: false - run: python -m pip install --group docs - run: python -m sphinx -W docs/ build/docs/ - uses: actions/upload-pages-artifact@v5 with: path: build/docs/ deploy: needs: build permissions: pages: write id-token: write environment: name: github-pages runs-on: ubuntu-latest if: ${{ github.ref == 'refs/heads/main' }} steps: - uses: actions/deploy-pages@v5 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.github/workflows/pixi.lock0000664000000000000000000011661215257562503020317 0ustar00rootrootversion: 7 platforms: - name: linux-aarch64 virtual-packages: - __unix=0=0 - __linux=4.18 - __glibc=2.28 - __archspec=0=aarch64 environments: default: channels: - url: https://prefix.dev/conda-forge/ packages: linux-aarch64: - conda: https://prefix.dev/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/binutils_impl_linux-aarch64-2.46.1-default_h5f4c503_102.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_10.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/c-ares-1.34.8-h29ee22c_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/c-compiler-2.0.0-h1f08cd5_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/cmake-4.4.2-hcbeb305_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/conda-gcc-specs-15.3.0-hbdd0822_7.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/cxx-compiler-2.0.0-hf41333a_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/cython-3.3.0-py314h1eee2f1_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/gcc-15.3.0-hfdd745d_7.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/gcc_impl_linux-aarch64-15.3.0-h543efd9_7.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/geos-3.15.0-h4125222_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/gxx-15.3.0-hfdd745d_7.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/gxx_impl_linux-aarch64-15.3.0-hcb04d1e_7.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/icu-78.3-py311h3512406_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/keyutils-1.6.3-h5bc82ec_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/krb5-1.22.2-h095d8e5_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libcurl-8.21.0-h86273da_5.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321hc48eb74_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libev-4.33-h80f16a2_3.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libffi-3.7.0-h376a255_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libgcc-16.2.0-h205dda4_4.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libgomp-16.2.0-h8acb6b2_4.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libnghttp2-1.68.1-ha4b982d_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libpsl-0.23.1-hb8431ed_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libsanitizer-15.3.0-he541324_7.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libsqlite-3.53.4-h399dd60_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libssh2-1.11.1-h7572e3e_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libstdcxx-16.2.0-hef695bb_4.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libuuid-2.42.2-h1022ec0_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libuv-1.52.1-h80f16a2_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_3.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/ncurses-6.6-h2b6f883_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/ninja-1.13.2-hdc560ac_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/patchelf-0.19.1-hfb11796_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/pkg-config-0.29.2-h36a561e_1011.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/python-3.14.7-h6bfacdd_100_cp314.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/readline-8.3-ha7194a6_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/rhash-1.4.6-he30d5cf_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/tk-8.6.13-noxft_hf03c496_4.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/zstd-1.5.7-h9d15635_7.conda - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/kernel-headers_linux-aarch64-4.18.0-h05a177a_9.conda - conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-aarch64-15.3.0-h6e7e4e0_107.conda - conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-aarch64-15.3.0-h0e8df58_107.conda - conda: https://prefix.dev/conda-forge/noarch/meson-1.12.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - conda: https://prefix.dev/conda-forge/noarch/pip-26.2.1-pyh145f28c_0.conda - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/pyproject-metadata-0.12.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pyproject_hooks-1.2.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-mock-3.15.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/python-build-1.5.0-pyhc364b38_0.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://prefix.dev/conda-forge/noarch/sysroot_linux-aarch64-2.28-h585391f_9.conda - conda: https://prefix.dev/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://prefix.dev/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda system-compilers: channels: - url: https://prefix.dev/conda-forge/ packages: linux-aarch64: - conda: https://prefix.dev/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_10.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/c-ares-1.34.8-h29ee22c_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/cmake-4.4.2-hcbeb305_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/cython-3.3.0-py314h1eee2f1_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/geos-3.15.0-h4125222_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/icu-78.3-py311h3512406_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/keyutils-1.6.3-h5bc82ec_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/krb5-1.22.2-h095d8e5_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libcurl-8.21.0-h86273da_5.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321hc48eb74_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libev-4.33-h80f16a2_3.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libffi-3.7.0-h376a255_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libgcc-16.2.0-h205dda4_4.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libgomp-16.2.0-h8acb6b2_4.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libnghttp2-1.68.1-ha4b982d_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libpsl-0.23.1-hb8431ed_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libsqlite-3.53.4-h399dd60_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libssh2-1.11.1-h7572e3e_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libstdcxx-16.2.0-hef695bb_4.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libuuid-2.42.2-h1022ec0_0.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libuv-1.52.1-h80f16a2_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_3.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/ncurses-6.6-h2b6f883_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/ninja-1.13.2-hdc560ac_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/patchelf-0.19.1-hfb11796_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/pkg-config-0.29.2-h36a561e_1011.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/python-3.14.7-h6bfacdd_100_cp314.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/readline-8.3-ha7194a6_1.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/rhash-1.4.6-he30d5cf_2.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/tk-8.6.13-noxft_hf03c496_4.conda - conda: https://prefix.dev/conda-forge/linux-aarch64/zstd-1.5.7-h9d15635_7.conda - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/meson-1.12.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda - conda: https://prefix.dev/conda-forge/noarch/pip-26.2.1-pyh145f28c_0.conda - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda - conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/pyproject-metadata-0.12.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/pyproject_hooks-1.2.0-pyhd8ed1ab_1.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda - conda: https://prefix.dev/conda-forge/noarch/pytest-mock-3.15.1-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/python-build-1.5.0-pyhc364b38_0.conda - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-8_cp314.conda - conda: https://prefix.dev/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda - conda: https://prefix.dev/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda - conda: https://prefix.dev/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda packages: - conda: https://prefix.dev/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda build_number: 20 sha256: a2527b1d81792a0ccd2c05850960df119c2b6d8f5fdec97f2db7d25dc23b1068 md5: 468fd3bb9e1f671d36c2cbc677e56f1d depends: - libgomp >=7.5.0 constrains: - openmp_impl <0.0a0 license: BSD-3-Clause license_family: BSD run_exports: strong: - _openmp_mutex >=4.5 size: 28926 timestamp: 1770939656741 - conda: https://prefix.dev/conda-forge/linux-aarch64/binutils_impl_linux-aarch64-2.46.1-default_h5f4c503_102.conda sha256: eebe159bf600943552e4319ff4ce27b6a2dadf0dcc5443e76dcee9259a408e11 md5: 58f37d76b8234c69dbf2939d511bea0b depends: - ld_impl_linux-aarch64 2.46.1 default_h1979696_102 - sysroot_linux-aarch64 - zstd >=1.5.7,<1.6.0a0 license: GPL-3.0-only license_family: GPL run_exports: {} size: 4677171 timestamp: 1784214549910 - conda: https://prefix.dev/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_10.conda sha256: 24eacc8a20fd7c4616566178562bef7f9344eb4a8700cfc3180fa75a6ff9d39f md5: fd544ef1c672d645bf78e5819cbb8f91 depends: - libgcc >=14 license: bzip2-1.0.6 license_family: BSD run_exports: weak: - bzip2 >=1.0.8,<2.0a0 size: 194694 timestamp: 1785906301397 - conda: https://prefix.dev/conda-forge/linux-aarch64/c-ares-1.34.8-h29ee22c_2.conda sha256: 3838d10a78c206a1a4ec7ff041880b4f9b8ecde3520c911daae9e06baeb8858e md5: eb80eb38625b8552a099aa88f8ba5db7 depends: - libgcc >=15 license: MIT license_family: MIT run_exports: weak: - c-ares >=1.34.8,<2.0a0 size: 241210 timestamp: 1787169968125 - conda: https://prefix.dev/conda-forge/linux-aarch64/c-compiler-2.0.0-h1f08cd5_0.conda sha256: f48a9cb26eaf043e59a76933a61a62e73e360b2ce7c2045581540e31f826f8a6 md5: 111808f8dee7e11e1ebe2461d4301edd depends: - gcc 15.* license: BSD-3-Clause license_family: BSD run_exports: {} size: 6988 timestamp: 1786642160586 - conda: https://prefix.dev/conda-forge/linux-aarch64/cmake-4.4.2-hcbeb305_2.conda sha256: 3a9a8584c4d6f65771e1e50061f67734400c69031dabc0a6dc2020e19feab566 md5: 4777f799c7478ae75c69de0df24fa399 depends: - libgcc >=15 - libstdcxx >=15 - liblzma >=5.8.3,<6.0a0 - libuv >=1.52.1,<2.0a0 - zstd >=1.5.7,<1.6.0a0 - bzip2 >=1.0.8,<2.0a0 - libexpat >=2.8.1,<3.0a0 - rhash >=1.4.6,<2.0a0 - ncurses >=6.6,<7.0a0 - libzlib >=1.3.2,<2.0a0 - libcurl >=8.21.0,<9.0a0 license: BSD-3-Clause license_family: BSD run_exports: {} size: 25496912 timestamp: 1787209719745 - conda: https://prefix.dev/conda-forge/linux-aarch64/conda-gcc-specs-15.3.0-hbdd0822_7.conda sha256: 972da393305529c4db79f3d8f34291586dd8767bbb5e75ff84e4fe2a365240eb md5: 5f1cec36f1dbe50c6d8c9ccf84a8be8c depends: - gcc_impl_linux-aarch64 >=15.3.0,<15.3.1.0a0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL run_exports: {} size: 32657 timestamp: 1790302403105 - conda: https://prefix.dev/conda-forge/linux-aarch64/cxx-compiler-2.0.0-hf41333a_0.conda sha256: 0616c1e5f97cbcb505f0daa119ca8c9975caca02c84c5bc4ceb0ef65bf7648a3 md5: ce387759a5f3908b1273247b8660a048 depends: - gxx 15.* license: BSD-3-Clause license_family: BSD run_exports: {} size: 6970 timestamp: 1786642161076 - conda: https://prefix.dev/conda-forge/linux-aarch64/cython-3.3.0-py314h1eee2f1_0.conda sha256: 2a414114c1046e6f7d8f047f0cec96b80b32ce0dbd9f17c4a2e90209b3f66304 md5: ef075772c977bf1a736eb45b21aa6a75 depends: - libgcc >=15 - libstdcxx >=15 - python >=3.14,<3.15.0a0 - python_abi 3.14.* *_cp314 license: Apache-2.0 run_exports: {} size: 3955136 timestamp: 1787435574078 - conda: https://prefix.dev/conda-forge/linux-aarch64/gcc-15.3.0-hfdd745d_7.conda sha256: 83761e8fe27e7ffc9134662bee77523f011299d7a781cceb3ee0300474748aa8 md5: 3ee778b8a6192bf8f61687c3c44fb6c9 depends: - conda-gcc-specs - gcc_impl_linux-aarch64 15.3.0 h543efd9_7 license: BSD-3-Clause license_family: BSD run_exports: {} size: 29585 timestamp: 1790302501803 - conda: https://prefix.dev/conda-forge/linux-aarch64/gcc_impl_linux-aarch64-15.3.0-h543efd9_7.conda sha256: b777f7fea75988191524a694b861222eef7d859b55ef200145bdb3559b243e54 md5: 509460640a88cadf2c9a5a4734134f51 depends: - binutils_impl_linux-aarch64 >=2.46.1 - libgcc >=15.3.0 - libgcc-devel_linux-aarch64 15.3.0 h6e7e4e0_107 - libgomp >=15.3.0 - libsanitizer 15.3.0 he541324_7 - libstdcxx >=15.3.0 - libstdcxx-devel_linux-aarch64 15.3.0 h0e8df58_107 - sysroot_linux-aarch64 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL run_exports: {} size: 75249934 timestamp: 1790302274160 - conda: https://prefix.dev/conda-forge/linux-aarch64/geos-3.15.0-h4125222_1.conda sha256: fd9bc3de82aec81d91285fbe18b84c6fa94d55f6cd36364dd4b6c37ab8cbc10b md5: 49e5818343217aff06b37c0d30ce6bfa depends: - libstdcxx >=15 - libgcc >=15 license: LGPL-2.1-only run_exports: weak: - geos >=3.15.0,<3.15.1.0a0 size: 2425569 timestamp: 1789734780719 - conda: https://prefix.dev/conda-forge/linux-aarch64/gxx-15.3.0-hfdd745d_7.conda sha256: 1b378d9d5a0562e66363dacd64f5d0b2489e403cd5a6dd647b82ba45a63f95bd md5: b0fc69e39425af4a983a5261a074c9a3 depends: - conda-gcc-specs - gcc 15.3.0 hfdd745d_7 - gxx_impl_linux-aarch64 15.3.0 hcb04d1e_7 license: BSD-3-Clause license_family: BSD run_exports: {} size: 29012 timestamp: 1790302530292 - conda: https://prefix.dev/conda-forge/linux-aarch64/gxx_impl_linux-aarch64-15.3.0-hcb04d1e_7.conda sha256: 25df4cff4be63cdb6c93693b7312b2d5fc71034955d2a7748893585e46605750 md5: 1300d1ce6d51343ff98b59917686c5c3 depends: - gcc_impl_linux-aarch64 15.3.0 h543efd9_7 - libstdcxx-devel_linux-aarch64 15.3.0 h0e8df58_107 - sysroot_linux-aarch64 - tzdata license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL run_exports: {} size: 15475341 timestamp: 1790302472944 - conda: https://prefix.dev/conda-forge/linux-aarch64/icu-78.3-py311h3512406_2.conda sha256: 54d921defd947adb58a90e10203d3bfe6c1f209f5f1a1ad2c6a9f7617f2fb59e md5: b35bbb1b957440ed742f35fb96eb7f1c depends: - libgcc >=14 - libstdcxx >=14 license: MIT license_family: MIT run_exports: weak: - icu >=78.3,<79.0a0 size: 14688525 timestamp: 1786545779464 - conda: https://prefix.dev/conda-forge/linux-aarch64/keyutils-1.6.3-h5bc82ec_1.conda sha256: 3999b1472f1e549a0b766428e2823abf20626aac5314b474c9b76bf6eb679def md5: 6d9be306ecb8dfc9ff46f02cb367d5c2 depends: - libgcc >=15 license: LGPL-2.1-or-later run_exports: weak: - keyutils >=1.6.3,<2.0a0 size: 129546 timestamp: 1786739205968 - conda: https://prefix.dev/conda-forge/linux-aarch64/krb5-1.22.2-h095d8e5_2.conda sha256: 601d79af94d9562ba70e2d4947034ba159aae293a3c860855335a7c76c14400e md5: a4d0da122ba952abf76981e76d0d283c depends: - keyutils >=1.6.3,<2.0a0 - libedit >=3.1.20250104,<3.2.0a0 - libedit >=3.1.20250104,<4.0a0 - libgcc >=15 - libstdcxx >=15 - openssl >=3.5.7,<4.0a0 license: MIT license_family: MIT run_exports: weak: - krb5 >=1.22.2,<1.23.0a0 size: 1538590 timestamp: 1786762058856 - conda: https://prefix.dev/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.46.1-default_h1979696_102.conda sha256: 2c4901f4227b0850328ed0c69f958b30ad2cd18982f7a31c7c1f911827004d08 md5: 489444d0acb2a579d2a002d85a08c059 depends: - zstd >=1.5.7,<1.6.0a0 constrains: - binutils_impl_linux-aarch64 2.46.1 license: GPL-3.0-only license_family: GPL run_exports: {} size: 905305 timestamp: 1784214534868 - conda: https://prefix.dev/conda-forge/linux-aarch64/libcurl-8.21.0-h86273da_5.conda sha256: d7bc660680aee2ce4011779bdfc00b3f8d0c98acf503aa2982874d81b075ff66 md5: c2c977033fa833d7f1f83bb34dd52717 depends: - krb5 >=1.22.2,<1.23.0a0 - libgcc >=15 - libnghttp2 >=1.68.1,<2.0a0 - libpsl >=0.23.1,<0.24.0a0 - libssh2 >=1.11.1,<2.0a0 - libzlib >=1.3.2,<2.0a0 - openssl >=3.5.7,<4.0a0 - zstd >=1.5.7,<1.6.0a0 license: curl license_family: MIT run_exports: weak: - libcurl >=8.21.0,<9.0a0 size: 508109 timestamp: 1787183657716 - conda: https://prefix.dev/conda-forge/linux-aarch64/libedit-3.1.20250104-pl5321hc48eb74_1.conda sha256: 2d7218da06f1121619335bff25a2669df810dee90d2eb65b17f8b2e6b1c0d372 md5: 6e06eb2c9fda76721699bcdd759b9c60 depends: - ncurses - libgcc >=14 - ncurses >=6.6,<7.0a0 license: BSD-2-Clause license_family: BSD run_exports: weak: - libedit >=3.1.20250104,<3.2.0a0 size: 149007 timestamp: 1786616643904 - conda: https://prefix.dev/conda-forge/linux-aarch64/libev-4.33-h80f16a2_3.conda sha256: 4475f79a020e9ff2a5a0308c48cb2970a25d55c3dd724a97ab28bfac3be6cd49 md5: f679b30a53d410d0b5ae0cb8f5b7397e depends: - libgcc >=14 license: BSD-2-Clause OR GPL-2.0-or-later license_family: GPL run_exports: weak: - libev >=4.33,<4.34.0a0 size: 45746 timestamp: 1785917328690 - conda: https://prefix.dev/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda sha256: 20a5726bc8705d91437c9e6ef83b30da64a1719b869656d20a1ee818333ea5ac md5: fac3b65a605cd253037fdf3daf2de8d9 depends: - libgcc >=14 constrains: - expat 2.8.1.* license: MIT license_family: MIT run_exports: {} size: 77649 timestamp: 1781203572523 - conda: https://prefix.dev/conda-forge/linux-aarch64/libffi-3.7.0-h376a255_0.conda sha256: c95b5b5fc13c8d7af2a9908e6c64844f48787a7631f8abcde1813dc21b3b079e md5: 81aedbde3ea118c602e8b289bf565ac5 depends: - libgcc >=14 license: MIT license_family: MIT run_exports: weak: - libffi >=3.7.0,<3.8.0a0 size: 63746 timestamp: 1783520889209 - conda: https://prefix.dev/conda-forge/linux-aarch64/libgcc-16.2.0-h205dda4_4.conda sha256: a132d78d49d0fa0a08e9e2a77528a12d974e8e123bc32895c0bd0a737b8abd89 md5: 2c81f8ce7bda35c7a88c4c044452a97c depends: - _openmp_mutex >=4.5 constrains: - libgcc-ng ==16.2.0=*_4 - libgomp 16.2.0 h8acb6b2_4 license: GPL-3.0-only WITH GCC-exception-3.1 run_exports: {} size: 627810 timestamp: 1787617756679 - conda: https://prefix.dev/conda-forge/linux-aarch64/libgomp-16.2.0-h8acb6b2_4.conda sha256: 6d216e6dc9a158b920f6e0c1dfdd6d77575bf79420dadf85d64576298ecb4503 md5: 727c19b26cd43140e4a90a6f8f1cc31a license: GPL-3.0-only WITH GCC-exception-3.1 run_exports: strong: - _openmp_mutex >=4.5 size: 617987 timestamp: 1787617685449 - conda: https://prefix.dev/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_1.conda sha256: f760669fd1cea27f689f411c0d5488e26ce50e382c9b63e4ad348f959850124a md5: e0e6411a60d00186eec7c73f4118ab67 depends: - libgcc >=14 constrains: - xz 5.8.3.* license: 0BSD run_exports: weak: - liblzma >=5.8.3,<6.0a0 size: 125578 timestamp: 1786348561649 - conda: https://prefix.dev/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_2.conda sha256: 5d6621a2229777824386164b40c67ff804fe98dd4165354cf73ee73e282a2adf md5: eaaaec4776cd8a7b987c4b1782220141 depends: - libgcc >=14 license: BSD-2-Clause license_family: BSD run_exports: {} size: 113885 timestamp: 1786650485380 - conda: https://prefix.dev/conda-forge/linux-aarch64/libnghttp2-1.68.1-ha4b982d_1.conda sha256: 0c28d734512fa2c66a232b2f3968eae7124dbd6ad42c594c752f1d08dfb86195 md5: ff4b2b7c169c438bf648fb14f369c3b9 depends: - c-ares >=1.34.8,<2.0a0 - libev >=4.33,<4.34.0a0 - libev >=4.33,<5.0a0 - libgcc >=15 - libstdcxx >=15 - libzlib >=1.3.2,<2.0a0 - openssl >=3.5.7,<4.0a0 license: MIT license_family: MIT run_exports: weak: - libnghttp2 >=1.68.1,<2.0a0 size: 734829 timestamp: 1787177407983 - conda: https://prefix.dev/conda-forge/linux-aarch64/libpsl-0.23.1-hb8431ed_1.conda sha256: 757f79c182ac3080cf416acd91c7643b8074b8b2e5c1eba0ffc5a16897feb84b md5: 5ab41e5e70b78eb00ef62cdaa35cd86f depends: - libgcc >=15 - libstdcxx >=15 - icu >=78.3,<79.0a0 license: MIT license_family: MIT run_exports: weak: - libpsl >=0.23.1,<0.24.0a0 size: 73118 timestamp: 1786970733378 - conda: https://prefix.dev/conda-forge/linux-aarch64/libsanitizer-15.3.0-he541324_7.conda sha256: 28bd5d6389f032a594dbc8cf6af4fbca85fb6b386dd85b6c8d3ce9cd13aa998b md5: baffcd8b96bdc491b795ae6b979f806f depends: - libgcc >=15.3.0 - libstdcxx >=15.3.0 license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL run_exports: weak: - libsanitizer 15.3.0 size: 7284100 timestamp: 1790302233451 - conda: https://prefix.dev/conda-forge/linux-aarch64/libsqlite-3.53.4-h399dd60_1.conda sha256: fae75e68e9dbc3c90dcf93d4bae6315f1330c95aaf1404a721e8468266c23475 md5: 27e16aa1f45c787aa181549be6f209f4 depends: - icu >=78.3,<79.0a0 - libgcc >=15 - libzlib >=1.3.2,<2.0a0 license: blessing run_exports: weak: - libsqlite >=3.53.4,<4.0a0 size: 972932 timestamp: 1787051100646 - conda: https://prefix.dev/conda-forge/linux-aarch64/libssh2-1.11.1-h7572e3e_1.conda sha256: f6fef76c1c8899d7976030871b8cd8016b0a306d2b8519834cd6491d6a42fb82 md5: 833be3f226277d894df3c7a7131d9532 depends: - libgcc >=14 - libzlib >=1.3.2,<2.0a0 - openssl >=3.5.7,<4.0a0 license: BSD-3-Clause license_family: BSD run_exports: weak: - libssh2 >=1.11.1,<2.0a0 size: 315682 timestamp: 1786713068743 - conda: https://prefix.dev/conda-forge/linux-aarch64/libstdcxx-16.2.0-hef695bb_4.conda sha256: 84d2b667bce6549325243235952110b1849ff2dfd7091a1479108930b88057d5 md5: 47b6b37e291c14f39bd95f9d340c45f5 depends: - libgcc 16.2.0 h205dda4_4 constrains: - libstdcxx-ng ==16.2.0=*_4 license: GPL-3.0-only WITH GCC-exception-3.1 run_exports: {} size: 6241792 timestamp: 1787617775395 - conda: https://prefix.dev/conda-forge/linux-aarch64/libuuid-2.42.2-h1022ec0_0.conda sha256: 7663489f97c104ae3814db10f384932c74b439f3c1fd4247e4fe3599830c090a md5: 58fa42bc4bc71fc329889497ec15effb depends: - libgcc >=14 license: BSD-3-Clause license_family: BSD run_exports: weak: - libuuid >=2.42.2,<3.0a0 size: 43248 timestamp: 1781625528371 - conda: https://prefix.dev/conda-forge/linux-aarch64/libuv-1.52.1-h80f16a2_1.conda sha256: 52f4bc6e340bde53bfe38e45f6cb1080a2d5f8891da9a647087f7cc6a6edfc22 md5: 8e2136432f02841b9d8b848045f66d7d depends: - libgcc >=14 license: MIT license_family: MIT run_exports: weak: - libuv >=1.52.1,<2.0a0 size: 457209 timestamp: 1785914582944 - conda: https://prefix.dev/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_3.conda sha256: 76efa6cc9d7e6f5ee3bbca0939f64054af2bdfb3c3632531f8e633cf6c2ea41e md5: bd534c2fbe56d8c2ea3b2d8f5e12bca8 constrains: - zlib 1.3.2 *_3 license: Zlib license_family: Other run_exports: weak: - libzlib >=1.3.2,<2.0a0 size: 70108 timestamp: 1785276540870 - conda: https://prefix.dev/conda-forge/linux-aarch64/ncurses-6.6-h2b6f883_1.conda sha256: d69a04914139627f0a6bfd19412d6c7f1e37edc896af84a6011e07e8bc1e69fa md5: c3b4349171ca987ff33a1de61f7b3f96 depends: - libgcc >=14 license: X11 AND BSD-3-Clause run_exports: weak: - ncurses >=6.6,<7.0a0 size: 955422 timestamp: 1786355019431 - conda: https://prefix.dev/conda-forge/linux-aarch64/ninja-1.13.2-hdc560ac_1.conda sha256: 63d956ff75ca18235cae1d2e814246b011f9c85765416517ab1270aff55027d6 md5: dc59c099f43cdffa2b92e5f6248be5b3 depends: - libstdcxx >=14 - libgcc >=14 license: Apache-2.0 license_family: APACHE run_exports: {} size: 182159 timestamp: 1786713053611 - conda: https://prefix.dev/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_1.conda sha256: c89e748e8a008e8ca6f25e102362f33319db0c98cc29d98ddada92842f636327 md5: 1600dfde78c5adba306f8571af62a323 depends: - ca-certificates - libgcc >=14 license: Apache-2.0 license_family: Apache run_exports: weak: - openssl >=3.6.3,<4.0a0 size: 3719270 timestamp: 1785913554920 - conda: https://prefix.dev/conda-forge/linux-aarch64/patchelf-0.19.1-hfb11796_1.conda sha256: 1055ef142ff6af9711166ea9b30b9d54c63c9f078154d998a63850ec99db5274 md5: e42be47cbb4f4a0c55ba95cd0c6c9ff6 depends: - libgcc >=15 - libstdcxx >=15 license: GPL-3.0-or-later license_family: GPL run_exports: {} size: 155619 timestamp: 1787380792832 - conda: https://prefix.dev/conda-forge/linux-aarch64/pkg-config-0.29.2-h36a561e_1011.conda sha256: 91cf73940417d96fe2c0dc8b4681cdf0e877a12a6eab1cf2ecba1a72699de075 md5: 635b6b5a581745fb3a4b237069c1a309 depends: - libgcc >=14 license: GPL-2.0-or-later license_family: GPL run_exports: {} size: 331109 timestamp: 1786352313756 - conda: https://prefix.dev/conda-forge/linux-aarch64/python-3.14.7-h6bfacdd_100_cp314.conda build_number: 100 sha256: f06bf28284339913931caf4004e3d81269bfb08e57fe3487cf87008c02480194 md5: 0be19acb61fbaa0f3c7bd3c58755ae39 depends: - bzip2 >=1.0.8,<2.0a0 - ld_impl_linux-aarch64 >=2.36.1 - libexpat >=2.8.1,<3.0a0 - libffi >=3.7.0,<3.8.0a0 - libgcc >=15 - liblzma >=5.8.3,<6.0a0 - libmpdec >=4.0.0,<5.0a0 - libsqlite >=3.53.4,<4.0a0 - libuuid >=2.42.2,<3.0a0 - libzlib >=1.3.2,<2.0a0 - ncurses >=6.6,<7.0a0 - openssl >=3.5.7,<4.0a0 - python_abi 3.14.* *_cp314 - readline >=8.3,<9.0a0 - tk >=8.6.13,<8.7.0a0 - tzdata - zstd >=1.5.7,<1.6.0a0 license: Python-2.0 run_exports: weak: - python_abi 3.14.* *_cp314 noarch: - python size: 35165847 timestamp: 1787154077054 python_site_packages_path: lib/python3.14/site-packages - conda: https://prefix.dev/conda-forge/linux-aarch64/readline-8.3-ha7194a6_1.conda sha256: 80167dcf73a96b6d0c1bb2298d7b8b9bc21b27cc5bf56979f9c548b49a4d1722 md5: 5b399a7afa10098f2a6b02263181426e depends: - libgcc >=15 - ncurses >=6.6,<7.0a0 license: GPL-3.0-only license_family: GPL run_exports: weak: - readline >=8.3,<9.0a0 size: 364344 timestamp: 1787033761576 - conda: https://prefix.dev/conda-forge/linux-aarch64/rhash-1.4.6-he30d5cf_2.conda sha256: b4e49255aa581788c28f0a4a19ba49756cea968998c599f40feadcfeb80d15fb md5: aa87887d8ec28a87ae84d996876e728e depends: - libgcc >=14 license: MIT license_family: MIT run_exports: weak: - rhash >=1.4.6,<2.0a0 size: 211434 timestamp: 1786731457243 - conda: https://prefix.dev/conda-forge/linux-aarch64/tk-8.6.13-noxft_hf03c496_4.conda build_number: 104 sha256: a1aa0d0f0b3d539644ff992e6dd0facf950c79df58fc37590ce5be84ff5e3f22 md5: ebaded4b4b74c2cc43a754ded4eed76f depends: - libgcc >=15 - libzlib >=1.3.2,<2.0a0 constrains: - xorg-libx11 >=1.8.13,<2.0a0 license: TCL run_exports: weak: - tk >=8.6.13,<8.7.0a0 size: 3664220 timestamp: 1787272859143 - conda: https://prefix.dev/conda-forge/linux-aarch64/zstd-1.5.7-h9d15635_7.conda sha256: 427fd14bcb3b8659796fecc682716617409350fb5a98e5b7b47558a10d1a2fc7 md5: d942e34ac3920ba83f8b2d0169570187 depends: - libzlib >=1.3.2,<2.0a0 license: BSD-3-Clause license_family: BSD run_exports: weak: - zstd >=1.5.7,<1.6.0a0 size: 615477 timestamp: 1786599613561 - conda: https://prefix.dev/conda-forge/noarch/ca-certificates-2026.7.22-hbd8a1cb_0.conda sha256: 0a0544cf95f64394fe4959286f5c71f5444ad58feb0602e53becb27448d24da6 md5: 0f51e2391ade309db462a55611263e9c depends: - __unix license: ISC run_exports: {} size: 131780 timestamp: 1784754889428 - conda: https://prefix.dev/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_1.conda sha256: ab29d57dc70786c1269633ba3dff20288b81664d3ff8d21af995742e2bb03287 md5: 962b9857ee8e7018c22f2776ffa0b2d7 depends: - python >=3.9 license: BSD-3-Clause license_family: BSD run_exports: {} size: 27011 timestamp: 1733218222191 - conda: https://prefix.dev/conda-forge/noarch/exceptiongroup-1.3.1-pyhd8ed1ab_0.conda sha256: ee6cf346d017d954255bbcbdb424cddea4d14e4ed7e9813e429db1d795d01144 md5: 8e662bd460bda79b1ea39194e3c4c9ab depends: - python >=3.10 - typing_extensions >=4.6.0 license: MIT and PSF-2.0 run_exports: {} size: 21333 timestamp: 1763918099466 - conda: https://prefix.dev/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda sha256: 43e2a5497cad1598ff88a3e69f69bc88b7b8f141fa63c60eab5db296317318b8 md5: ffc17e785d64e12fc311af9184221839 depends: - python >=3.10 - zipp >=3.20 - python license: Apache-2.0 license_family: APACHE run_exports: {} size: 34766 timestamp: 1779714582554 - conda: https://prefix.dev/conda-forge/noarch/iniconfig-2.3.0-pyhd8ed1ab_0.conda sha256: e1a9e3b1c8fe62dc3932a616c284b5d8cbe3124bbfbedcf4ce5c828cb166ee19 md5: 9614359868482abba1bd15ce465e3c42 depends: - python >=3.10 license: MIT license_family: MIT run_exports: {} size: 13387 timestamp: 1760831448842 - conda: https://prefix.dev/conda-forge/noarch/kernel-headers_linux-aarch64-4.18.0-h05a177a_9.conda sha256: 5d224bf4df9bac24e69de41897c53756108c5271a0e5d2d2f66fd4e2fbc1d84b md5: bb3b7cad9005f2cbf9d169fb30263f3e constrains: - sysroot_linux-aarch64 ==2.28 license: LGPL-2.0-or-later AND LGPL-2.0-or-later WITH exceptions AND GPL-2.0-or-later license_family: GPL run_exports: {} size: 1248134 timestamp: 1765578613607 - conda: https://prefix.dev/conda-forge/noarch/libgcc-devel_linux-aarch64-15.3.0-h6e7e4e0_107.conda sha256: e26af963eeca0f3a9b17182b1686f3a08ad3a7633e2da92b95052b320a48480d md5: 163cf0269dc64983bc6edf481a5557fb depends: - __unix license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL run_exports: {} size: 2346429 timestamp: 1790302128084 - conda: https://prefix.dev/conda-forge/noarch/libstdcxx-devel_linux-aarch64-15.3.0-h0e8df58_107.conda sha256: 7c821bf495207ca0157b38a9d2c935356ed8dba096ffacd6676adb76c759b89c md5: 709858d98ee8e0e91c4efddc6d02887f depends: - __unix license: GPL-3.0-only WITH GCC-exception-3.1 license_family: GPL run_exports: {} size: 17521094 timestamp: 1790302146011 - conda: https://prefix.dev/conda-forge/noarch/meson-1.12.0-pyhcf101f3_0.conda sha256: 6c158a48c43f0b2e03dd26521fe940991285fd149773aaeb5ead843b2bda92ca md5: 73afbaae293a0d6feed3a5559b6d4359 depends: - python >=3.10 - ninja >=1.8.2 - python license: Apache-2.0 license_family: APACHE run_exports: {} size: 796640 timestamp: 1786430108066 - conda: https://prefix.dev/conda-forge/noarch/packaging-26.3-pyhc364b38_0.conda sha256: c432626b16768b8dab228bfb706f7060c2d462a21c516d240f68f2f902b5a044 md5: 936687ed80f295a1f5dbcf8bd34c252c depends: - python >=3.9 - python license: Apache-2.0 license_family: APACHE run_exports: {} size: 116363 timestamp: 1785888127370 - conda: https://prefix.dev/conda-forge/noarch/pip-26.2.1-pyh145f28c_0.conda sha256: 0f7021cfb3ff454c91a5e28e1f5060906a52c6d1cde3f879a7d03ac33c28b1c3 md5: 573cb3ed111004230ed3de650653cd4d depends: - python >=3.13.0a0 license: MIT license_family: MIT run_exports: {} size: 1198163 timestamp: 1785914482439 - conda: https://prefix.dev/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e md5: d7585b6550ad04c8c5e21097ada2888e depends: - python >=3.9 - python license: MIT license_family: MIT run_exports: {} size: 25877 timestamp: 1764896838868 - conda: https://prefix.dev/conda-forge/noarch/pygments-2.21.0-pyhcf101f3_0.conda sha256: f5f015ff1bc3e1b7fc08eee096b1865234189ae0b82bebdb86a5369116e42fa0 md5: 2882dee445dfa45b0c5afce3ffb7730a depends: - python >=3.10 - python license: BSD-2-Clause license_family: BSD run_exports: {} size: 959376 timestamp: 1786995678795 - conda: https://prefix.dev/conda-forge/noarch/pyproject-metadata-0.12.1-pyhd8ed1ab_0.conda sha256: 9951d325225765ab01977f151abf9165cab68e5b73b93eac210dfb7322b74c65 md5: 5997c30f8b2310c4acf067a1a7c7ccc3 depends: - packaging >=23.2 - python >=3.10 license: MIT license_family: MIT run_exports: {} size: 27343 timestamp: 1783140019536 - conda: https://prefix.dev/conda-forge/noarch/pyproject_hooks-1.2.0-pyhd8ed1ab_1.conda sha256: 065ac44591da9abf1ff740feb25929554b920b00d09287a551fcced2c9791092 md5: d4582021af437c931d7d77ec39007845 depends: - python >=3.9 - tomli >=1.1.0 license: MIT license_family: MIT run_exports: {} size: 15528 timestamp: 1733710122949 - conda: https://prefix.dev/conda-forge/noarch/pytest-9.1.1-pyhc364b38_2.conda sha256: 430051d80765207a7d782b2b188230ba1489d35c6e75fd9903f76cb9fda4af16 md5: 64c98a12c4e23eb238bf66bbecafdf3c depends: - colorama - pygments >=2.7.2 - python >=3.10 - iniconfig >=1.0.1 - packaging >=22 - pluggy >=1.5,<2 - tomli >=1 - exceptiongroup >=1 - python constrains: - pytest-faulthandler >=2 license: MIT license_family: MIT run_exports: {} size: 306724 timestamp: 1782127176429 - conda: https://prefix.dev/conda-forge/noarch/pytest-mock-3.15.1-pyhd8ed1ab_0.conda sha256: 2936717381a2740c7bef3d96827c042a3bba3ba1496c59892989296591e3dabb md5: 0511afbe860b1a653125d77c719ece53 depends: - pytest >=6.2.5 - python >=3.10 license: MIT license_family: MIT run_exports: {} size: 22968 timestamp: 1758101248317 - conda: https://prefix.dev/conda-forge/noarch/python-build-1.5.0-pyhc364b38_0.conda sha256: eb8d5e44fddee9033eb7cfdd5ea584b7594b50e31c7602bef553af0fd4ee9266 md5: fa587158c0d768127faa1a3b4df01e5d depends: - python >=3.10 - colorama - importlib-metadata >=4.6 - packaging >=24.0 - pyproject_hooks - tomli >=1.1.0 - python constrains: - build <0 license: MIT license_family: MIT run_exports: {} size: 28946 timestamp: 1778048948266 - conda: https://prefix.dev/conda-forge/noarch/python_abi-3.14-8_cp314.conda build_number: 8 sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 md5: 0539938c55b6b1a59b560e843ad864a4 constrains: - python 3.14.* *_cp314 license: BSD-3-Clause license_family: BSD run_exports: {} size: 6989 timestamp: 1752805904792 - conda: https://prefix.dev/conda-forge/noarch/sysroot_linux-aarch64-2.28-h585391f_9.conda sha256: 1bd2db6b2e451247bab103e4a0128cf6c7595dd72cb26d70f7fadd9edd1d1bc3 md5: fdf07ab944a222ff28c754914fdb0740 depends: - __glibc >=2.28 - kernel-headers_linux-aarch64 4.18.0 h05a177a_9 - tzdata license: LGPL-2.0-or-later AND LGPL-2.0-or-later WITH exceptions AND GPL-2.0-or-later license_family: GPL run_exports: strong: - __glibc >=2.28,<3.0.a0 size: 23644746 timestamp: 1765578629426 - conda: https://prefix.dev/conda-forge/noarch/tomli-2.4.1-pyhcf101f3_0.conda sha256: 91cafdb64268e43e0e10d30bd1bef5af392e69f00edd34dfaf909f69ab2da6bd md5: b5325cf06a000c5b14970462ff5e4d58 depends: - python >=3.10 - python license: MIT license_family: MIT run_exports: {} size: 21561 timestamp: 1774492402955 - conda: https://prefix.dev/conda-forge/noarch/typing_extensions-4.16.0-pyhcf101f3_0.conda sha256: 2d888f90af0686044882c74193ec80a90ec1943145d94a7b1b048958acda1848 md5: c70ad746c22219b9700931707482992c depends: - python >=3.10 - python license: PSF-2.0 license_family: PSF run_exports: {} size: 52631 timestamp: 1783002732887 - conda: https://prefix.dev/conda-forge/noarch/tzdata-2026c-h151e31d_0.conda sha256: b928c30ddcb0e3f544c6eade8352737e6e610e263276b90232db6a578ef899d8 md5: fcb489df604d100968b737f2cb6076c6 license: LicenseRef-Public-Domain run_exports: {} size: 118849 timestamp: 1784250406640 - conda: https://prefix.dev/conda-forge/noarch/wheel-0.48.0-pyhd8ed1ab_0.conda sha256: ba64b29b6d418024cb565081a1799262cb2780d2534ff4c14f76aa858c4286cd md5: 9a2124517bfd5d792e0f7b86eefdfeb8 depends: - packaging >=24.0 - python >=3.10 license: MIT license_family: MIT run_exports: {} size: 34528 timestamp: 1786613220176 - conda: https://prefix.dev/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda sha256: 210bd31c22bb88f5e2a167df24c95bb5f152b2ada7502f9b8c49d1f5366db423 md5: ba3dcdc8584155c97c648ae9c044b7a3 depends: - python >=3.10 - python license: MIT license_family: MIT run_exports: {} size: 24190 timestamp: 1779159948016 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.github/workflows/pixi.toml0000664000000000000000000000155715257562503020343 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT [workspace] name = "meson-python" description = "The Python build backend for Meson projects" license = "MIT" documentation = "https://mesonbuild.com/meson-python" repository = "https://github.com/mesonbuild/meson-python" channels = ["https://prefix.dev/conda-forge"] platforms = ["linux-aarch64"] [dependencies] meson = "*" packaging = ">=24.2" pyproject-metadata = ">=0.9.0" ninja = "*" pkg-config = "*" cmake = "*" patchelf = "*" geos = "*" pip = "*" python-build = "*" cython = "*" pytest = "*" pytest-mock = "*" wheel = "*" [feature.compilers.dependencies] c-compiler = "*" cxx-compiler = "*" [environments] default = { features = ["compilers"], solve-group = "test" } system-compilers = { features = [], solve-group = "test" } [tasks] test = { cmd = "pytest", cwd = "../.." } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.github/workflows/release.yml0000664000000000000000000000213015257562503020624 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT name: release on: push: tags: - '[0-9]+.[0-9]+.[0-9]+' pull_request: branches: - main - release-* permissions: {} jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: persist-credentials: false - uses: actions/setup-python@v7 with: python-version: '3.14' - run: python -m pip install build - run: python -m build - uses: actions/upload-artifact@v7 with: path: dist/* upload: needs: build runs-on: ubuntu-latest if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') environment: name: pypi url: https://pypi.org/p/meson-python permissions: id-token: write steps: - uses: actions/download-artifact@v8 with: merge-multiple: true path: dist - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: print-hash: true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.github/workflows/tests.yml0000664000000000000000000002550315257562503020357 0ustar00rootroot# 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/**' - '!CHANGELOG.rst' - '!LICENSE' - '!LICENSES/**' - '!README.rst' - '!.github/workflows/docs.yml' workflow_dispatch: # Allow to run manually permissions: {} 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 }} strategy: fail-fast: false matrix: os: - ubuntu-latest - windows-latest - macos-latest # GitHub Actions switched to macOS on amr64 by default. Keep # a job running on macOS on x86-64 for a while longer. - macos-15-intel python: - '3.10' - '3.15' meson: - dependencies: - include: - os: ubuntu-latest python: 'pypy-3.11' # 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. # To avoid having too many CI jobs, combine this with tests # with the minimum version of other dependencies. - os: ubuntu-latest python: '3.11' meson: '~=0.64.0' - os: ubuntu-latest python: '3.11' meson: '~=1.0.0' - os: ubuntu-latest python: '3.11' meson: '~=1.1.0' - os: ubuntu-latest python: '3.12' meson: '~=1.2.3' - os: ubuntu-latest python: '3.12' meson: '~=1.3.0' - os: ubuntu-latest python: '3.12' meson: '~=1.4.0' - os: ubuntu-latest python: '3.12' meson: '~=1.5.0' dependencies: 'packaging==23.2 pyproject-metadata==0.9.0' - os: ubuntu-latest python: '3.12' meson: '~=1.6.0' dependencies: 'pyproject-metadata==0.9.0' - os: ubuntu-latest python: '3.12' meson: '~=1.7.0' dependencies: 'packaging==23.2' - os: ubuntu-latest python: '3.13' meson: '~=1.8.0' - os: ubuntu-latest python: '3.13' meson: '~=1.9.0' - os: ubuntu-latest python: '3.13' meson: '~=1.10.0' - os: ubuntu-latest python: '3.13' meson: '~=1.11.0' # Test with Meson master branch. - os: ubuntu-latest python: '3.14' meson: '@git+https://github.com/mesonbuild/meson.git' - os: windows-latest python: '3.14' meson: '@git+https://github.com/mesonbuild/meson.git' # Test free-threaded builds to verify the correct handling of the # 'abi3t' stable ABI, see PEP 803. Test on Linux and Windows to cover # the case where stable ABI extension modules use a dedicated # filename suffix and the case where they do not. - os: ubuntu-latest python: '3.15t' - os: windows-latest python: '3.15t' steps: - name: Checkout uses: actions/checkout@v7 with: persist-credentials: false - name: Set up target Python uses: actions/setup-python@v7 with: python-version: ${{ matrix.python }} allow-prereleases: true - name: Install Ninja run: sudo apt-get install ninja-build if: ${{ runner.os == 'Linux' }} - name: Install Ninja run: brew install ninja if: ${{ runner.os == 'macOS' }} - name: Install Ninja run: python -m pip install ninja if: ${{ runner.os == 'Windows' }} - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install dependencies run: python -m pip install ${{ matrix.dependencies }} if: ${{ matrix.dependencies }} - name: Install run: python -m pip install . --group test - name: Run tests run: python -m pytest --showlocals -vv --cov --cov-report=xml - name: Upload coverage report uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 if: ${{ always() }} env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} msvc: runs-on: windows-latest strategy: fail-fast: false matrix: python: - '3.11' meson: - steps: - name: Checkout uses: actions/checkout@v7 with: persist-credentials: false - name: Set up target Python uses: actions/setup-python@v7 with: python-version: ${{ matrix.python }} - name: Install Ninja run: python -m pip install ninja - name: Setup MSVC uses: bus1/cabuild/action/msdevshell@06ea2833eef61e9b0d0ce0d728416e617e4fb1fe # 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 . --group test - name: Run tests run: python -m pytest --showlocals -vv cygwin: runs-on: windows-latest strategy: fail-fast: false matrix: python: - '3.12' meson: - steps: - name: Checkout uses: actions/checkout@v7 with: persist-credentials: false - name: Setup Cygwin uses: cygwin/cygwin-install-action@3f0a3f9f988f7e96b8c18098ae05eaec175f5b52 # v6 with: packages: >- python312 python312-devel python312-pip python312-setuptools python312-virtualenv 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@v6 with: path: ${{ steps.pip-cache-path.outputs.path }} key: cygwin-pip-${{ github.sha }} restore-keys: cygwin-pip- lookup-only: true - 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 run: python -m pip install . --group 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} homebrew: runs-on: macos-latest strategy: fail-fast: false matrix: python: - '3.10' - '3.12' meson: - steps: - name: Checkout uses: actions/checkout@v7 with: persist-credentials: false - name: Install Homebrew Python run: | brew install --overwrite python@${{ matrix.python }} echo /opt/homebrew/opt/python@${{ matrix.python }}/libexec/bin/ >> $GITHUB_PATH python${{ matrix.python }} -m pip config set global.break-system-packages true - name: Check Python version run: python --version | grep ${{ matrix.python }} - name: Install Ninja run: brew install ninja - name: Install Meson run: python -m pip install "meson ${{ matrix.meson }}" if: ${{ matrix.meson }} - name: Install run: python -m pip install . --group test - name: Run tests run: python -m pytest --showlocals -vv mypy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v7 with: persist-credentials: false - name: Setup Python uses: actions/setup-python@v7 with: python-version: '3.10' - name: Install dependencies run: python -m pip install . - name: Install mypy run: python -m pip install mypy~=2.3.1 - name: Run mypy run: mypy -p mesonpy pixi: name: ${{ matrix.name }} runs-on: ubuntu-24.04-arm strategy: fail-fast: false matrix: include: - name: pixi environment: default - name: pixi-system-compilers environment: system-compilers steps: - name: Checkout uses: actions/checkout@v7 with: persist-credentials: false - uses: prefix-dev/setup-pixi@f00437f565399d418b0acc85936d12c1fb668347 # v0.10.1 with: pixi-version: v0.77.1 manifest-path: .github/workflows/pixi.toml environments: ${{ matrix.environment }} cache: false - name: Run tests working-directory: .github/workflows run: pixi run --environment ${{ matrix.environment }} test uv-sync: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: persist-credentials: false - name: Install uv uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0 with: enable-cache: false version: "0.12.13" # Released on 2026-09-10 # Ensure that dependencies and dependency groups are consistent and resolvable. - run: uv sync --all-extras --all-groups --dry-run ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.github/workflows/zizmor.yml0000664000000000000000000000107715257562503020547 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT name: zizmor on: push: branches: - main paths: - .github/workflows/* pull_request: branches: - main - release-* paths: - .github/workflows/* permissions: {} jobs: zizmor: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 with: persist-credentials: false - run: python -m pip install zizmor==1.29.0 - run: zizmor . env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.github/zizmor.yml0000664000000000000000000000025415257562503016506 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT rules: unpinned-uses: config: policies: actions/*: ref-pin ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.gitignore0000664000000000000000000000031515257562503015057 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT .mesonpy-native-file.ini .mesonpy/ docs/_build *.pyc .cache/ dist/ .coverage tests/packages/**/.wraplock *.lock ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.mailmap0000664000000000000000000000024715257562503014514 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT Matthias Kรถppe Yue Yang ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/.pre-commit-config.yaml0000664000000000000000000000202515257562503017350 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT # 'pre-commit' is not a project dependency -- if needed, users may choose to install it ci: autofix_prs: false autoupdate_commit_msg: 'MAINT: bump pre-commit dependencies' autoupdate_schedule: 'quarterly' repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v5.0.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: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.6.9 hooks: - id: ruff args: [--fix, --show-fixes, --output-format, grouped] - repo: https://github.com/fsfe/reuse-tool rev: v4.0.3 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=1790895427.0 meson_python-0.22.1/.vscode/settings.json0000664000000000000000000000022015257562503017156 0ustar00rootroot{ "python.testing.pytestArgs": [ "." ], "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/CHANGELOG.rst0000664000000000000000000004065015257562503015116 0ustar00rootroot.. 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.22.1 ====== - Do not remove absolute build RPATH entries, unless pointing within the build directory. Fixes an issue when using system compilers in a conda environment. Daniele Nicolodi, Ralf Gommers --- 01-10-2026. 0.22.0 ====== - Add support for adding RPATH entries specified with ``install_rpath`` argument to Meson functions that accept it. - Add support for removing build RPATH entries added by Meson to allow executing parts of the project from the build directory. - Fix corner cases in handling RPATH entries and relocation of shared libraries distributed as part of Python packages. Daniele Nicolodi, Mike Taves, Nathan Goldbaum, Ralf Gommers --- 25-09-2026. 0.21.1 ====== - Restore compatibility with Python interpreters not implementing PEP 3149. Daniele Nicolodi, Ralf Gommers --- 11-09-2026. 0.21.0 ====== - Add support for the stable ABI for free-threaded interpreters (``abi3t``). - Add support for the stable ABI extension modules' platform-specific filename suffixes introduced in Python 3.15. - Allow specifying ``editable-verbose`` in ``pyproject.toml``. - Improve the default behavior of editable installs by capturing and reporting build errors when rebuilding. - Use ``.start`` files (PEP 829) instead of ``.pth`` files to implement editable wheels for Python 3.15 and later. - From this release onwards, SSH keys used to sign release tags. Daniele Nicolodi, Michaล‚ Gรณrny, Ralf Gommers --- 07-09-2026. 0.20.0 ====== - Add support for targeting the Android platform. Daniele Nicolodi, Malcolm Smith, Ralf Gommers --- 10-06-2026. 0.19.0 ====== - Drop Python 3.8 support. - Development-related extras were moved to dependency groups. - Add support for targeting the iOS platform. - The ``strip`` binary is now included in synthesized cross files. - Documentation improvements: add more examples for specific use cases, and a contributing guide. - Use trusted publishing with digital attestations to upload release artifacts to PyPI. Andrew Annex, Daniele Nicolodi, Michaล‚ Gรณrny, Ralf Gommers, Russell Keith-Magee, Tobias Diez --- 14-01-2026. 0.18.0 ====== - Drop Python 3.7 support. - Bump minimum required Meson version to 0.64.0. - Bump minimum required ``pyproject-metadata`` version to 0.9.0 to enable support for PEP 639. - Bump minimum required ``packaging`` version to 23.2. ``pyproject-metadata`` version 0.9.1 requires this version of ``packaging`` but fails to record the version requirement in the package metadata. Enforcing the version requirement in ``meson-python`` allows fixing possible dependency problems without having ``meson-python`` depend on a very recent ``pyproject-metadata`` release. - Add support for PEP 639 metadata fields. Canonicalization and validation of the license expression requires ``packaging`` version 24.2 or later. - Add support for declaring the ``licence`` and ``license-files`` as dynamic fields in ``pyproject.toml`` to extract the package license and license files from the ones declared via the ``project()`` call in ``meson.build``. This requires Meson version 1.6.0 or later. - Add support for ``RPATH`` handling on SunOS. - Include shared libraries built as part of the Meson project in the Python wheels also on Windows, when explicitly enabled via the ``tool.meson-python.allow-windows-internal-shared-libs`` project setting. - Add support for symbolic links that point to files within the source tree. They are now included as regular files in the sdist archive. Daniele Nicolodi, Marcel Telka, Ralf Gommers --- 30-04-2025. 0.17.1 ====== - Update tests to work with newly released ``pyproject-metadata`` 0.9.0. - Fix tests to work when not executed in a git work tree. Daniele Nicolodi --- 23-10-2024. 0.17.0 ====== - Refuse to build wheels targeting the limited API and free-threaded CPython: the free-threaded CPython build does not support the limited API yet. - Always use UTF-8 encoding for writing Meson native and cross files. Always use UTF-8 encoding for reading read Meson introspection data and ``pyproject.toml``. - Do not include uncommitted changes when creating source distributions. Previously, uncommitted changes to files under version control were included, but not untracked files. There was no strong use case for this behavior and it was too surprising to keep it. - Make source distribution reproducible: use the modification time of ``pyproject.toml`` for the generated files in the source distribution archives. - Disable the ``abi3`` wheel tag for PyPy when building wheels targeting the limited API: PyPy supports the limited API but not the stable ABI. - Raise ``ImportError`` when the package rebuild fails when importing an editable install. - Fix the wheel platform tag for GraalPy. - Add ``.gitignore`` and ``.hgignore`` files to build directory if it is empty. - Allow ``install_subdir()`` of missing directories. Christian Clauss, Daniele Nicolodi, Jonathan J. Helmus, Leo Singer, Loรฏc Estรจve, Michael Simacek, Ralf Gommers, Simon McVittie --- 19-10-2024. 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=1790895427.0 meson_python-0.22.1/LICENSE0000664000000000000000000000220315257562503014072 0ustar00rootrootCopyright ยฉ 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=1790895427.0 meson_python-0.22.1/LICENSES/MIT.txt0000664000000000000000000000220315257562503015464 0ustar00rootrootCopyright ยฉ 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=1790895427.0 meson_python-0.22.1/README.rst0000664000000000000000000000172215257562503014561 0ustar00rootroot.. 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=1790895427.0 meson_python-0.22.1/RELEASE.rst0000664000000000000000000000274215257562503014707 0ustar00rootroot.. SPDX-FileCopyrightText: 2023 The meson-python developers .. .. SPDX-License-Identifier: MIT Release Process =============== Releases are published as git tags, signed with either an SSH or a PGP key belonging to a maintainer. The signing key must be registered on GitHub so that GitHub shows the tag as verified. You may release the project by following these steps: #. Release to the Git repository on GitHub: #. Create the release commit #. Bump the versions in ``pyproject.toml`` and in ``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 signed tag for the release: .. code-block:: console $ git tag -s X.Y.Z This signs with your PGP key by default. To sign with an SSH key instead, configure git once beforehand: .. code-block:: console $ git config --global gpg.format ssh $ git config --global user.signingkey ~/.ssh/id_ed25519.pub The SSH signing key must be registered on GitHub as a Signing Key for the tag to show as verified. 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 tag to the repository: .. code-block:: console $ git push --tags #. Release to PyPI is done via trusted publishing, triggering on the tag. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/REUSE.toml0000664000000000000000000000052515257562503014652 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # SPDX-License-Identifier: MIT version = 1 [[annotations]] path = [ ".github/workflows/pixi.lock", "tests/packages/install-data/data.txt", "tests/packages/simple/data.txt", ] SPDX-FileCopyrightText = "2026 The meson-python developers" SPDX-License-Identifier = "MIT" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/codecov.yml0000664000000000000000000000037615257562503015243 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/docs/about.rst0000664000000000000000000000453315257562503015671 0ustar00rootroot.. 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 `_ Emeritus maintainers: - `Filipe Laรญns `_ - `Thomas Li `_ 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`_. From ``0.21.0`` onwards, releases are published as signed tags, signed with either an SSH or a PGP key belonging to `@rgommers`_ or `@dnicolodi`_. Those signing keys can be retrieved from GitHub. Releases up to and including ``0.20.0`` 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/ .. _@rgommers: https://github.com/rgommers .. _@dnicolodi: https://github.com/dnicolodi .. |3DCE51D60930EBA47858BA4146F633CBB0EB4BF2| replace:: ``3DCE51D60930EBA47858BA4146F633CBB0EB4BF2`` .. _3DCE51D60930EBA47858BA4146F633CBB0EB4BF2: https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3dce51d60930eba47858ba4146f633cbb0eb4bf2 .. |52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5| replace:: ``52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5`` .. _52BDC33FD1FBAB569D47FFA923D9E5499A08BDC5: https://github.com/rgommers.gpg ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/changelog.rst0000664000000000000000000004065015257562503016506 0ustar00rootroot.. 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.22.1 ====== - Do not remove absolute build RPATH entries, unless pointing within the build directory. Fixes an issue when using system compilers in a conda environment. Daniele Nicolodi, Ralf Gommers --- 01-10-2026. 0.22.0 ====== - Add support for adding RPATH entries specified with ``install_rpath`` argument to Meson functions that accept it. - Add support for removing build RPATH entries added by Meson to allow executing parts of the project from the build directory. - Fix corner cases in handling RPATH entries and relocation of shared libraries distributed as part of Python packages. Daniele Nicolodi, Mike Taves, Nathan Goldbaum, Ralf Gommers --- 25-09-2026. 0.21.1 ====== - Restore compatibility with Python interpreters not implementing PEP 3149. Daniele Nicolodi, Ralf Gommers --- 11-09-2026. 0.21.0 ====== - Add support for the stable ABI for free-threaded interpreters (``abi3t``). - Add support for the stable ABI extension modules' platform-specific filename suffixes introduced in Python 3.15. - Allow specifying ``editable-verbose`` in ``pyproject.toml``. - Improve the default behavior of editable installs by capturing and reporting build errors when rebuilding. - Use ``.start`` files (PEP 829) instead of ``.pth`` files to implement editable wheels for Python 3.15 and later. - From this release onwards, SSH keys used to sign release tags. Daniele Nicolodi, Michaล‚ Gรณrny, Ralf Gommers --- 07-09-2026. 0.20.0 ====== - Add support for targeting the Android platform. Daniele Nicolodi, Malcolm Smith, Ralf Gommers --- 10-06-2026. 0.19.0 ====== - Drop Python 3.8 support. - Development-related extras were moved to dependency groups. - Add support for targeting the iOS platform. - The ``strip`` binary is now included in synthesized cross files. - Documentation improvements: add more examples for specific use cases, and a contributing guide. - Use trusted publishing with digital attestations to upload release artifacts to PyPI. Andrew Annex, Daniele Nicolodi, Michaล‚ Gรณrny, Ralf Gommers, Russell Keith-Magee, Tobias Diez --- 14-01-2026. 0.18.0 ====== - Drop Python 3.7 support. - Bump minimum required Meson version to 0.64.0. - Bump minimum required ``pyproject-metadata`` version to 0.9.0 to enable support for PEP 639. - Bump minimum required ``packaging`` version to 23.2. ``pyproject-metadata`` version 0.9.1 requires this version of ``packaging`` but fails to record the version requirement in the package metadata. Enforcing the version requirement in ``meson-python`` allows fixing possible dependency problems without having ``meson-python`` depend on a very recent ``pyproject-metadata`` release. - Add support for PEP 639 metadata fields. Canonicalization and validation of the license expression requires ``packaging`` version 24.2 or later. - Add support for declaring the ``licence`` and ``license-files`` as dynamic fields in ``pyproject.toml`` to extract the package license and license files from the ones declared via the ``project()`` call in ``meson.build``. This requires Meson version 1.6.0 or later. - Add support for ``RPATH`` handling on SunOS. - Include shared libraries built as part of the Meson project in the Python wheels also on Windows, when explicitly enabled via the ``tool.meson-python.allow-windows-internal-shared-libs`` project setting. - Add support for symbolic links that point to files within the source tree. They are now included as regular files in the sdist archive. Daniele Nicolodi, Marcel Telka, Ralf Gommers --- 30-04-2025. 0.17.1 ====== - Update tests to work with newly released ``pyproject-metadata`` 0.9.0. - Fix tests to work when not executed in a git work tree. Daniele Nicolodi --- 23-10-2024. 0.17.0 ====== - Refuse to build wheels targeting the limited API and free-threaded CPython: the free-threaded CPython build does not support the limited API yet. - Always use UTF-8 encoding for writing Meson native and cross files. Always use UTF-8 encoding for reading read Meson introspection data and ``pyproject.toml``. - Do not include uncommitted changes when creating source distributions. Previously, uncommitted changes to files under version control were included, but not untracked files. There was no strong use case for this behavior and it was too surprising to keep it. - Make source distribution reproducible: use the modification time of ``pyproject.toml`` for the generated files in the source distribution archives. - Disable the ``abi3`` wheel tag for PyPy when building wheels targeting the limited API: PyPy supports the limited API but not the stable ABI. - Raise ``ImportError`` when the package rebuild fails when importing an editable install. - Fix the wheel platform tag for GraalPy. - Add ``.gitignore`` and ``.hgignore`` files to build directory if it is empty. - Allow ``install_subdir()`` of missing directories. Christian Clauss, Daniele Nicolodi, Jonathan J. Helmus, Leo Singer, Loรฏc Estรจve, Michael Simacek, Ralf Gommers, Simon McVittie --- 19-10-2024. 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=1790895427.0 meson_python-0.22.1/docs/conf.py0000664000000000000000000000142415257562503015320 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT import datetime import os import time import sys _build_time = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) _build_date = datetime.datetime.fromtimestamp(_build_time, tz=datetime.timezone.utc) project = 'meson-python' copyright = f'2021\N{EN DASH}{_build_date.year} The meson-python developers' html_theme = 'furo' html_title = f'meson-python' extensions = [ 'sphinx_copybutton', 'sphinx_design', 'sphinxext.opengraph', 'sphinx.ext.intersphinx', ] # sphinx.ext.intersphinx intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} # sphinxext.opengraph ogp_site_url = 'https://mesonbuild.com/meson-python/' ogp_site_name = 'meson-python documentation' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/explanations/default-options.rst0000664000000000000000000000777715257562503022416 0ustar00rootroot.. 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=1790895427.0 meson_python-0.22.1/docs/explanations/design-old.rst0000664000000000000000000000557515257562503021320 0ustar00rootroot.. 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. 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=1790895427.0 meson_python-0.22.1/docs/how-to-guides/config-settings.rst0000664000000000000000000001124515257562503022353 0ustar00rootroot.. 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/build :sync: key_pypa_build .. code-block:: console $ python -m build --wheel \ -Csetup-args="-Doption=true" \ -Csetup-args="-Dvalue=1" \ -Ccompile-args="-j6" .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel . \ -Csetup-args="-Doption=true" \ -Csetup-args="-Dvalue=1" \ -Ccompile-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:: Older pip versions :class: caution Please note that prior to version 23.1 ``pip`` did not support the ``-C`` short command line switch for the ``--config-settings`` options and 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/ Using a persistent build directory ================================== By default, ``meson-python`` uses a temporary build directory which is deleted when the build terminates. A persistent build directory allows faster incremental builds and to access build logs and intermediate build artifacts. The :option:`build-dir` config setting can be used to build in a user-specified build directory which will not be deleted. For example: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build --wheel -Cbuild-dir=build .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip install . -Cbuild-dir=build After running this command, the ``build`` directory will contain all the build artifacts and support files created by ``meson``, ``ninja`` and ``meson-python``. The same build directory can be used by subsequent invocations of ``meson-python``, avoiding the need to rebuild the whole project when testing changes during development. Using a permanent build directory also aids in debugging a failing build by allowing access to build logs and intermediate build outputs, including the Meson introspection files and detailed log. The latter is stored in the ``meson-logs/meson-log.txt`` file in the build directory and can be useful to diagnose why a build fails at the project configuration stage. For example, to understand why dependency detection failed, it is often necessary to look at the ``pkg-config`` or other dependency detection methods output. Access to detailed logs and intermediate build outputs is particularly helpful in CI setups where introspecting the build environment is usually more difficult than on a local system. Therefore, it can be useful to show the more detailed log files when the CI build step fails. For example, the following GitHub Actions workflow file snippet shows the detailed Meson setup log when the build fails: .. code-block:: yaml - name: Build the package run: python -m build --wheel -Cbuild-dir=build - name: Show meson-log.txt if: ${{ failure() }} run: cat build/meson-logs/meson-log.txt Replacing ``failure()`` with ``always()`` in the code above will result in the Meson log file always being shown. See the GitHub Actions documentation__ for more details. Please be aware that the setup log can become very long for complex projects, and the GitHub Actions web interface becomes unresponsive when the running job emits many output lines. __ https://docs.github.com/en/actions/learn-github-actions/expressions#status-check-functions ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/how-to-guides/contributing.rst0000664000000000000000000000551415257562503021761 0ustar00rootroot.. SPDX-FileCopyrightText: 2021 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _how-to-guides-contributing: Contributing ============ Thank you for your interest in contributing. ``meson-python`` development is hosted on GitHub_ and uses the ubiquitous pull-request based workflow. The usual Python development practices apply. Python source code should adhere to the `PEP 8`_ code style with a maximum line length of 127 characters. Single quotes are used as string delimiters. Python code uses type annotations verified via Mypy_ and is kept clean linting it with Ruff_. ``meson-python`` focus is producing Python wheels containing extension modules and thus running its test suite requires C and C++ compilers, and CMake. The ``patchelf`` utility is required on Linux. These are best installed via the system package manager. The documentation is written in reST format and the published version is generated with Sphinx_. To work on the code: 1. Fork the repository. 2. Set up the development environment by creating a virtual environment and installing the necessary dependencies for development and testing: .. code-block:: console $ uv venv $ source .venv/bin/activate $ uv pip install meson ninja pyproject-metadata $ uv pip install --no-build-isolation --editable . $ uv pip install --group test $ uv pip install ruff mypy 3. Create your branch from the ``main`` branch. 4. Hack away. Add tests as necessary. 5. Run the linter, the type checker, and the test suite: .. code-block:: console $ ruff check $ mypy $ pytest 6. Organize your changes in logical commits with clear, concise, and well formatted commit messages describing the motivation for the change. Commit messages should be organized in a subject line, describing the commit briefly, followed by a blank line, and more test if needed. Lines should be word wrapped at 72 characters. The subject line should start with a capitalized acronym indicating the nature of the commit, followed by a colon. Used acronyms include: "BUG" for bug fixes, "ENH" for new features and other enhancements, "TST" for addition or modification of tests, "MAINT" for maintenance commits, typically refactoring, typo or code style fixes, "DOC" for documentation, "CI" for changes to the continuous integration setup. To work on the documentation: 1. Install the required tools: .. code-block:: console $ uv pip install --group docs 2. Generate and inspect the HTML documentation: .. code-block:: console $ python -m sphinx docs html $ open html/index.html .. _GitHub: https://github.com/meson/meson-python/ .. _Mypy: https://mypy.readthedocs.io .. _PEP 8: https://www.python.org/dev/peps/pep-0008/ .. _Ruff: https://docs.astral.sh/ruff/ .. _Sphinx: https://www.sphinx-doc.org ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/how-to-guides/debug-builds.rst0000664000000000000000000000423015257562503021612 0ustar00rootroot.. 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=1790895427.0 meson_python-0.22.1/docs/how-to-guides/editable-installs.rst0000664000000000000000000001732515257562503022655 0ustar00rootroot.. 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. Data files ---------- It is relatively common to install data files needed at runtime alongside the package's Python code or extension modules. For a Python package named ``package`` this would look like this: .. TODO the :force: option should be removed once the pygments meson lexer is updated to fix https://github.com/pygments/pygments/issues/2918 .. literalinclude:: ../../tests/packages/install-data/meson.build :language: meson :force: :lines: 5- In most circumstances, these files can be accessed deriving their filesystem path from the filesystem path of the Python module next to them via the ``__file__`` special variable. For example, within the package ``__init__.py``: .. code-block:: python import pathlib data = pathlib.Path(__file__).parent.joinpath('data.txt').read_text() uuid = pathlib.Path(__file__).parent.joinpath('uuid.txt').read_text() # WRONG! However, this does not work when modules are not loaded from a package installed in the Python library path in the filesystem but with a special module loader, as used to implement editable installs in ``meson-python``. In the example above, the second read would fail when the package is installed in editable mode. For this reason, data files need to be accessed using :mod:`importlib.resources`. The code above should be replaced with: .. literalinclude:: ../../tests/packages/install-data/__init__.py :lines: 5- :mod:`importlib.resources` implements a virtual filesystem that allows to access individual files as if they were in their install location. However, there is no way to expose this file structure outside of the python runtime. In the example above, it is not possible to make the ``data.txt`` and ``uuid.txt`` files appear in the same fileystem directory. .. warning:: The :mod:`importlib.resources` appeared in Python 3.7 but it did not work correctly for this use until Python 3.10. The `importlib-resources`_ backport version 5.10 or later can be used if support for earlier Python versions is desired. .. _importlib-resources: https://importlib-resources.readthedocs.io/en/latest/index.html .. _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:`tool.meson-python.editable-verbose` option can be set in ``pyproject.toml`` or 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 -Ceditable-verbose=true --editable . .. warning:: ``ninja`` outputs the compilation log on standard output thus it cannot be separated from expected output from command line tools via output redirection. This may make the output of command line tools that import the package harder to use. Consider this carefully when enabling verbose output in package configuration. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/how-to-guides/limited-api.rst0000664000000000000000000001446515257562503021455 0ustar00rootroot.. SPDX-FileCopyrightText: 2026 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _howto-limited-api: *********************************** Targeting the CPython Limited C API *********************************** This page describes how to configure your package to build against the CPython `limited API`_ and build `stable ABI`_ wheels. Limited API builds target a minimum interpreter version and produce a single wheel that can support newer interpreter versions. You can enable limited API builds by default or make them opt-in. We recommend making them opt-in to avoid failures or special handling when building for interpreters that do not support the stable ABI, such as free-threaded CPython 3.14. Using the version-specific C API can also `improve performance`_ for source installations and distribution packages that do not need the stable ABI. Compile your extension modules for the limited API by specifying the ``limited_api`` argument to the ``extension_module()`` function in the Meson Python module. The version passed to ``limited_api`` selects the limited API your extension uses. Meson converts this version to the corresponding value of the ``Py_LIMITED_API`` preprocessor macro. The wheel's :ref:`Python compatibility tag ` still corresponds to the interpreter used for the build, regardless of the ``limited_api`` version you select. Enabling the :option:`tool.meson-python.limited-api` setting declares that all the extension modules in your package target the limited API and adjusts the wheel filename ABI tag accordingly: .. code-block:: meson py = import('python').find_installation(pure: false) py.extension_module( '_core', '_core.c', limited_api: '3.10', install: true, subdir: 'example', ) .. code-block:: toml [tool.meson-python] limited-api = true For limited API builds, on platforms where Python extension modules targeting the stable ABI use a dedicated filename suffix, ``meson-python`` verifies that all the extension modules included in the wheel use the stable ABI filename suffix and fails the build otherwise. .. _opt-in-limited-api-example: Set up Limited API support as opt-in ------------------------------------ To make limited API builds opt-in, add ``python.allow_limited_api=false`` to the ``default_options`` in your existing ``project()`` call in ``meson.build``: .. code-block:: meson project( 'example', 'c', default_options: ['python.allow_limited_api=false'], ) Keep ``limited-api = true`` in ``pyproject.toml`` and the ``limited_api`` argument to ``extension_module()`` as shown above. When ``python.allow_limited_api`` is false, Meson ignores the ``limited_api`` argument, compiles extension modules for the ABI of the interpreter used for the build, and produces a wheel tagged as compatible with the build interpreter. To build a stable ABI wheel, explicitly enable limited API builds: .. tab-set:: .. tab-item:: pypa/build :sync: key_pypa_build .. code-block:: console $ python -m build --wheel -Csetup-args="-Dpython.allow_limited_api=true" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel -Csetup-args="-Dpython.allow_limited_api=true" . .. _limited-api-wheel-tags: Limited API compatibility ------------------------- ``meson-python`` conservatively chooses the wheel's Python compatibility tag based only on the interpreter used for the build, regardless of the target ``limited_api`` version. For example, a wheel built with CPython 3.12 for the 3.10 limited API is tagged ``cp312-abi3`` and can be installed only on GIL-enabled CPython 3.12 and later. When building stable ABI wheels for distribution, for example on PyPI, build with the oldest CPython version you want the wheel to support, as `recommended by CPython`_. If you are installing from source into a particular environment, use that environment's interpreter; you do not need to build with the oldest supported version. PyPy supports the limited API, but does not implement a stable ABI, thus the :option:`tool.meson-python.limited-api` setting has no effect on the wheel tags when building with PyPy. The ``abi3t`` stable ABI ------------------------ CPython 3.15 introduces the ``abi3t`` stable ABI. Extension modules built for ``abi3t`` can be loaded by both the GIL-enabled and the free-threaded builds of CPython 3.15 and later: a single wheel tagged ``abi3.abi3t`` supports all CPython interpreters from version 3.15 on. ``abi3t`` extension modules require limited API version 3.15 or later and, currently, a free-threaded interpreter for the build: compiling for ``abi3t`` with a GIL-enabled interpreter is not supported yet. Once you have made the source changes described in the `abi3t migration guide`_, no additional build configuration is required: the CPython headers select ``abi3t`` when ``Py_LIMITED_API`` is defined while compiling for a free-threaded interpreter. Meson refuses a ``limited_api`` version newer than the interpreter used for the build. If you build ``abi3`` wheels for older CPython versions and ``abi3.abi3t`` wheels for CPython 3.15 and later, you can select the limited API version by querying the ``Py_GIL_DISABLED`` sysconfig variable, which is 1 for free-threaded builds: .. code-block:: meson py = import('python').find_installation(pure: false) limited_api = '3.10' if py.language_version().version_compare('>=3.15') if py.get_variable('Py_GIL_DISABLED') == 1 limited_api = '3.15' endif endif py.extension_module( '_core', '_core.c', limited_api: limited_api, install: true, subdir: 'example', ) Free-threaded CPython 3.13 and 3.14 do not support the limited API: disable limited API builds when using these interpreters. The :ref:`opt-in configuration above ` disables them by default. .. _limited API: https://docs.python.org/3/c-api/stable.html#limited-c-api .. _stable ABI: https://docs.python.org/3/c-api/stable.html#stable-application-binary-interface .. _recommended by CPython: https://docs.python.org/3/c-api/stable.html#limited-api-caveats .. _improve performance: https://docs.python.org/3/c-api/stable.html#limited-api-scope-and-performance .. _abi3t migration guide: https://docs.python.org/3.15/howto/abi3t-migration.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/how-to-guides/meson-args.rst0000664000000000000000000001517315257562503021327 0ustar00rootroot.. 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 --wheel -Csetup-args="--default-library=static" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel -Csetup-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 --wheel -Cinstall-args="--tags=runtime,python-runtime" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel -Cinstall-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 --wheel -Csetup-args="-Doptimization=3" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel -Csetup-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'] And in case you don't want to set ``--vsenv`` as the default, but do want to build Windows wheels with MSVC in CI using cibuildwheel: .. code-block:: toml [tool.cibuildwheel.windows] config-settings = { setup-args = ["--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 --wheel -Csetup-args="--vsenv" . .. tab-item:: pip :sync: key_pip .. code-block:: console $ python -m pip wheel -Csetup-args="--vsenv" . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/how-to-guides/sdist.rst0000664000000000000000000000437115257562503020400 0ustar00rootroot.. SPDX-FileCopyrightText: 2024 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _sdist: ****************************** Creating a source distribution ****************************** A source distribution for the project can be created executing .. code-block:: console $ python -m build --sdist . in the project root folder. This will create a ``.tar.gz`` archive in the ``dist`` folder in the project root folder. This archive contains the full contents of the latest commit in revision control with all revision control metadata removed. Uncommitted modifications and files unknown to the revision control system are not included. The source distribution archive is created by adding the required metadata files to the archive obtained by executing the ``meson dist --no-tests --allow-dirty`` command. To generate a source distribution, ``meson-python`` must successfully configure the Meson project by running the ``meson setup`` command. Additional arguments can be passed to ``meson dist`` to alter its behavior. Refer to the relevant `Meson documentation`__ and to the :ref:`how-to-guides-meson-args` guide for details. The ``meson dist`` command uses the archival tool of the underlying revision control system for creating the archive. This implies that a source distribution can only be created for a project versioned in a revision control system. Meson supports the Git and Mercurial revision control systems. Files can be excluded from the source distribution via the relevant mechanism provided by the revision control system. When using Git as a revision control system, it is possible to exclude files from the source distribution setting the ``export-ignore`` attribute. For example, adding a ``.gitattributes`` files containing .. code-block:: none dev/** export-ignore would result in the ``dev`` folder to be excluded from the source distribution. Refer to the ``git archive`` documentation__ for details. Another mechanism to alter the content of the source distribution is offered by dist scripts. Refer to the relevant `Meson documentation`__ for details. __ https://mesonbuild.com/Creating-releases.html __ https://git-scm.com/docs/git-archive#ATTRIBUTES __ https://mesonbuild.com/Reference-manual_builtin_meson.html#mesonadd_dist_script ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/how-to-guides/shared-libraries.rst0000664000000000000000000002703515257562503022474 0ustar00rootroot.. SPDX-FileCopyrightText: 2024 The meson-python developers .. .. SPDX-License-Identifier: MIT .. _shared-libraries: ********************** Using shared libraries ********************** Python projects may build shared libraries as part of their project, or link with shared libraries from a dependency. This tends to be a common source of issues, hence this page aims to explain how to include shared libraries in wheels, any limitations and gotchas, and how support is implemented in ``meson-python`` under the hood. We distinguish between *internal* shared libraries that are built as part of the project, and *external* shared libraries that are provided by project dependencies and that are linked with the project build artifacts. For internal shared libraries, we also distinguish whether the shared library is being installed to its default system location (typically ``/usr/local/lib`` on Unix-like systems, and ``C:\\lib`` on Windows - we call this ``libdir`` in this guide) or to a location in ``site-packages`` within the Python package install tree. All these scenarios are (or will be) supported, with some caveats: +-----------------------+------------------+------------+-------+-------+ | shared library source | install location | Windows | macOS | Linux | +=======================+==================+============+=======+=======+ | internal | libdir | โœ“ :sup:`1` | โœ“ | โœ“ | +-----------------------+------------------+------------+-------+-------+ | internal | site-packages | โœ“ | โœ“ | โœ“ | +-----------------------+------------------+------------+-------+-------+ | external | --- | โœ“ :sup:`2` | โœ“ | โœ“ | +-----------------------+------------------+------------+-------+-------+ .. TODO: add subproject as a source 1. Support for internal shared libraries on Windows is enabled with the :option:`tool.meson-python.allow-windows-internal-shared-libs` option and requires cooperation from the package to extend the DLL search path or preload the required libraries. See below for more details. 2. External shared libraries require ``delvewheel`` usage on Windows (or some equivalent way, like amending the DLL search path to include the directory in which the external shared library is located). Due to the lack of `RPATH `__ support on Windows, there is no good way around this. .. _internal-shared-libraries: Internal shared libraries ========================= A shared library produced by ``library()`` or ``shared_library()`` built like this .. code-block:: meson example_lib = shared_library( 'example', 'examplelib.c', install: true, ) is installed to ``libdir`` by default. If the only reason the shared library exists is to be used inside the Python package being built, then it is best to modify the install location, via the ``install_dir`` argument, to be within the Python package itself: .. code-block:: meson example_lib = shared_library( 'example', 'examplelib.c', install: true, install_dir: py.get_install_dir() / 'mypkg/subdir', ) On Linux, macOS, and in general on all systems except Windows, an extension module can dynamically link against a shared library installed in the same package by using ``install_rpath`` with a relative path: .. code-block:: meson py.extension_module('_extmodule', '_extmodule.c', link_with: example_lib, install: true, subdir: 'mypkg/subdir', install_rpath: host_machine.system() == 'darwin' ? '@loader_path' : '$ORIGIN' ) Note that Mach-O binaries on macOS use the ``@loader_path`` token to indicate the location of the current executable or shared library while ELF binaries use the ``$ORIGIN`` token. For backward compatibility, ``meson-python`` translates the more common ``$ORIGIN`` token to the macOS-specific ``@loader_path`` token when building on macOS. However, Meson itself does not, thus relying on this translation is discouraged. Windows needs some special handling though, due to the lack of RPATH support: .. literalinclude:: ../../tests/packages/sharedlib-in-package/mypkg/__init__.py :start-after: start-literalinclude :end-before: end-literalinclude If an internal shared library is not only used as part of a Python package, but for example also as a regular shared library then the method shown above won't work. The library is then marked for installation into the system default ``libdir`` location. Actually installing into ``libdir`` isn't possible with wheels, hence ``meson-python`` will instead do the following: 1. Install the shared library to the ``..mesonpy.libs`` top-level directory in the wheel, which on install will end up in ``site-packages``. 2. On platforms other than Windows, rewrite RPATH entries for install targets that depend on the shared library to point to that new install location instead. On platforms other than Windows, this will make the shared library work automatically, with no other action needed from the package author. On Windows, due to the lack of RPATH support, the ``..mesonpy.libs`` location search path needs to be added to the DLL search path, with code similar to the one presented above. For this reason, handling of internal shared libraries on Windows is conditional to setting the :option:`tool.meson-python.allow-windows-internal-shared-libs` option. External shared libraries ========================= External shared libraries are installed somewhere on the build machine, and usually detected by a ``dependency()`` or ``compiler.find_library()`` call in a ``meson.build`` file. When a Python extension module or executable uses the dependency, the shared library will be linked against at build time. If the shared library is located in a directory on the loader search path, the wheel created by ``meson-python`` will work locally when installed. If it's in a non-standard location however, the shared library will go missing at runtime. The Python extension module linked against it needs an RPATH entry - and Meson will not automatically manage RPATH entries for you. Hence you'll need to add the needed RPATH yourself, for example by adding ``-Wl,rpath=/path/to/dir/sharedlib/is/in`` to ``LDFLAGS`` before starting the build. In case you run into this problem after a wheel is built and installed, adding that same path to the ``LD_LIBRARY_PATH`` environment variable is a quick way of checking if that is indeed the problem. On Windows, the solution is similar - the shared library can either be preloaded, or the directory that the library is located in added to the DLL search path with ``os.add_dll_directory``, or vendored into the wheel with ``delvewheel`` in order to make the built Python package usable locally. Publishing wheels which depend on external shared libraries ----------------------------------------------------------- On all platforms, wheels which depend on external shared libraries usually need post-processing to make them usable on machines other than the one on which they were built. This is because the RPATH entry for an external shared library contains a path specific to the build machine. This post-processing is done by tools like ``auditwheel`` (Linux), ``delvewheel`` (Windows), ``delocate`` (macOS) or ``repair-wheel`` (any platform, wraps the other tools). Running any of those tools on a wheel produced by ``meson-python`` will vendor the external shared library into the wheel and rewrite the RPATH entries (it may also do some other things, like symbol mangling). On Windows, the package author may also have to add the preloading like shown above with ``_append_to_sharedlib_load_path()`` to the main ``__init__.py`` of the package, ``delvewheel`` may or may not take care of this (please check its documentation if your shared library goes missing at runtime). Note that we don't cover using shared libraries contained in another wheel and depending on such a wheel at runtime in this guide. This is inherently complex and not recommended (you need to be in control of both packages, or upgrades may be impossible/breaking). Using libraries from a Meson subproject ======================================= It can often be useful to build a shared library in a `Meson subproject `__, for example as a fallback in case an external dependency isn't detected. There are two main strategies for folding a library built in a subproject into a wheel built with ``meson-python``: 1. Build the library as a static library instead of a shared library, and link it into a Python extension module that needs it. 2. Build the library as a shared library, and either change its install path to be within the Python package's tree, or rely on ``meson-python`` to fold it into the wheel when it'd otherwise be installed to ``libdir``. Static linking tends to be easier, and it is the recommended solution, unless the library of interest cannot be built as a static library or it would inflate the wheel size too much because it's needed by multiple Python extension modules. Static library from subproject ------------------------------ The major advantage of building a library target as static and folding it directly into an extension module is that the RPATH or the DLL search path do not need to be adjusted and no targets from the subproject need to be installed. To ensures that ``library()`` targets are built as static, and that no parts of the subprojects are installed, the following configuration can be added in ``pyproject.toml`` to ensure the relevant options are passed to Meson: .. code-block:: toml [tool.meson-python.args] setup = ['--default-library=static'] install = ['--skip-subprojects'] To then link against the static library in the subproject, say for a subproject named ``bar`` with the main library target contained in a ``bar_dep`` dependency, add this to your ``meson.build`` file: .. code-block:: meson bar_proj = subproject('bar') bar_dep = bar_proj.get_variable('bar_dep') py.extension_module( '_example', '_examplemod.c', dependencies: bar_dep, install: true, ) Shared library from subproject ------------------------------ Sometimes it may be necessary or preferable to use dynamic linking to a shared library provided in a subproject, for example to avoid inflating the wheel size having multiple copies of the same object code in different extension modules using the same library. In this case, the subproject needs to install the shared library in the usual location in ``libdir``. ``meson-python`` will automatically include it into the wheel in ``..mesonpy.libs`` just like an internal shared library. Most projects, however, install more than the shared library and the extra components, such as header files or documentation, should not be included in the Python wheel. Projects may have configuration options to disable building and installing additional components, in this case, these options can be passed to the ``subproject()`` call: .. code-block:: meson foo_subproj = subproject('foo', default_options: { 'docs': 'disabled', }) foo_dep = foo_subproj.get_variable('foo_dep') Install tags do not work per subproject, therefore to exclude other parts of the subproject from being included in the wheel, we need to resort to ``meson-python`` install location filters using the :option:`tool.meson-python.wheel.exclude` build option: .. code-block:: toml [tool.meson-python.wheel] exclude = ['{prefix}/include/*'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/index.rst0000664000000000000000000000707115257562503015666 0ustar00rootroot.. 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 = 'MIT' license-files = ['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/sdist how-to-guides/editable-installs how-to-guides/config-settings how-to-guides/meson-args how-to-guides/debug-builds how-to-guides/shared-libraries how-to-guides/limited-api 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 how-to-guides/contributing Discussions Source Code Issue Tracker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/projects-using-meson-python.rst0000664000000000000000000000216315257562503022166 0ustar00rootroot.. 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=1790895427.0 meson_python-0.22.1/docs/reference/config-settings.rst0000664000000000000000000000320115257562503021607 0ustar00rootroot.. 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``. 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 `. Accepts an optional argument taking the values ``true`` or ``false``. This config setting takes precedence over the project setting with the same name. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/reference/environment-variables.rst0000664000000000000000000001354115257562503023026 0ustar00rootroot.. 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:: IPHONEOS_DEPLOYMENT_TARGET This environment variable is used to specify the target iOS platform version to the Xcode development tools. If this environment variable is set, ``meson-python`` will use the specified iOS version for the Python wheel platform tag, instead than the iOS platform default of 13.0. This variable must be set to a major/minor version, for example ``13.0`` or ``15.4``. Note that ``IPHONEOS_DEPLOYMENT_TARGET`` is the only supported mechanism for specifying the target iOS version. Although the iOS toolchain supports the use of ``-mios-version-min`` compile and link flags to set the target iOS version, ``meson-python`` will not set the Python wheel platform tag correctly unless ``IPHONEOS_DEPLOYMENT_TARGET`` is set. .. 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 variable is used to specify 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. Note that ``MACOSX_DEPLOYMENT_TARGET`` is the only supported mechanism for specifying the target macOS version. Although the macOS toolchain supports the use of ``-mmacosx-version-min`` compile and link flags to set the target macOS version, ``meson-python`` will not set the Python wheel platform tag correctly unless ``MACOSX_DEPLOYMENT_TARGET`` is set. .. 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=1790895427.0 meson_python-0.22.1/docs/reference/limitations.rst0000664000000000000000000000204415257562503021044 0ustar00rootroot.. 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. .. _install_data(): https://mesonbuild.com/Reference-manual_functions.html#install_data .. _importlib-resources: https://importlib-resources.readthedocs.io/en/latest/index.html .. |install_data()| replace:: ``install_data()`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/reference/meson-compatibility.rst0000664000000000000000000000571215257562503022505 0ustar00rootroot.. 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.64.0 Meson is 0.64.0 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.0 Meson 1.2.0 or later is required to support the ``--skip-subprojects`` option that can be passed to ``meson install`` to not include files installed by some or all subprojects in the Python wheel. .. 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. .. option:: 1.6.0 Meson 1.6.0 or later is required to support ``license`` and ``license-files`` dynamic fields in ``pyproject.toml`` and to populate the package license and license files from the ones declared via the ``project()`` call in ``meson.build``. Meson 1.6.0 or later is also required to support the ``install_rpath`` argument to Meson functions that accept it, such as ``library()`` and ``extension_module()``. On older Meson versions, this argument has no effect. .. option:: 1.9.0 Meson 1.9.0 or later is required to support building for iOS. Meson 1.9.0 or later is also required to remove RPATH entries that are added by Meson to allow executing parts of the project from the build directory and that are normally removed during ``meson install``. On older Meson versions, these entries are not removed. 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=1790895427.0 meson_python-0.22.1/docs/reference/pyproject-settings.rst0000664000000000000000000001137315257562503022372 0ustar00rootroot.. 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.allow-windows-internal-shared-libs Enable support for relocating internal shared libraries that would be installed into the system shared library location to the ``..mesonpy.libs`` folder also on Windows. The relocation can be done transparently on UNIX platforms and on macOS, where the shared library load path can be adjusted via RPATH or equivalent mechanisms. Windows lacks a similar facility, thus the Python package is responsible to extend the DLL load path to include this directory or to preload the shared libraries. See :ref:`here ` for detailed documentation. This option ensures that the package authors are aware of this requirement. .. option:: tool.meson-python.editable-verbose A boolean indicating whether :ref:`verbose mode ` should be enabled when building an :ref:`editable install `. This setting can be overridden via the config option of the same name. .. 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 Python wheel filename ABI tag is set to ``abi3``, or ``abi3.abi3t`` when building with free-threaded CPython 3.15 or later. This setting is automatically reverted to false when the ``-Dpython.allow_limited_api=false`` option is passed to ``meson setup``. See :ref:`howto-limited-api` for more information on limited API builds. .. 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. .. option:: tool.meson-python.wheel.exclude List of glob patterns matching paths of files that must be excluded from the Python wheel. The accepted glob patterns are the ones implemented by the Python :mod:`fnmatch` with case sensitive matching. The paths to be matched are as they appear in the Meson introspection data, namely they are rooted in one of the Meson install locations: ``{bindir}``, ``{datadir}``, ``{includedir}``, ``{libdir_shared}``, ``{libdir_static}``, et cetera. Inspecting the `Meson introspection data`_ may be useful to craft the exclude patterns. It is accessible as the ``meson-info/intro-install_plan.json`` JSON document in the build directory. This configuration setting is measure of last resort to exclude installed files from a Python wheel. It is to be used when the project includes subprojects that do not allow fine control on the installed files. Better solutions include the use of Meson install tags and excluding subprojects to be installed via :option:`tool.meson-python.args.install`. .. option:: tool.meson-python.wheel.include List of glob patterns matching paths of files that must not be excluded from the Python wheel. All files recorded for installation in the Meson project are included in the Python wheel unless matching an exclude glob pattern specified in :option:`tool.meson-python.wheel.exclude`. An include glob pattern is useful exclusively to limit the effect of an exclude pattern that matches too many files. .. _python limited api: https://docs.python.org/3/c-api/stable.html#stable-application-binary-interface .. _extension_module(): `https://mesonbuild.com/Python-module.html#extension_module .. _meson introspection data: https://mesonbuild.com/IDE-integration.html#install-plan .. |extension_module()| replace:: ``extension_module()`` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/docs/tutorials/introduction.rst0000664000000000000000000002422115257562503021322 0ustar00rootroot.. 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 :ref:`extending-index` guide in the Python documentation. Also consider if you need to use the CPython C API directly, or are perhaps better off using a binding generator tool like Cython_, pybind11_ or nanobind_ which will take care of a lot of the low-level details for you. 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 = 'MIT' license-files = ['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, and an sdist is created from the most recent commit - uncommitted changes are ignored. 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. Note that by default, ``python -m build`` builds an sdist first, and then a wheel from the sdist. If you only want one artifact, add ``--sdist`` or ``--wheel`` to the invocation. .. 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. Build isolation ``````````````` Building with ``python -m build`` or with ``pip`` uses build isolation by default. I.e., the build frontend creates a new, temporary virtual environment with all build dependencies before calling ``meson-python`` to build a wheel. If you disable build isolation, you are responsible for ensuring that ``meson-python`` and all other build dependencies for the package are installed already in the Python environment. Note that if you use a virtual environment to build in, it must be activated (otherwise ``meson`` or another executable may not be found). 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 .. _Cython: https://cython.readthedocs.io .. _pybind11: https://pybind11.readthedocs.io .. _nanobind: https://nanobind.readthedocs.io ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/meson.build0000664000000000000000000000055315257562503015235 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('meson-python') py = import('python').find_installation() py.install_sources( 'mesonpy/__init__.py', 'mesonpy/_editable.py', 'mesonpy/_rpath.py', 'mesonpy/_tags.py', 'mesonpy/_util.py', 'mesonpy/_wheelfile.py', subdir: 'mesonpy', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/mesonpy/__init__.py0000664000000000000000000016367215257562503016712 0ustar00rootroot# 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 copy import dataclasses import difflib import fnmatch import functools import importlib.machinery import importlib.resources import io import itertools import json import os import pathlib import platform import posixpath import re import shutil import subprocess import sys import sysconfig import tarfile import tempfile import textwrap import typing import warnings from functools import cached_property if sys.version_info < (3, 11): import tomli as tomllib else: import tomllib import packaging.utils import packaging.version import pyproject_metadata import mesonpy._rpath import mesonpy._tags import mesonpy._util import mesonpy._wheelfile try: from packaging.licenses import InvalidLicenseExpression, canonicalize_license_expression except ImportError: # PEP-639 support requires packaging >= 24.2. def canonicalize_license_expression(s: str) -> str: # type: ignore[misc] warnings.warn( 'canonicalization and validation of license expression in "project.license" ' 'as defined by PEP-639 requires packaging version 24.2 or later.', stacklevel=2) return s class InvalidLicenseExpression(Exception): # type: ignore[no-redef] pass if typing.TYPE_CHECKING: # pragma: no cover from collections.abc import Collection, Iterator, Mapping from typing import Any, Callable, DefaultDict, Dict, List, Literal, Optional, Sequence, TextIO, Tuple, Type, TypeVar, Union from typing_extensions import ParamSpec, Self P = ParamSpec('P') T = TypeVar('T') MesonArgsKeys = Literal['dist', 'setup', 'compile', 'install'] MesonArgs = Mapping[MesonArgsKeys, List[str]] Path = Union[str, os.PathLike[str]] __version__ = '0.22.1' _PYPROJECT_METADATA_VERSION = tuple(map(int, pyproject_metadata.__version__.split('.')[:2])) _SUPPORTED_DYNAMIC_FIELDS = {'version', } if _PYPROJECT_METADATA_VERSION < (0, 9) else {'version', 'license', 'license-files'} _NINJA_REQUIRED_VERSION = '1.8.2' # Keep in sync with the version requirement in pyproject.toml _MESON_REQUIRED_VERSION = '0.64.0' if sys.version_info < (3, 12) else '1.2.3' _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 _compile_patterns(patterns: List[str]) -> Callable[[str], bool]: if not patterns: return lambda x: False func = re.compile('|'.join(fnmatch.translate(os.path.normpath(p)) for p in patterns)).match return typing.cast('Callable[[str], bool]', func) def _translate_rpath(path: str, dst: pathlib.Path) -> str: root, sep, stem = path.partition('/') if root == '$ORIGIN': translated = f'@loader_path{sep}{stem}' warnings.warn( f'translated "install_rpath" argument for {str(dst)!r} ' f'from {path!r} to {translated!r}', stacklevel=2) path = translated return path class _Entry(typing.NamedTuple): dst: pathlib.Path src: str install_rpath: List[str] = [] build_rpath: List[str] = [] def _map_to_wheel(sources: Dict[str, Dict[str, Any]], exclude: List[str], include: List[str], build_dir: str) -> DefaultDict[str, List[_Entry]]: """Map files to the wheel, organized by wheel installation directory.""" wheel_files: DefaultDict[str, List[_Entry]] = collections.defaultdict(list) packages: Dict[str, str] = {} excluded = _compile_patterns(exclude) included = _compile_patterns(include) build_dir = os.path.normpath(build_dir) assert os.path.isabs(build_dir) for key, group in sources.items(): for src, target in group.items(): target_destination = os.path.normpath(target['destination']) if excluded(target_destination) and not included(target_destination): continue 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:])) module = next(entry.dst for entry in wheel_files[other] if entry.dst.parts[0] == destination.parts[1]) that = os.fspath(other / module) 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): 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 deterministically 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(_Entry(filedst, filesrc)) else: rpath = target.get('install_rpath') install_rpath = rpath.split(':') if rpath else [] build_rpath = target.get('build_rpaths') or [] # Translate ``$ORIGIN`` to ``@loader_path`` in ``install_rpath`` # arguments on macOS. This is better done here to be able to # emit a meaningful warning. if sys.platform == 'darwin': install_rpath = [_translate_rpath(path, dst) for path in install_rpath] # ``build_rpath`` lists the RPATH entries to remove from the # binary. Meson automatically adds RPATH entries for shared # libraries built as part of the project, using relative paths # anchored at ``$ORIGIN`` or ``@loader_path``, and for shared # libraries from dependencies installed in non-standard # locations, using absolute paths. Installed binaries need # the absolute paths to find their external dependencies, so # we drop them from the list. The relative paths are only # meaningful inside the build tree, so we leave them in the # list to be removed. Additional entries can be added with # the ``build_rpath`` argument passed to Meson functions. The # most common use case for these is to point at directories # inside the build directory. These may be absolute paths, # but they are irrelevant for installed binaries, so we leave # them too in the list to be removed. build_rpath = [path for path in build_rpath if not path.startswith('/') or os.path.commonpath((os.path.normpath(path), build_dir)) == build_dir] wheel_files[path].append(_Entry(dst, src, install_rpath, build_rpath)) 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.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[union-attr] 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): # 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') super().__init__(name, *args, **kwargs) @classmethod def from_pyproject(cls, # type: ignore[override] data: Mapping[str, Any], project_dir: Path = os.path.curdir, metadata_version: Optional[str] = None) -> Self: metadata = super().from_pyproject(data, project_dir, metadata_version) # Check for unsupported dynamic fields. unsupported_dynamic = set(metadata.dynamic) - _SUPPORTED_DYNAMIC_FIELDS if unsupported_dynamic: fields = ', '.join(f'"{x}"' for x in unsupported_dynamic) raise pyproject_metadata.ConfigurationError(f'Unsupported dynamic fields: {fields}') # Validate license field to be a valid SDPX license expression. if isinstance(metadata.license, str): metadata.license = canonicalize_license_expression(metadata.license) return metadata @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 @dataclasses.dataclass class _WheelBuilder(): """Helper class to build wheels from projects.""" _metadata: Metadata _manifest: Dict[str, List[_Entry]] _limited_api: bool _allow_windows_shared_libs: bool @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 entry in self._manifest['scripts']: if _is_native(entry.src): 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 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]: # PyPy supports the limited API but does not provide a stable # ABI, therefore extension modules using the limited API do # not use the stable ABI filename suffix and wheels should not # be tagged with the abi3 tag. if self._limited_api and '__pypy__' not in sys.builtin_module_names: # On free-threaded Python 3.15 or later, we expect to be # building 'abi3t' wheels for the time being. In the future # we will want an option to target 'abi3t' from GIL-enabled # Python too. abi3t = bool(sysconfig.get_config_var('Py_GIL_DISABLED')) and sys.version_info >= (3, 15) expected_abi = 'abi3t' if abi3t else 'abi3' # 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 entry in self._manifest['platlib']: match = _EXTENSION_SUFFIX_REGEX.match(entry.dst.name) if match: abi = match.group('abi') if abi is not None and abi != expected_abi: raise BuildError( f'The package declares compatibility with Python limited API but extension ' f'module {os.fspath(entry.dst)!r} is tagged for a specific Python version.') return 'abi3.abi3t' if abi3t else 'abi3' return None def _install_path(self, wheel_file: mesonpy._wheelfile.WheelFile, origin: Path, destination: pathlib.Path, install_rpath: List[str], build_rpath: List[str]) -> None: """Add a file to the wheel.""" if self._has_internal_libs and _is_native(origin): libspath = os.path.relpath(self._libs_dir, destination.parent) mesonpy._rpath.fix_rpath(origin, install_rpath, build_rpath, libspath) elif install_rpath or build_rpath: mesonpy._rpath.fix_rpath(origin, install_rpath, build_rpath, None) 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 pre-PEP-639 license files. if isinstance(self._metadata.license, pyproject_metadata.License): license_file = self._metadata.license.file if license_file: whl.write(license_file, f'{self._distinfo_dir}/{os.path.basename(license_file)}') # Add PEP-639 license-files. Use ``getattr()`` for compatibility with pyproject-metadata < 0.9.0. license_files = getattr(self._metadata, 'license_files', None) if license_files: for f in license_files: whl.write(f, f'{self._distinfo_dir}/licenses/{pathlib.Path(f).as_posix()}') def build(self, directory: Path) -> pathlib.Path: if sys.platform == 'win32' and self._has_internal_libs and not self._allow_windows_shared_libs: raise NotImplementedError( 'Loading shared libraries bundled in the Python wheel on Windows requires ' 'setting the DLL load path or preloading. See the documentation for ' 'the "tool.meson-python.allow-windows-internal-shared-libs" option.') 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, install_rpath, build_rpath 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, install_rpath, build_rpath) return wheel_file class _EditableWheelBuilder(_WheelBuilder): @property def _top_level_modules(self) -> Collection[str]: modules = set() for type_ in self._manifest: for entry in self._manifest[type_]: name, dot, ext = entry.dst.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) # install loader module loader_module_name = f'_{self._metadata.distribution_name}_editable_loader' whl.writestr( f'{loader_module_name}.py', importlib.resources.files('mesonpy').joinpath('_editable.py').read_bytes() + textwrap.dedent(f''' def init(): finder = MesonpyMetaFinder( {self._metadata.name!r}, {self._top_level_modules!r}, {os.fspath(build_dir)!r}, {build_command!r}, {verbose!r}, ) sys.meta_path.insert(0, finder) sys.path_hooks.insert(0, finder._path_hook) ''').encode('utf-8')) if sys.version_info >= (3, 15): # install .start file whl.writestr( f'{self._metadata.canonical_name}-editable.start', f'{loader_module_name}:init'.encode('utf-8')) else: # install .pth file whl.writestr( f'{self._metadata.canonical_name}-editable.pth', f'import {loader_module_name}; {loader_module_name}.init()'.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): return os.path.abspath(value) return value scheme = _table({ 'meson': _string_or_path, 'limited-api': _bool, 'allow-windows-internal-shared-libs': _bool, 'args': _table(dict.fromkeys(_MESON_ARGS_KEYS, _strings)), 'wheel': _table({ 'exclude': _strings, 'include': _strings, }), 'editable-verbose': _bool, }) 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 _empty_or_bool(value: Any, name: str) -> bool: if isinstance(value, bool): return value if isinstance(value, str): if value == 'false': return False if value == 'true': return True # For backward compatibility, treat a missing value as True. if value == '': return True raise ConfigError(f'Invalid value for "{name}": {value!r}') def _string_or_strings(value: Any, name: str) -> List[str]: return [value] if isinstance(value, str) else list(value) options = { 'builddir': _string, 'build-dir': _string, 'editable-verbose': _empty_or_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: Optional[bool] = None) -> None: self._source_dir = pathlib.Path(source_dir).absolute() self._build_dir = pathlib.Path(build_dir).absolute() 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(encoding='utf-8')) # 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) # editable-verbose setting from build options takes precedence over # setting in pyproject.toml if editable_verbose is None: editable_verbose = bool(pyproject_config.get('editable-verbose')) self._editable_verbose = editable_verbose # 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) # if the build dir is empty, add .gitignore and .hgignore files if not any(self._build_dir.iterdir()): _add_ignore_files(self._build_dir) # 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}] strip = ['strip', '-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, encoding='utf-8') self._meson_args['setup'].extend(('--cross-file', os.fspath(self._meson_cross_file))) # Simplify cross-compilation for Android with cibuildwheel: detect the # cross-compilation environment set up by cibuildwheel and synthesize an # appropriate cross file. elif sysconfig.get_platform().startswith('android-') and 'CIBUILDWHEEL' in os.environ: cpu = platform.machine() cpu_family = 'x86' if cpu == 'i686' else 'arm' if cpu.startswith('arm') else cpu # cibuildwheel uses environment variables to point to the cross # compilation toolchain binaries thus the [binaries] section of # the cross file is not needed. cross_file_data = textwrap.dedent(f''' [host_machine] system = 'android' subsystem = 'android' kernel = 'linux' cpu_family = {cpu_family!r} cpu = {cpu!r} endian = {sys.byteorder!r} [properties] # To obtain the correct wheel tags when cross-compiling # cibuildwheel monkey-patches platform.system() and # platform.machine() to simulate running on Android. # This makes Meson believe that host and build machines # match, and thus that host binaries can be run on the # build machine when this is not actually the case. # Override the auto-detection. needs_exe_wrapper = true ''') self._meson_cross_file.write_text(cross_file_data, encoding='utf-8') self._meson_args['setup'].extend(('--cross-file', os.fspath(self._meson_cross_file))) # Support iOS targets. iOS does not have native build tools and always # requires cross compilation: synthesize the appropriate cross file. elif sysconfig.get_platform().startswith('ios-'): ios_ver = platform.ios_ver() # type: ignore[attr-defined] arch = platform.machine() family = 'aarch64' if arch == 'arm64' else arch subsystem = 'ios-simulator' if ios_ver.is_simulator else 'ios' cross_file_data = textwrap.dedent(f''' [binaries] ar = '{arch}-apple-{subsystem}-ar' c = '{arch}-apple-{subsystem}-clang' cpp = '{arch}-apple-{subsystem}-clang++' objc = '{arch}-apple-{subsystem}-clang' objcpp = '{arch}-apple-{subsystem}-clang++' strip = '{arch}-apple-{subsystem}-strip' [host_machine] system = 'ios' subsystem = {subsystem!r} cpu = {arch!r} cpu_family = {family!r} endian = 'little' ''') self._meson_cross_file.write_text(cross_file_data, encoding='utf-8') 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, encoding='utf-8') # 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 is None: raise pyproject_metadata.ConfigurationError( 'Field "version" declared as dynamic but version is not defined in meson.build') self._metadata.version = packaging.version.Version(version) if 'license' in self._metadata.dynamic: license = self._meson_license if license is None: raise pyproject_metadata.ConfigurationError( 'Field "license" declared as dynamic but license is not specified in meson.build') # mypy is not happy when analyzing typing based on # pyproject-metadata < 0.9 where license needs to be of # License type. However, this code is not executed if # pyproject-metadata is older than 0.9 because then dynamic # license is not allowed. self._metadata.license = license # type: ignore[assignment, unused-ignore] if 'license-files' in self._metadata.dynamic: self._metadata.license_files = self._meson_license_files else: # if project section is missing, use minimal metadata from meson.build name, version = self._meson_name, self._meson_version if not version: raise pyproject_metadata.ConfigurationError( 'Section "project" missing in pyproject.toml and version is not defined in meson.build') kwargs = { 'license': self._meson_license, 'license_files': self._meson_license_files } if _PYPROJECT_METADATA_VERSION >= (0, 9) else {} self._metadata = Metadata(name=name, version=packaging.version.Version(version), **kwargs) # 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'The 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') allow_limited_api = next((opt['value'] for opt in options if opt['name'] == 'python.allow_limited_api'), None) if not allow_limited_api: self._limited_api = False if self._limited_api and bool(sysconfig.get_config_var('Py_GIL_DISABLED')) and sys.version_info < (3, 15): raise BuildError( 'The package targets Python\'s Limited API, which is not supported by free-threaded CPython before version ' '3.15. The "python.allow_limited_api" Meson build option may be used to override the package default.') # Shared library support on Windows requires collaboration # from the package, make sure the developers acknowledge this. self._allow_windows_shared_libs = pyproject_config.get('allow-windows-internal-shared-libs', False) # Files to be excluded from the wheel self._excluded_files = pyproject_config.get('wheel', {}).get('exclude', []) self._included_files = pyproject_config.get('wheel', {}).get('include', []) 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.cache def build(self) -> None: """Build the Meson project.""" self._run(self._build_command) @functools.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(encoding='utf-8')) @property def _manifest(self) -> DefaultDict[str, List[_Entry]]: """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, others = parser.parse_known_args(self._meson_args['install']) if others: otherstr = ' '.join(others) warnings.warn(f'unhandled arguments specified for meson install: {otherstr}', stacklevel=1) 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, self._excluded_files, self._included_files, str(self._build_dir)) @property def _meson_name(self) -> str: """The project name specified with ``project()`` in meson.build.""" value = self._info('intro-projectinfo')['descriptive_name'] assert isinstance(value, str) return value @property def _meson_version(self) -> Optional[str]: """The version specified with the ``version`` argument to ``project()`` in meson.build.""" value = self._info('intro-projectinfo')['version'] assert isinstance(value, str) if value == 'undefined': return None return value @property def _meson_license(self) -> Optional[str]: """The license specified with the ``license`` argument to ``project()`` in meson.build.""" value = self._info('intro-projectinfo').get('license', None) if value is None: return None assert isinstance(value, list) if len(value) > 1: raise pyproject_metadata.ConfigurationError( 'Using a list of strings for the license declared in meson.build is ambiguous: use a SPDX license expression') value = value[0] assert isinstance(value, str) if value == 'unknown': return None return str(canonicalize_license_expression(value)) # str() is to make mypy happy @property def _meson_license_files(self) -> Optional[List[pathlib.Path]]: """The license files specified with the ``license_files`` argument to ``project()`` in meson.build.""" value = self._info('intro-projectinfo').get('license_files', None) if not value: return None assert isinstance(value, list) return [pathlib.Path(x) for x in value] 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']]) dist_name = f'{self._metadata.distribution_name}-{self._metadata.version}' meson_version = self._meson_version or 'undefined' meson_dist_name = f'{self._meson_name}-{meson_version}' meson_dist_path = pathlib.Path(self._build_dir, 'meson-dist', f'{meson_dist_name}.tar.gz') sdist_path = pathlib.Path(directory, f'{dist_name}.tar.gz') pyproject_toml_mtime: Union[int, float] = 0 with tarfile.open(meson_dist_path, 'r:gz') as meson_dist, mesonpy._util.create_targz(sdist_path) as sdist: for member in meson_dist.getmembers(): # Record the original member name. The symbolic link # resolution loop will make ``member`` point to the link # target, but it needs to be archived under the original name. # Symbolic link target resolution must be relative to # ``member.name``, which therefore cannot be updated in the # symbolic link resolution loop. name = member.name # Recursively resolve symbolic links. The source distribution # archive format specification allows for symbolic links as # long as the target path does not include a '..' component. # This makes symbolic links support unusable in most cases, # therefore include the symbolic link targets as regular files # in all cases. visited = set() while member.issym(): # Detect symbolic link chains resulting in a cycle. if member.name in visited: warnings.warn( f'symbolic link resulting in a cycle ignored: {name}', stacklevel=1) break visited.add(member.name) target = posixpath.normpath(posixpath.join(posixpath.dirname(member.name), member.linkname)) try: member = meson_dist.getmember(target) except KeyError: warnings.warn( 'symbolic link with absolute path target, pointing outside the ' f'archive, or dangling ignored: {name}', stacklevel=1) break if member.isdir(): warnings.warn( f'symbolic link pointing to a directory ignored: {name}', stacklevel=1) break if member.isfile(): file = meson_dist.extractfile(member.name) # Copy ``member`` before starting to modify it member = copy.copy(member) # Reset pax extended header. The tar archive member may be # using pax headers to store some file metadata. The pax # headers are not reset when the metadata is modified and # they take precedence when the member is deserialized. # This is relevant because when rewriting the member name, # the length of the path may shrink from being more than # 100 characters (requiring the path to be stored in the # pax headers) to being less than 100 characters. When this # happens, the tar archive member is serialized with the # shorter name in the regular header and the longer one in # the extended pax header. The archives handled here are # not expected to use extended pax headers other than for # the ones required to encode file metadata. The easiest # solution is to reset the pax extended headers. member.pax_headers = {} # Rewrite the path to match the sdist distribution name. stem = name.split('/', 1)[1] member.name = '/'.join((dist_name, stem)) if stem == 'pyproject.toml': pyproject_toml_mtime = member.mtime # Reset owner and group to root:root. This mimics what # 'git archive' does and makes the sdist reproducible upon # being built by different users. member.uname = member.gname = 'root' member.uid = member.gid = 0 sdist.addfile(member, file) elif not member.isdir() and not member.issym(): warnings.warn( f'special file in the source archive ignored: {member.name}', stacklevel=1) # Add 'PKG-INFO'. member = tarfile.TarInfo(f'{dist_name}/PKG-INFO') member.uid = member.gid = 0 member.uname = member.gname = 'root' # Set the 'PKG-INFO' modification time to the modification time of # 'pyproject.toml' in the archive generated by 'meson dist'. In # turn this is the last commit time, unless touched by a dist # script. This makes the sdist reproducible upon being built at # different times, when dist scripts are not used, which should be # the majority of cases. # # Note that support for dynamic version in project metadata allows # the version to depend on the build time. Therefore, setting the # 'PKG-INFO' modification time to the 'pyproject.toml' # modification time can be seen as not strictly correct. However, # the sdist standard does not dictate which modification time to # use for 'PKG-INFO'. This choice allows to make the sdist # byte-for-byte reproducible in the most common case. member.mtime = pyproject_toml_mtime metadata = bytes(self._metadata.as_rfc822()) member.size = len(metadata) sdist.addfile(member, io.BytesIO(metadata)) return sdist_path 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, self._allow_windows_shared_libs) 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, self._allow_windows_shared_libs) 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 = 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'): if not os.path.exists(meson): raise ConfigError(f'Could not find the specified meson: "{meson}"') 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 correctly. try: r = subprocess.run(cmd + ['--version'], text=True, capture_output=True) except FileNotFoundError as err: raise ConfigError(f'meson executable "{meson}" not found') from err if r.returncode != 0: raise ConfigError(f'Could not execute meson: {r.stderr.strip()}') meson_version = r.stdout.strip() if _parse_version_string(meson_version) < _parse_version_string(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, InvalidLicenseExpression, 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: config_settings['build-dir'] = 'build/' + mesonpy._tags.get_abi_tag() out = pathlib.Path(wheel_directory) with _project(config_settings) as project: return project.editable(out).name ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/mesonpy/_editable.py0000664000000000000000000003673715257562503017064 0ustar00rootroot# 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 locale 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 else: from importlib.abc import Traversable, TraversableResources if sys.version_info >= (3, 11): getencoding = locale.getencoding else: def getencoding() -> str: return locale.getpreferredencoding(False) 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) 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: # type: ignore[override] 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: # type: ignore[override] 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: # type: ignore[override] 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 deterministically 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(): src = os.path.normpath(src) 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, check=False, 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: try: # 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, '')): log_path = None # 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, check=True) else: # Redirect build log to file. log_path = os.path.join(self._build_path, 'meson-logs', 'meson-python-build-log.txt') # It does not matter if the log file is opened in text or # binary mode: `subprocess.run()` directly connects the # underlying file descriptor to the child process stdout. with open(log_path, 'w') as log: subprocess.run(self._build_cmd, cwd=self._build_path, env=env, check=True, stderr=subprocess.STDOUT, stdout=log) except subprocess.CalledProcessError as err: msg = f'rebuilding the "{self._name}" editable package failed' if log_path: # Compiler and other tools are expected to write log # messages using the environment default text encoding. # Since Python 3.15, UTF-8 mode is the default, thus # explicitly set the encoding. with open(log_path, 'r', encoding=getencoding(), errors='backslashreplace') as log: # Skip to the error. for line in log: if line.startswith('FAILED: '): break else: # When no `FAILED: ` line is found, rewind to the # beginning of the log. log.seek(0) if line.strip().endswith(' build.ninja'): # When the error occurred when rebuilding `ninja.build`, # the meson output appears before the `FAILED: ` line. # Rewind the build log to the beginning to report the # error. log.seek(0) error = log.read() if sys.version_info >= (3, 11): exc = ImportError(msg) exc.add_note(error) raise exc from err msg = f'{msg}:\n{error}' raise ImportError(msg) from err 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 = 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/mesonpy/_rpath.py0000664000000000000000000001334315257562503016415 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import os import re import subprocess import sys import typing if typing.TYPE_CHECKING: Path = str | os.PathLike[str] T = typing.TypeVar('T') def unique(values: list[T]) -> list[T]: return list(dict.fromkeys(values)) class RPATH: origin = '$ORIGIN' @staticmethod def get_rpath(filepath: Path) -> list[str]: raise NotImplementedError @staticmethod def set_rpath(filepath: Path, old: list[str], rpath: list[str]) -> None: raise NotImplementedError @classmethod def fix_rpath(cls, filepath: Path, install_rpath: list[str], build_rpath: list[str], libs_path: str | None) -> None: old_rpath = cls.get_rpath(filepath) # Prepend install_rpath entries. new_rpath = install_rpath # Merge with existing entries, excluding build_rpath entries. Meson # adds a padding entry to RPATH composed of enough ``X`` characters # to reserve enough space in the ELF header to hold the the final # installation RPATH. Remove this entry and empty entries too. new_rpath += [path for path in old_rpath if path.strip('X') and path not in build_rpath] # When an executable, library, or Python extension module is # dynamically linked to a library built as part of the project, Meson # adds a build RPATH pointing to the build directory, in the form of a # relative RPATH entry. We can use the presence of any RPATH entries # relative to ``$ORIGIN`` as an indicator that the installed object # depends on shared libraries internal to the project. In this case we # need to add an RPATH entry pointing to the meson-python shared # library install location. This heuristic is not perfect: RPATH # entries relative to ``$ORIGIN`` can exist for other reasons. # However, this only results in harmless additional RPATH entries. if libs_path and any(path.startswith(cls.origin) for path in old_rpath): new_rpath.append(os.path.join(cls.origin, libs_path)) new_rpath = unique(new_rpath) if new_rpath != old_rpath: cls.set_rpath(filepath, old_rpath, new_rpath) class _Windows(RPATH): @classmethod def fix_rpath(cls, filepath: Path, install_rpath: list[str], build_rpath: list[str], libs_path: str | None) -> None: pass class _MacOS(RPATH): origin = '@loader_path' @staticmethod def get_rpath(filepath: Path) -> list[str]: rpath = [] r = subprocess.run(['otool', '-l', os.fspath(filepath)], capture_output=True, text=True) lines = iter(r.stdout.splitlines()) for line in lines: if line.strip().startswith('cmd LC_RPATH'): for line in lines: if m := re.match(r'^\s*path (.+) \(offset \d+\)$', line): rpath.append(m.group(1)) break return rpath @staticmethod def set_rpath(filepath: Path, old: list[str], rpath: list[str]) -> None: # ``install_name_tool`` allows to delete, add, or rewrite specific # LC_RPATH entries, however, this operations cannot be combined in # arbitrary order in a single call. The only robust way to get # entries in a specific order with at max two tool invocations is to # delete the entries that are out of place and re-add them in the # right order. keep = 0 while keep < len(old) and keep < len(rpath) and old[keep] == rpath[keep]: keep += 1 delete = old[keep:] add = rpath[keep:] if delete: # ``install_name_tool`` does not accept repeated ``-delete_rpath`` # arguments. There should not be duplicated in the existing RPATH, # but the assert should make this occurrence easier to debug. assert unique(delete) == delete args = [a for p in delete for a in ('-delete_rpath', p)] subprocess.run(['install_name_tool', *args, os.fspath(filepath)], check=True) if add: args = [a for p in add for a in ('-add_rpath', p)] subprocess.run(['install_name_tool', *args, os.fspath(filepath)], check=True) class _SunOS5(RPATH): @staticmethod def get_rpath(filepath: Path) -> list[str]: rpath = [] r = subprocess.run(['/usr/bin/elfedit', '-r', '-e', 'dyn:rpath', os.fspath(filepath)], capture_output=True, check=True, text=True) for line in [x.split() for x in r.stdout.split('\n')]: if len(line) >= 4 and line[1] in ['RPATH', 'RUNPATH']: for path in line[3].split(':'): if path not in rpath: rpath.append(path) return rpath @staticmethod def set_rpath(filepath: Path, old: list[str], rpath: list[str]) -> None: subprocess.run(['/usr/bin/elfedit', '-e', 'dyn:rpath ' + ':'.join(rpath), os.fspath(filepath)], check=True) class _ELF(RPATH): @staticmethod def get_rpath(filepath: Path) -> list[str]: r = subprocess.run(['patchelf', '--print-rpath', os.fspath(filepath)], capture_output=True, text=True) return [x for x in r.stdout.strip().split(':') if x] @staticmethod def set_rpath(filepath: Path, old: list[str], rpath: list[str]) -> None: subprocess.run(['patchelf','--set-rpath', ':'.join(rpath), os.fspath(filepath)], check=True) if sys.platform == 'win32' or sys.platform == 'cygwin': _cls = _Windows elif sys.platform == 'darwin': _cls = _MacOS elif sys.platform == 'sunos5': _cls = _SunOS5 else: _cls = _ELF get_rpath = _cls.get_rpath set_rpath = _cls.set_rpath fix_rpath = _cls.fix_rpath ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/mesonpy/_tags.py0000664000000000000000000001633315257562503016237 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT from __future__ import annotations import os import platform import struct import sys import sysconfig # https://peps.python.org/pep-0425/#python-tag INTERPRETERS = { 'python': 'py', 'cpython': 'cp', 'pypy': 'pp', 'ironpython': 'ip', 'jython': 'jy', } _32_BIT_INTERPRETER = struct.calcsize('P') == 4 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: str | int | None = None) -> str | int | None: value: str | int | None = sysconfig.get_config_var(name) if value is None: return default return value def _get_cpython_abi() -> str: # Fallback for Python distributions not implementing PEP 3149. if sys.implementation.name != 'cpython': raise NotImplementedError version = sys.version_info debug = threading = '' if _get_config_var('Py_DEBUG', hasattr(sys, 'gettotalrefcount')): debug = 'd' if version >= (3, 13) and _get_config_var('Py_GIL_DISABLED'): threading = 't' return f'cp{version[0]}{version[1]}{threading}{debug}' 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. parts = str(sysconfig.get_config_var('EXT_SUFFIX')).split('.') # Some Python distributions (notably pkgsrc, the default NetBSD # package manager) patch the Python configure script to remove # $SOABI from $EXT_SUFFIX. if len(parts) < 3: 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. abi = parts[1] 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: parts = os.environ.get('MACOSX_DEPLOYMENT_TARGET', '').split('.')[:2] version = tuple(map(int, parts + ['0'] * (2 - len(parts)))) except ValueError: version = tuple(map(int, ver.split('.')))[:2] # Python built with older macOS SDK on macOS 11, reports an # nonexistent 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 releases 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_ios_platform_tag() -> str: # Override the iOS version if one is provided via the # IPHONEOS_DEPLOYMENT_TARGET environment variable. try: parts = os.environ.get('IPHONEOS_DEPLOYMENT_TARGET', '').split('.')[:2] version = tuple(map(int, parts + ['0'] * (2 - len(parts)))) except ValueError: version = tuple(map(int, platform.ios_ver().release.split('.')))[:2] # type: ignore[attr-defined] # Although _multiarch is an internal implementation detail, it's a core part # of how CPython is implemented on iOS; this attribute is also relied upon # by `packaging` as part of tag determination. multiarch = sys.implementation._multiarch.replace('-', '_') return f'ios_{version[0]}_{version[1]}_{multiarch}' def get_platform_tag() -> str: platform = sysconfig.get_platform() if platform.startswith('macosx'): return _get_macosx_platform_tag() if platform.startswith('ios'): return _get_ios_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: str | None = None, abi: str | None = None, platform: str | None = 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=1790895427.0 meson_python-0.22.1/mesonpy/_util.py0000664000000000000000000000356415257562503016260 0ustar00rootroot# 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 typing import Iterator, Union Path = Union[str, os.PathLike[str]] @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='w', # Set the stream last modification time to 0. This mimics # what 'git archive' does and makes the archives byte-for-byte # reproducible. mtime=0, )) 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=1790895427.0 meson_python-0.22.1/mesonpy/_wheelfile.py0000664000000000000000000001030315257562503017234 0ustar00rootroot# 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 Path = Union[str, os.PathLike[str]] 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=1790895427.0 meson_python-0.22.1/pyproject.toml0000664000000000000000000000644015257562503016010 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' backend-path = ['.'] requires = [ 'meson >= 0.64.0; python_version < "3.12"', 'meson >= 1.2.3; python_version >= "3.12"', 'packaging >= 23.2; sys_platform != "ios"', 'packaging >= 24.2; sys_platform == "ios"', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', ] [project] name = 'meson-python' version = '0.22.1' description = 'The Python build backend for Meson projects' readme = 'README.rst' requires-python = '>= 3.10' license = 'MIT' license-files = ['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' }, ] classifiers = [ 'Development Status :: 5 - Production/Stable', 'Programming Language :: Python', 'Topic :: Software Development :: Build Tools', ] dependencies = [ 'meson >= 0.64.0; python_version < "3.12"', 'meson >= 1.2.3; python_version >= "3.12"', 'packaging >= 23.2; sys_platform != "ios"', 'packaging >= 24.2; sys_platform == "ios"', 'pyproject-metadata >= 0.9.0', 'tomli >= 1.0.0; python_version < "3.11"', ] [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' [dependency-groups] test = [ 'build', 'pytest >= 6.0', 'pytest-cov', 'pytest-mock', 'cython >= 3.0.3', # required for Python 3.12 support 'wheel', ] docs = [ 'furo >= 2024.08.06', 'pygments >= 2.20.0', # required for https://github.com/pygments/pygments/issues/2918 'sphinx ~= 8.1.0', 'sphinx-copybutton >= 0.5.0', 'sphinx-design >= 0.1.0', 'sphinxext-opengraph >= 0.7.0', ] # uv includes by default the dev dependency group in the environment dev = [ {include-group = 'test'}, ] [tool.mypy] show_error_codes = true ignore_missing_imports = true strict = true [tool.ruff] line-length = 127 [tool.ruff.format] quote-style = 'single' [tool.ruff.lint] extend-ignore = [ 'B019', ] select = [ 'B', # flake8-bugbear 'C4', # flake8-comprehensions 'E', # pycodestyle 'F', # pyflakes 'I', # isort 'Q', # flake8-quotes 'W', # pycodestyle 'RUF100', # ruff ] exclude = [ 'docs/conf.py', ] [tool.ruff.lint.flake8-quotes] avoid-escape = false inline-quotes = 'single' multiline-quotes = 'single' [tool.ruff.lint.isort] lines-between-types = 1 lines-after-imports = 2 known-first-party = [ 'mesonpy', ] [tool.ruff.lint.per-file-ignores] # this file is included literally in the documentation and the double # empty lines forced by the import sorting style look odd there 'tests/packages/install-data/__init__.py' = ['I001'] [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=1790895427.0 meson_python-0.22.1/tests/__init__.py0000664000000000000000000000013415257562503016341 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/conftest.py0000664000000000000000000002057015257562503016435 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import contextlib import importlib.metadata import os import os.path import pathlib import re import shutil import subprocess import sys import sysconfig import tempfile import warnings from venv import EnvBuilder import packaging.metadata import packaging.version import pytest import mesonpy from mesonpy._util import chdir _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') FREE_THREADED_BUILD = bool(sysconfig.get_config_var('Py_GIL_DISABLED')) def metadata(data): meta, other = packaging.metadata.parse_email(data) # PEP-639 support requires packaging >= 24.1. Add minimal # handling of PEP-639 fields here to allow testing with older # packaging releases. value = other.pop('license-expression', None) if value is not None: # The ``License-Expression`` header should appear only once. assert len(value) == 1 meta['license-expression'] = value[0] value = other.pop('license-file', None) if value is not None: meta['license-file'] = value assert not other return meta 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 temptation of using pathlib.Path here: it is not # supported 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) # Free-threaded Python 3.13 requires pip 24.1b1 or later. if sysconfig.get_config_var('Py_GIL_DISABLED'): if packaging.version.Version(importlib.metadata.version('pip')) < packaging.version.Version('24.1b1'): self.pip('install', '--upgrade', 'pip >= 24.1b1') 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): 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): 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() @pytest.fixture(autouse=True, scope='session') def cleanenv(): # Cannot use the 'monkeypatch' fixture because of scope mismatch. mpatch = pytest.MonkeyPatch() # $MACOSX_DEPLOYMENT_TARGET affects the computation of the platform tag on macOS. yield mpatch.delenv('MACOSX_DEPLOYMENT_TARGET', raising=False) mpatch.undo() @pytest.fixture(autouse=True, scope='session') def meson_fatal_warnings(): # Cannot use the 'monkeypatch' fixture because of scope mismatch. mpatch = pytest.MonkeyPatch() mesonpy_project_init = mesonpy.Project.__init__ def __init__(self, source_dir, build_dir, meson_args=None, editable_verbose=None): if pathlib.Path(source_dir).absolute().name not in { # The CMake subproject emits ``WARNING: CMake Toolchain: # Failed to determine CMake compilers state`` on some # systems. This is probably related to missing Rust or ObjC # toolchains. 'cmake-subproject', # These packages use linker arguments to add RPATH entries. # This functionality is deprecated in Meson but it is used # in the wild thus we should make sure it keeps working. 'link-against-local-lib', 'sharedlib-in-package', 'same-name-sharedlibs', }: if meson_args is None: meson_args = {} meson_args.setdefault('setup', []).append('--fatal-meson-warnings') mesonpy_project_init(self, source_dir, build_dir, meson_args, editable_verbose) mpatch.setattr(mesonpy.Project, '__init__', __init__) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/cmake-subproject/cmakesubproject.pyx0000664000000000000000000000041015257562503025164 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT cdef extern from "cmaketest.hpp": cdef cppclass Test: Test(int) except + int add(int) def sum(int a, int b): t = new Test(a) return t.add(b) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/cmake-subproject/meson.build0000664000000000000000000000127215257562503023412 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT project('cmake-subproject', ['c', 'cpp', 'cython'], version: '1') if host_machine.system() == 'linux' and meson.version().version_compare('< 1.9.99') error('support for CMake subprojects rerquires Meson >= 1.10 on Linux') endif if meson.version().version_compare('< 1.3.0') dep = import('cmake').subproject('cmaketest').dependency('cmaketest') else dep = dependency('cmaketest') endif py = import('python').find_installation() py.extension_module( 'cmakesubproject', 'cmakesubproject.pyx', dependencies: dep, override_options: ['cython_language=cpp'], install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/cmake-subproject/pyproject.toml0000664000000000000000000000024215257562503024160 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/cmake-subproject/subprojects/cmaketest/CMakeLists.txt0000664000000000000000000000055415257562503030335 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT cmake_minimum_required(VERSION 3.5) project(cmaketest) set(CMAKE_CXX_STANDARD 14) include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_library(cmaketest SHARED cmaketest.cpp) include(GenerateExportHeader) generate_export_header(cmaketest) install(TARGETS cmaketest) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/cmake-subproject/subprojects/cmaketest/cmaketest.cpp0000664000000000000000000000031715257562503030256 0ustar00rootroot// SPDX-FileCopyrightText: 2024 The meson-python developers // // SPDX-License-Identifier: MIT #include "cmaketest.hpp" Test::Test(int x) { this->x = x; } int Test::add(int y) const { return x + y; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/cmake-subproject/subprojects/cmaketest/cmaketest.hpp0000664000000000000000000000035615257562503030266 0ustar00rootroot// SPDX-FileCopyrightText: 2024 The meson-python developers // // SPDX-License-Identifier: MIT #pragma once #include "cmaketest_export.h" class CMAKETEST_EXPORT Test { private: int x; public: Test(int x); int add(int y) const; }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/cmake-subproject/subprojects/cmaketest.wrap0000664000000000000000000000023515257562503026464 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT [wrap-file] method = cmake [provide] cmaketest = cmaketest_dep ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/complex/__init__.py0000664000000000000000000000013415257562503023235 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/complex/more/__init__.py0000664000000000000000000000016715257562503024205 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def test(): return 44 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/complex/more/baz.pyx0000664000000000000000000000017115257562503023405 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def answer(): return 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/complex/more/meson.build0000664000000000000000000000027515257562503024236 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/complex/complex/namespace/bar.py0000664000000000000000000000017115257562503024177 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def bar(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/complex/namespace/foo.py0000664000000000000000000000017115257562503024216 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'foo' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/extension.c0000664000000000000000000000122715257562503021641 0ustar00rootroot// SPDX-FileCopyrightText: 2024 The meson-python developers // // SPDX-License-Identifier: MIT #include static PyObject* answer(PyObject* self) { return PyLong_FromLong(42); } static PyMethodDef methods[] = { {"answer", (PyCFunction) answer, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "extension", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_extension(void) { PyObject *m = PyModule_Create(&module); if (m == NULL) { return NULL; } #ifdef Py_GIL_DISABLED PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); #endif return m; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/foo.py0000664000000000000000000000017015257562503020612 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/meson.build0000664000000000000000000000233015257562503021617 0ustar00rootroot# 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( 'extension', 'extension.c', install: true, subdir: 'complex', ) 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=1790895427.0 meson_python-0.22.1/tests/packages/complex/move.py0000664000000000000000000000017115257562503020776 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT def test(): return True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/pyproject.toml0000664000000000000000000000024215257562503022371 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/complex/test.pyx0000664000000000000000000000017115257562503021177 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def answer(): return 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/configure-data/configure_data.py.in0000664000000000000000000000021315257562503024625 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def message(): return 'meson says: @MSG@' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/configure-data/meson.build0000664000000000000000000000055415257562503023046 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/configure-data/pyproject.toml0000664000000000000000000000024215257562503023612 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/custom-target-dir/codegen.py0000664000000000000000000000047615257562503023347 0ustar00rootroot#!/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=1790895427.0 meson_python-0.22.1/tests/packages/custom-target-dir/meson.build0000664000000000000000000000052115257562503023522 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/custom-target-dir/pyproject.toml0000664000000000000000000000024215257562503024274 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/detect-compiler/detect_compiler.c0000664000000000000000000000133415257562503024377 0ustar00rootroot// 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=1790895427.0 meson_python-0.22.1/tests/packages/detect-compiler/meson.build0000664000000000000000000000040415257562503023230 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/detect-compiler/pyproject.toml0000664000000000000000000000024215257562503024002 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/dist-script/meson.build0000664000000000000000000000024615257562503022421 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/dist-script/pyproject.toml0000664000000000000000000000024215257562503023167 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/dynamic-version/meson.build0000664000000000000000000000021215257562503023254 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('dynamic-version', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/dynamic-version/pyproject.toml0000664000000000000000000000034315257562503024033 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/encoding/meson.build0000664000000000000000000000032215257562503021735 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/encoding/pyproject.toml0000664000000000000000000000024215257562503022510 0ustar00rootroot# 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.22.1/tests/packages/encoding/ใƒ†ใ‚นใƒˆ.py 22 mtime=1790895427.0 meson_python-0.22.1/tests/packages/encoding/???.py0000664000000000000000000000013415257562503020522 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/executable/example.c0000664000000000000000000000022615257562503021730 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/executable/meson.build0000664000000000000000000000031415257562503022271 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/executable/pyproject.toml0000664000000000000000000000024215257562503023043 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/executable-bit/example-script.py0000775000000000000000000000016715257562503024223 0ustar00rootroot#!python # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT print('hello!') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/executable-bit/example.c0000664000000000000000000000022615257562503022504 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/executable-bit/executable_module.py0000775000000000000000000000025715257562503024754 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' if __name__ == '__main__': print('foo?', foo()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/executable-bit/meson.build0000664000000000000000000000062615257562503023053 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/executable-bit/pyproject.toml0000664000000000000000000000024215257562503023617 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/full-metadata/LICENSE0000664000000000000000000000001515257562503021531 0ustar00rootrootsome license ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/full-metadata/README.md0000664000000000000000000000024715257562503022012 0ustar00rootroot # full-metadata An example package with all of the PEP 621 metadata! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/full-metadata/meson.build0000664000000000000000000000021015257562503022663 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT project('full-metadata', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/full-metadata/pyproject.toml0000664000000000000000000000222515257562503023445 0ustar00rootroot# 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', 'keyword with spaces'] 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=1790895427.0 meson_python-0.22.1/tests/packages/generated-files/example-script.py0000775000000000000000000000016715257562503024364 0ustar00rootroot#!python # SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT print('hello!') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/generated-files/example.c0000664000000000000000000000022615257562503022645 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include int main() { printf("hello!"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/generated-files/executable_module.py0000775000000000000000000000025715257562503025115 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' if __name__ == '__main__': print('foo?', foo()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/generated-files/generate_version.py0000664000000000000000000000171015257562503024756 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/generated-files/meson.build0000664000000000000000000000162515257562503023214 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/generated-files/pyproject.toml0000664000000000000000000000024215257562503023760 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/imports-itself-during-build/meson.build0000664000000000000000000000053615257562503025522 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/imports-itself-during-build/plat.c0000664000000000000000000000076515257562503024470 0ustar00rootroot// 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=1790895427.0 meson_python-0.22.1/tests/packages/imports-itself-during-build/pure.py0000664000000000000000000000017115257562503024700 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/imports-itself-during-build/pyproject.toml0000664000000000000000000000024215257562503026266 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-data/__init__.py0000664000000000000000000000042715257562503022501 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT import importlib.resources data = importlib.resources.files(__package__).joinpath('data.txt').read_text() uuid = importlib.resources.files(__package__).joinpath('uuid.txt').read_text() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-data/data.txt0000664000000000000000000000000515257562503022032 0ustar00rootrootDATA ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-data/meson.build0000664000000000000000000000074615257562503022536 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT project('package', version: '1.0.0') py = import('python').find_installation() py.install_sources( '__init__.py', subdir: 'package', ) install_data( 'data.txt', install_dir: py.get_install_dir() / 'package', ) custom_target( output: 'uuid.txt', command: [py, '-m', 'uuid'], capture: true, install: true, install_dir: py.get_install_dir() / 'package', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-data/pyproject.toml0000664000000000000000000000024215257562503023277 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/meson.build0000664000000000000000000000111215257562503023101 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/nested/deep/deep.py0000664000000000000000000000013415257562503024430 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/nested/deep/excluded.py0000664000000000000000000000013415257562503025310 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/nested/nested.py0000664000000000000000000000013415257562503024060 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/pyproject.toml0000664000000000000000000000024215257562503023656 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/strip/excluded.py0000664000000000000000000000013415257562503024252 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/strip/module.py0000664000000000000000000000013415257562503023742 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/subdir/__init__.py0000664000000000000000000000013415257562503024343 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/subdir/excluded/__init__.py0000664000000000000000000000013415257562503026140 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/subdir/excluded.py0000664000000000000000000000013415257562503024401 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/install-subdir/subdir/test.py0000664000000000000000000000013415257562503023563 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/library/example.c0000664000000000000000000000026615257562503021257 0ustar00rootroot// 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=1790895427.0 meson_python-0.22.1/tests/packages/library/examplelib.c0000664000000000000000000000021115257562503021734 0ustar00rootroot// SPDX-FileCopyrightText: 2021 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b) { return a + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/library/examplelib.h0000664000000000000000000000016715257562503021753 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT int sum(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/library/meson.build0000664000000000000000000000053515257562503021621 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/library/pyproject.toml0000664000000000000000000000024215257562503022366 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/license-file/meson.build0000664000000000000000000000020715257562503022510 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('license-file', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/license-file/pyproject.toml0000664000000000000000000000040515257562503023262 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/license-file/something/LICENSE.custom0000664000000000000000000000000715257562503024657 0ustar00rootrootHello! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/license-pep639/LICENSES/BSD-3-Clause.txt0000664000000000000000000000003715257562503024406 0ustar00rootrootPlaceholder, just for testing. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/license-pep639/LICENSES/MIT.txt0000664000000000000000000000003715257562503023055 0ustar00rootrootPlaceholder, just for testing. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/license-pep639/meson.build0000664000000000000000000000021115257562503022612 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('license-pep639', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/license-pep639/pyproject.toml0000664000000000000000000000042615257562503023374 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'license-pep639' version = '1.0.0' license = 'MIT OR BSD-3-Clause' license-files = ['LICENSES/*'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/limited-api/meson.build0000664000000000000000000000063415257562503022353 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('limited-api', 'c', version: '1.0.0', meson_version: '>= 1.3') 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=1790895427.0 meson_python-0.22.1/tests/packages/limited-api/meson.options0000664000000000000000000000021415257562503022741 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT option('extra', type: 'boolean', value: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/limited-api/module.c0000664000000000000000000000111115257562503021631 0ustar00rootroot// 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, "module", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_module(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/limited-api/pyproject.toml0000664000000000000000000000031215257562503023116 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/limited-api-free-threaded/meson.build0000664000000000000000000000051115257562503025042 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('limited-api-free-thraded', 'c', version: '1.0.0', meson_version: '>= 1.3') py = import('python').find_installation(pure: false) py.extension_module( 'module', 'module.c', limited_api: '3.15', install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/limited-api-free-threaded/module.c0000664000000000000000000000133415257562503024335 0ustar00rootroot// 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}, }; PyABIInfo_VAR(abi_info); static PySlot module_slots[] = { PySlot_STATIC_DATA(Py_mod_name, "module"), PySlot_STATIC_DATA(Py_mod_methods, methods), PySlot_DATA(Py_mod_gil, Py_MOD_GIL_NOT_USED), PySlot_DATA(Py_mod_abi, &abi_info), PySlot_END, }; PyMODEXPORT_FUNC PyModExport_module(void) { return module_slots; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/limited-api-free-threaded/pyproject.toml0000664000000000000000000000031215257562503025613 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/link-against-external-lib/external.c0000664000000000000000000000102515257562503024741 0ustar00rootroot// SPDX-FileCopyrightText: 2026 The meson-python developers // // SPDX-License-Identifier: MIT #include #include static PyObject *version(PyObject *self, PyObject *args) { return PyUnicode_FromString(GEOSversion()); } static PyMethodDef methods[] = { {"version", version, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "external", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_external(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-against-external-lib/meson.build0000664000000000000000000000055415257562503025123 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT project('link-against-external-lib', 'c', version: '1.0.0') py = import('python').find_installation(pure: false) external = dependency('geos', method: 'pkg-config') py.extension_module( 'external', 'external.c', dependencies: external, install: true ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-against-external-lib/pyproject.toml0000664000000000000000000000024215257562503025667 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-against-local-lib/__init__.py0000664000000000000000000000070315257562503024336 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT import os import sys _path = os.path.join(os.path.dirname(__file__), '..', '.link_against_local_lib.mesonpy.libs') if os.name == 'nt': os.add_dll_directory(_path) elif sys.platform == 'cygwin': os.environ['PATH'] = os.pathsep.join((os.environ['PATH'], _path)) del _path from ._example import example_sum # noqa: E402 __all__ = ['example_sum'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-against-local-lib/examplemod.c0000664000000000000000000000126515257562503024530 0ustar00rootroot// 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=1790895427.0 meson_python-0.22.1/tests/packages/link-against-local-lib/lib/examplelib.c0000664000000000000000000000024215257562503025257 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "examplelib.h" int sum(int a, int b) { return a + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-against-local-lib/lib/examplelib.h0000664000000000000000000000052415257562503025267 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #pragma once #if defined(EXAMPLE_DLL_EXPORTS) #define EXAMPLE_DLL __declspec(dllexport) #elif defined(BAR_DLL_IMPORTS) #define EXAMPLE_DLL __declspec(dllimport) #else #define EXAMPLE_DLL #endif EXAMPLE_DLL int sum(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-against-local-lib/lib/meson.build0000664000000000000000000000032115257562503025131 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT example_lib = shared_library( 'example', 'examplelib.c', c_args: lib_compile_args, install: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-against-local-lib/meson.build0000664000000000000000000000125515257562503024372 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('link-against-local-lib', 'c', version: '1.0.0') if meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl'] lib_compile_args = ['-DEXAMPLE_DLL_EXPORTS'] link_args = ['-DEXAMPLE_DLL_IMPORTS'] else lib_compile_args = [] link_args = ['-Wl,-rpath,custom-rpath'] endif subdir('lib') py = import('python').find_installation(pure: false) py.install_sources( '__init__.py', subdir: 'example', ) py.extension_module( '_example', 'examplemod.c', link_with: example_lib, link_args: link_args, install: true, subdir: 'example', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-against-local-lib/pyproject.toml0000664000000000000000000000034115257562503025137 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python] allow-windows-internal-shared-libs = true ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/foo/__init__.py0000664000000000000000000000023315257562503026063 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT from ._example import example_sum __all__ = ['example_sum'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/foo/_examplemod.c0000664000000000000000000000126115257562503026412 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include #include "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=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/foo/meson.build0000664000000000000000000000043115257562503026114 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT py.extension_module( '_example', '_examplemod.c', dependencies: bar_dep, install: true, subdir: 'foo', ) py.install_sources( ['__init__.py'], subdir: 'foo', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/meson.build0000664000000000000000000000052515257562503025335 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project( 'link-library-in-subproject', 'c', version: '1.0.0', meson_version: '>=1.2.0', ) py = import('python').find_installation(pure: false) bar_proj = subproject('bar') bar_dep = bar_proj.get_variable('bar_dep') subdir('foo') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/pyproject.toml0000664000000000000000000000050315257562503026103 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'link-library-in-subproject' version = '1.2.3' [tool.meson-python.args] setup = ['--default-library=static'] install = ['--skip-subprojects'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/subprojects/bar/bar_dll.h0000664000000000000000000000126415257562503030053 0ustar00rootroot// SPDX-FileCopyrightText: 2024 The meson-python developers // // SPDX-License-Identifier: MIT #pragma once // When building the `examplelib` DLL, this macro expands to `__declspec(dllexport)` // so we can annotate symbols appropriately as being exported. When used in // headers consuming a DLL, this macro expands to `__declspec(dllimport)` so // that consumers know the symbol is defined inside the DLL. In all other cases, // the macro expands to nothing. // Note: BAR_DLL_{EX,IM}PORTS are set in meson.build #if defined(BAR_DLL_EXPORTS) #define BAR_DLL __declspec(dllexport) #elif defined(BAR_DLL_IMPORTS) #define BAR_DLL __declspec(dllimport) #else #define BAR_DLL #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/subprojects/bar/examplelib.c0000664000000000000000000000025215257562503030565 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "bar_dll.h" BAR_DLL int sum(int a, int b) { return a + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/subprojects/bar/examplelib.h0000664000000000000000000000022515257562503030572 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "bar_dll.h" BAR_DLL int sum(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/link-library-in-subproject/subprojects/bar/meson.build0000664000000000000000000000200115257562503030433 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('bar', 'c', version: '1.2.3', meson_version: '>= 1.3.0') if get_option('default_library') == 'shared' and meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl'] export_dll_args = ['-DBAR_DLL_EXPORTS'] import_dll_args = ['-DBAR_DLL_IMPORTS'] else export_dll_args = [] import_dll_args = [] endif example_lib = library( 'examplelib', 'examplelib.c', c_shared_args: export_dll_args, install: true, ) # A second library that we don't link from `foo`. If we install the subproject, # this second library also ends up in the wheel. To prevent that, we need to # skip installing this `bar` subproject, and statically link `example_lib`. unwanted_lib = library( 'unwantedlib', 'examplelib.c', c_shared_args: export_dll_args, install: true, ) bar_dep = declare_dependency( compile_args: import_dll_args, link_with: example_lib, include_directories: '.', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/long-path/meson.build0000664000000000000000000000033715257562503022046 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT project('very-long-project-name-that-makes-the-paths-within-the-sdist-exceed-100-characters-xxxxxxxxxxxxxxxxx', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/long-path/pyproject.toml0000664000000000000000000000032615257562503022616 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'long-path' dynamic = ['version'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/missing-dynamic-version/meson.build0000664000000000000000000000020015257562503024720 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('missing-dynamic-version') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/missing-dynamic-version/pyproject.toml0000664000000000000000000000034415257562503025503 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/missing-meson-version/meson.build0000664000000000000000000000017615257562503024431 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('missing-meson-version') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/missing-meson-version/pyproject.toml0000664000000000000000000000024215257562503025175 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/module-types/file.py0000664000000000000000000000013415257562503021726 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/module-types/meson.build0000664000000000000000000000066615257562503022611 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/module-types/namespace/data.py0000664000000000000000000000013415257562503023654 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/module-types/native.c0000664000000000000000000000076615257562503022102 0ustar00rootroot// 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=1790895427.0 meson_python-0.22.1/tests/packages/module-types/package/__init__.py0000664000000000000000000000013415257562503024141 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/module-types/pyproject.toml0000664000000000000000000000024215257562503023351 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/pure/meson.build0000664000000000000000000000031115257562503021120 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/pure/pure.py0000664000000000000000000000017115257562503020307 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/pure/pyproject.toml0000664000000000000000000000024215257562503021675 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/purelib-and-platlib/meson.build0000664000000000000000000000066715257562503024012 0ustar00rootroot# 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', build_rpath: ':'.join(['/usr/local/lib', meson.current_build_dir() / 'private']), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/purelib-and-platlib/plat.c0000664000000000000000000000076215257562503022750 0ustar00rootroot// 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=1790895427.0 meson_python-0.22.1/tests/packages/purelib-and-platlib/pure.py0000664000000000000000000000017115257562503023163 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/purelib-and-platlib/pyproject.toml0000664000000000000000000000024215257562503024551 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/purelib-platlib-split/meson.build0000664000000000000000000000054215257562503024373 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/purelib-platlib-split/plat.py0000664000000000000000000000017115257562503023541 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/purelib-platlib-split/pure.py0000664000000000000000000000017115257562503023554 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/purelib-platlib-split/pyproject.toml0000664000000000000000000000024215257562503025142 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/meson.build0000664000000000000000000000033715257562503024136 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT project('same-name-sharedlibs', 'c', version: '1.0.0') py = import('python').find_installation(pure: false) subdir('same_name') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/pyproject.toml0000664000000000000000000000024215257562503024703 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/same_name/__init__.py0000664000000000000000000000013415257562503026025 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/same_name/competing/choice.c0000664000000000000000000000020315257562503027274 0ustar00rootroot// SPDX-FileCopyrightText: 2026 The meson-python developers // // SPDX-License-Identifier: MIT int choice(void) { return 7; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/same_name/competing/meson.build0000664000000000000000000000033315257562503030044 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT shared_library( 'choice', 'choice.c', install: true, install_dir: py.get_install_dir() / 'same_name/competing', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/same_name/meson.build0000664000000000000000000000137515257562503026066 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT subdir('competing') subdir('private') py.install_sources('__init__.py', subdir: 'same_name') origin = build_machine.system() == 'darwin' ? '@loader_path' : '$ORIGIN' # Simulate an external library whose runtime path is supplied through linker # flags (for example, -Wl,-rpath,... in LDFLAGS). Keep that library inside this # fixture to make the test self-contained. The requested private installation # path must take precedence over this preserved competing path. py.extension_module( 'choice', 'module.c', link_with: private, link_args: f'-Wl,-rpath,@origin@/competing', install: true, subdir: 'same_name', install_rpath: '$ORIGIN/private', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/same_name/module.c0000664000000000000000000000100715257562503025345 0ustar00rootroot// SPDX-FileCopyrightText: 2026 The meson-python developers // // SPDX-License-Identifier: MIT #include extern int choice(void); static PyObject *value(PyObject *self, PyObject *args) { return PyLong_FromLong(choice()); } static PyMethodDef methods[] = { {"value", value, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; static struct PyModuleDef module = { PyModuleDef_HEAD_INIT, "choice", NULL, -1, methods, }; PyMODINIT_FUNC PyInit_choice(void) { return PyModule_Create(&module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/same_name/private/choice.c0000664000000000000000000000020415257562503026762 0ustar00rootroot// SPDX-FileCopyrightText: 2026 The meson-python developers // // SPDX-License-Identifier: MIT int choice(void) { return 42; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/same-name-sharedlibs/same_name/private/meson.build0000664000000000000000000000034315257562503027532 0ustar00rootroot# SPDX-FileCopyrightText: 2026 The meson-python developers # # SPDX-License-Identifier: MIT private = shared_library( 'choice', 'choice.c', install: true, install_dir: py.get_install_dir() / 'same_name/private', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/meson.build0000664000000000000000000000111715257562503022223 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/mypkg/__init__.py0000664000000000000000000000017115257562503023320 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/mypkg/cy_extmod.pyx0000664000000000000000000000025115257562503023743 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/mypkg/extmod.c0000664000000000000000000000076415257562503022663 0ustar00rootroot// 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=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/mypkg/meson.build0000664000000000000000000000153015257562503023351 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/mypkg/submod/__init__.py0000664000000000000000000000013415257562503024610 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/mypkg/submod/unknown_filetype.npq0000664000000000000000000000027315257562503026623 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/pyproject.toml0000664000000000000000000000040215257562503022771 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/scipy-like/tools/generate_config.py0000664000000000000000000000033315257562503024711 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/meson.build0000664000000000000000000000046315257562503024107 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('sharedlib-in-package', 'c', version: '1.0.0') py = import('python').find_installation(pure: false) origin = build_machine.system() == 'darwin' ? '@loader_path' : '$ORIGIN' subdir('src') subdir('mypkg') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/mypkg/__init__.py0000664000000000000000000000340515257562503025204 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT import os import sys # start-literalinclude def _append_to_sharedlib_load_path(): """Ensure the shared libraries in this package can be loaded on Windows. Windows lacks a concept equivalent to RPATH: Python extension modules cannot find DLLs installed outside the DLL search path. This function ensures that the location of the shared libraries distributed inside this Python package is in the DLL search path of the process. The Windows DLL search path includes the path to the object attempting to load the DLL: it needs to be augmented only when the Python extension modules and the DLLs they require are installed in separate directories. Cygwin does not have the same default library search path: all locations where the shared libraries are installed need to be added to the search path. This function is very similar to the snippet inserted into the main ``__init__.py`` of a package by ``delvewheel`` when it vendors external shared libraries. .. note:: `os.add_dll_directory` is only available for Python 3.8 and later, and in the Conda ``python`` packages it works as advertised only for version 3.10 and later. For older Python versions, pre-loading the DLLs with `ctypes.WinDLL` may be preferred. """ basedir = os.path.dirname(__file__) subdir = os.path.join(basedir, 'sub') if os.name == 'nt': os.add_dll_directory(subdir) elif sys.platform == 'cygwin': os.environ['PATH'] = os.pathsep.join((os.environ['PATH'], basedir, subdir)) _append_to_sharedlib_load_path() # end-literalinclude from ._example import prodsum # noqa: E402 __all__ = ['prodsum'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/mypkg/_examplemod.c0000664000000000000000000000127615257562503025535 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include #include "lib.h" static PyObject* example_prodsum(PyObject* self, PyObject *args) { int a, b, x; if (!PyArg_ParseTuple(args, "iii", &a, &b, &x)) { return NULL; } long result = prodsum(a, b, x); return PyLong_FromLong(result); } static PyMethodDef methods[] = { {"prodsum", (PyCFunction)example_prodsum, 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=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/mypkg/meson.build0000664000000000000000000000122115257562503025227 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT # install_rpath is not exposed in the Meson introspection data in # Meson versions prior to 1.6.0 and thus cannot be set by meson-python # when building the Python wheel. Use link_args to set the RPATH when # using older Meson. kwargs = meson.version().version_compare('< 1.6') ? {'link_args': f'-Wl,-rpath,@origin@'} : {'install_rpath': f'@origin@'} py.extension_module( '_example', '_examplemod.c', dependencies: lib_dep, install: true, subdir: 'mypkg', kwargs: kwargs, ) py.install_sources( ['__init__.py'], subdir: 'mypkg', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/mypkg/sub/meson.build0000664000000000000000000000056515257562503026032 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT example_lib2 = shared_library( 'examplelib2', 'examplelib2.c', c_args: export_dll_args, install: true, install_dir: py.get_install_dir() / 'mypkg/sub', ) example_lib2_dep = declare_dependency( compile_args: import_dll_args, link_with: example_lib2, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/mypkg/sub/mypkg_dll.h0000664000000000000000000000165615257562503026025 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #pragma once // MYPKG_DLL // inspired by https://github.com/abseil/abseil-cpp/blob/20240116.2/absl/base/config.h#L736-L753 // and https://github.com/scipy/scipy/blob/9ded83b51099eee745418ccbb30196db96c81f3f/scipy/_build_utils/src/scipy_dll.h // // When building the `examplelib` DLL, this macro expands to `__declspec(dllexport)` // so we can annotate symbols appropriately as being exported. When used in // headers consuming a DLL, this macro expands to `__declspec(dllimport)` so // that consumers know the symbol is defined inside the DLL. In all other cases, // the macro expands to nothing. // Note: MYPKG_DLL_{EX,IM}PORTS are set in mypkg/meson.build #if defined(MYPKG_DLL_EXPORTS) #define MYPKG_DLL __declspec(dllexport) #elif defined(MYPKG_DLL_IMPORTS) #define MYPKG_DLL __declspec(dllimport) #else #define MYPKG_DLL #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/pyproject.toml0000664000000000000000000000024215257562503024654 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/src/lib.c0000664000000000000000000000030615257562503023442 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "lib.h" #include "sublib.h" int prodsum(int a, int b, int x) { return prod(a, x) + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/src/lib.h0000664000000000000000000000047415257562503023455 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #if defined(MYPKG_DLL_EXPORTS) #define EXPORT __declspec(dllexport) #elif defined(MYPKG_DLL_IMPORTS) #define EXPORT __declspec(dllimport) #else #define EXPORT #endif EXPORT int prodsum(int a, int b, int x); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/src/meson.build0000664000000000000000000000236215257562503024676 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT if meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl'] export_dll_args = ['-DMYPKG_DLL_EXPORTS'] import_dll_args = ['-DMYPKG_DLL_IMPORTS'] else export_dll_args = [] import_dll_args = [] endif sublib = shared_library( 'sublib', 'sublib.c', c_args: export_dll_args, install: true, install_dir: py.get_install_dir() / 'mypkg/sub', ) sublib_dep = declare_dependency( compile_args: import_dll_args, link_with: sublib, ) # install_rpath is not exposed in the Meson introspection data in # Meson versions prior to 1.6.0 and thus cannot be set by meson-python # when building the Python wheel. Use link_args to set the RPATH when # using older Meson. kwargs = meson.version().version_compare('< 1.6') ? {'link_args': f'-Wl,-rpath,@origin@/sub'} : {'install_rpath': f'@origin@/sub'} lib = shared_library( 'lib', 'lib.c', dependencies: sublib_dep, c_args: export_dll_args, install: true, install_dir: py.get_install_dir() / 'mypkg', kwargs: kwargs, ) lib_dep = declare_dependency( compile_args: import_dll_args, link_with: lib, include_directories: include_directories('.'), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/src/sublib.c0000664000000000000000000000024215257562503024153 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "sublib.h" int prod(int a, int b) { return a * b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package/src/sublib.h0000664000000000000000000000046215257562503024164 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #if defined(MYPKG_DLL_EXPORTS) #define EXPORT __declspec(dllexport) #elif defined(MYPKG_DLL_IMPORTS) #define EXPORT __declspec(dllimport) #else #define EXPORT #endif EXPORT int prod(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/meson.build0000664000000000000000000000034215257562503025345 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('sharedlib-in-package-legacy', 'c', version: '1.0.0') py = import('python').find_installation(pure: false) subdir('mypkg') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/__init__.py0000664000000000000000000000345215257562503026450 0ustar00rootroot# SPDX-FileCopyrightText: 2024 The meson-python developers # # SPDX-License-Identifier: MIT import os import sys # start-literalinclude def _append_to_sharedlib_load_path(): """Ensure the shared libraries in this package can be loaded on Windows. Windows lacks a concept equivalent to RPATH: Python extension modules cannot find DLLs installed outside the DLL search path. This function ensures that the location of the shared libraries distributed inside this Python package is in the DLL search path of the process. The Windows DLL search path includes the path to the object attempting to load the DLL: it needs to be augmented only when the Python extension modules and the DLLs they require are installed in separate directories. Cygwin does not have the same default library search path: all locations where the shared libraries are installed need to be added to the search path. This function is very similar to the snippet inserted into the main ``__init__.py`` of a package by ``delvewheel`` when it vendors external shared libraries. .. note:: `os.add_dll_directory` is only available for Python 3.8 and later, and in the Conda ``python`` packages it works as advertised only for version 3.10 and later. For older Python versions, pre-loading the DLLs with `ctypes.WinDLL` may be preferred. """ basedir = os.path.dirname(__file__) subdir = os.path.join(basedir, 'sub') if os.name == 'nt': os.add_dll_directory(subdir) elif sys.platform == 'cygwin': os.environ['PATH'] = os.pathsep.join((os.environ['PATH'], basedir, subdir)) _append_to_sharedlib_load_path() # end-literalinclude from ._example import example_prod, example_sum #noqa: E402 __all__ = ['example_prod', 'example_sum'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/_examplemod.c0000664000000000000000000000176015257562503026775 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include #include "examplelib.h" #include "examplelib2.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 PyObject* example_prod(PyObject* self, PyObject *args) { int a, b; if (!PyArg_ParseTuple(args, "ii", &a, &b)) { return NULL; } long result = prod(a, b); return PyLong_FromLong(result); } static PyMethodDef methods[] = { {"example_prod", (PyCFunction)example_prod, METH_VARARGS, NULL}, {"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=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/examplelib.c0000664000000000000000000000026215257562503026621 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "sub/mypkg_dll.h" MYPKG_DLL int sum(int a, int b) { return a + b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/examplelib.h0000664000000000000000000000023515257562503026626 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "sub/mypkg_dll.h" MYPKG_DLL int sum(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/meson.build0000664000000000000000000000160415257562503026476 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT if meson.get_compiler('c').get_id() in ['msvc', 'clang-cl', 'intel-cl'] export_dll_args = ['-DMYPKG_DLL_EXPORTS'] import_dll_args = ['-DMYPKG_DLL_IMPORTS'] else export_dll_args = [] import_dll_args = [] endif example_lib = shared_library( 'examplelib', 'examplelib.c', c_args: export_dll_args, install: true, install_dir: py.get_install_dir() / 'mypkg', ) example_lib_dep = declare_dependency( compile_args: import_dll_args, link_with: example_lib, ) subdir('sub') py.extension_module( '_example', '_examplemod.c', dependencies: [example_lib_dep, example_lib2_dep], include_directories: 'sub', install: true, subdir: 'mypkg', install_rpath: '$ORIGIN:$ORIGIN/sub', ) py.install_sources( ['__init__.py'], subdir: 'mypkg', ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/sub/examplelib2.c0000664000000000000000000000025715257562503027500 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "mypkg_dll.h" MYPKG_DLL int prod(int a, int b) { return a * b; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/sub/examplelib2.h0000664000000000000000000000023215257562503027476 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #include "mypkg_dll.h" MYPKG_DLL int prod(int a, int b); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/sub/meson.build0000664000000000000000000000056515257562503027274 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT example_lib2 = shared_library( 'examplelib2', 'examplelib2.c', c_args: export_dll_args, install: true, install_dir: py.get_install_dir() / 'mypkg/sub', ) example_lib2_dep = declare_dependency( compile_args: import_dll_args, link_with: example_lib2, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/mypkg/sub/mypkg_dll.h0000664000000000000000000000165615257562503027267 0ustar00rootroot// SPDX-FileCopyrightText: 2022 The meson-python developers // // SPDX-License-Identifier: MIT #pragma once // MYPKG_DLL // inspired by https://github.com/abseil/abseil-cpp/blob/20240116.2/absl/base/config.h#L736-L753 // and https://github.com/scipy/scipy/blob/9ded83b51099eee745418ccbb30196db96c81f3f/scipy/_build_utils/src/scipy_dll.h // // When building the `examplelib` DLL, this macro expands to `__declspec(dllexport)` // so we can annotate symbols appropriately as being exported. When used in // headers consuming a DLL, this macro expands to `__declspec(dllimport)` so // that consumers know the symbol is defined inside the DLL. In all other cases, // the macro expands to nothing. // Note: MYPKG_DLL_{EX,IM}PORTS are set in mypkg/meson.build #if defined(MYPKG_DLL_EXPORTS) #define MYPKG_DLL __declspec(dllexport) #elif defined(MYPKG_DLL_IMPORTS) #define MYPKG_DLL __declspec(dllimport) #else #define MYPKG_DLL #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/sharedlib-in-package-legacy/pyproject.toml0000664000000000000000000000024215257562503026116 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/simple/__init__.py0000664000000000000000000000020215257562503021404 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT from .test import data # noqa: F401 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/simple/data.txt0000664000000000000000000000000415257562503020745 0ustar00rootrootABC ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/simple/meson.build0000664000000000000000000000037015257562503021443 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/simple/pyproject.toml0000664000000000000000000000024215257562503022213 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/simple/test.py0000664000000000000000000000034415257562503020633 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/subdirs/meson.build0000664000000000000000000000037015257562503021625 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('subdirs', version: '1.0.0') py = import('python').find_installation() py.install_sources( 'subdirs/__init__.py', preserve_path: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subdirs/pyproject.toml0000664000000000000000000000024215257562503022375 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subdirs/subdirs/__init__.py0000664000000000000000000000013415257562503023245 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subdirs/subdirs/a/__init__.py0000664000000000000000000000013415257562503023465 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subdirs/subdirs/a/b/c.py0000664000000000000000000000013415257562503022371 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subdirs/subdirs/b/c.py0000664000000000000000000000013415257562503022151 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subproject/meson.build0000664000000000000000000000035015257562503022330 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/subproject/pyproject.toml0000664000000000000000000000045115257562503023104 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [tool.meson-python.wheel] exclude = [ '{datadir}/dep/*.txt', '{py_purelib}/dep.*', ] include = [ '{py_purelib}/dep.py', ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subproject/subproject.py0000664000000000000000000000013415257562503022720 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subproject/subprojects/dep/data.txt0000664000000000000000000000005515257562503024755 0ustar00rootrootexcluded via tool.meson-python.wheel.exclude ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subproject/subprojects/dep/dep.py0000664000000000000000000000013415257562503024423 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/subproject/subprojects/dep/meson.build0000664000000000000000000000107215257562503025445 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT project('dep') py = import('python').find_installation() py.install_sources( 'dep.py', ) install_data( 'data.txt', # Prior to meson 1.3.0, the default install path for subproject data files # is ``{datadir}/{main-project-name}/``. In later versions it is the more # correct ``{datadir}/{subproject-name}/``. Specify the install path to # obtain uniform behavior across different meson versions. install_dir: '{datadir}' / meson.project_name(), ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/symlinks/__init__.py0000664000000000000000000000013415257562503021770 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/symlinks/ccc.py0000664000000000000000000000016615257562503020766 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/symlinks/meson.build0000664000000000000000000000050415257562503022022 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT project('symlinks') py = import('python').find_installation() py.install_sources( '__init__.py', 'submodule/__init__.py', 'submodule/aaa.py', 'submodule/bbb.py', subdir: 'symlinks', preserve_path: true, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/symlinks/pyproject.toml0000664000000000000000000000032115257562503022571 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'symlinks' version = '1.0.0' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/symlinks/submodule/__init__.py0000664000000000000000000000013415257562503023767 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/symlinks/submodule/aaa.py0000664000000000000000000000016615257562503022757 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/symlinks/submodule/bbb.py0000664000000000000000000000016615257562503022762 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/unknown-user-args-meson-args/pyproject.toml0000664000000000000000000000031115257562503026375 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/unknown-user-args-top-level/pyproject.toml0000664000000000000000000000030415257562503026233 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/unsupported-python-version/meson.build0000664000000000000000000000022515257562503025543 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT project('unsupported-python-version', version: '1.0.0') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/unsupported-python-version/pyproject.toml0000664000000000000000000000037715257562503026325 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/user-args/meson.build0000664000000000000000000000031615257562503022062 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/user-args/pure.py0000664000000000000000000000017115257562503021244 0ustar00rootroot# SPDX-FileCopyrightText: 2022 The meson-python developers # # SPDX-License-Identifier: MIT def foo(): return 'bar' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/user-args/pyproject.toml0000664000000000000000000000046115257562503022635 0ustar00rootroot# 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 = ['--skip-subprojects=config'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/vendored-meson/meson.build0000664000000000000000000000044515257562503023102 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/vendored-meson/meson_options.txt0000664000000000000000000000023015257562503024365 0ustar00rootroot# SPDX-FileCopyrightText: 2023 The meson-python developers # # SPDX-License-Identifier: MIT option('custom-meson-used', type: 'boolean', value: false) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/packages/vendored-meson/pyproject.toml0000664000000000000000000000032615257562503023652 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/packages/vendored-meson/third-party/meson.py0000664000000000000000000000042015257562503024673 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/test_consistency.py0000664000000000000000000000274015257562503020207 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import sys from packaging import requirements, specifiers if sys.version_info >= (3, 11): import tomllib else: import tomli as tomllib import mesonpy def test_version(): pyproject = pathlib.Path(__file__).parent.parent.joinpath('pyproject.toml') with open(pyproject, 'rb') as f: project_version = tomllib.load(f)['project']['version'] assert mesonpy.__version__ == project_version 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"' def test_meson_version_requirement(): pyproject = pathlib.Path(__file__).parent.parent.joinpath('pyproject.toml') with open(pyproject, 'rb') as f: data = tomllib.load(f) for dep in data['project']['dependencies']: req = requirements.Requirement(dep) if req.name == 'meson' and req.marker.evaluate(): assert req.specifier == specifiers.SpecifierSet(f'>= {mesonpy._MESON_REQUIRED_VERSION}') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_editable.py0000664000000000000000000003731015257562503017420 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import io import os import pathlib import pkgutil import re import subprocess import sys from contextlib import redirect_stdout import pytest import wheel.wheelfile import mesonpy from mesonpy import _editable from .conftest import EXT_SUFFIX, FREE_THREADED_BUILD def find_cython_version(): cython_version_str = subprocess.run(['cython', '--version'], check=True, stdout=subprocess.PIPE, text=True).stdout version_str = re.search(r'(\d{1,4}\.\d{1,4}\.?\d{0,4})', cython_version_str).group(0) return tuple(map(int, version_str.split('.'))) CYTHON_VERSION = find_cython_version() 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') @pytest.mark.skipif(FREE_THREADED_BUILD and CYTHON_VERSION < (3, 1, 0), reason='Cython version too old, no free-threaded CPython support') def test_mesonpy_meta_finder(package_complex, tmp_path): # build a package in a temporary directory project = mesonpy.Project(package_complex, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder('complex', {'complex'}, os.fspath(tmp_path), project._build_command, True) # 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.extension assert complex.extension.__spec__.origin == os.fspath(tmp_path / f'extension{EXT_SUFFIX}') assert complex.extension.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' project = mesonpy.Project(package_path, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder('simple', {'simple'}, os.fspath(tmp_path), project._build_command, True) # 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' def test_importlib_resources(tmp_path): # build a package in a temporary directory package_path = pathlib.Path(__file__).parent / 'packages' / 'simple' project = mesonpy.Project(package_path, tmp_path) # point the meta finder to the build directory finder = _editable.MesonpyMetaFinder('simple', {'simple'}, os.fspath(tmp_path), project._build_command, True) 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_editable_contents(editable_simple): artifact = wheel.wheelfile.WheelFile(editable_simple) impl = 'start' if sys.version_info >= (3, 15) else 'pth' expecting = { 'simple-1.0.0.dist-info/METADATA', 'simple-1.0.0.dist-info/RECORD', 'simple-1.0.0.dist-info/WHEEL', '_simple_editable_loader.py', f'simple-editable.{impl}', } assert set(artifact.namelist()) == expecting 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) @pytest.mark.skipif(FREE_THREADED_BUILD and CYTHON_VERSION < (3, 1, 0), reason='Cython version too old, no free-threaded CPython support') def test_editable_pkgutils_walk_packages(package_complex, tmp_path): # build a package in a temporary directory project = mesonpy.Project(package_complex, tmp_path) finder = _editable.MesonpyMetaFinder('complex', {'complex'}, os.fspath(tmp_path), project._build_command, True) 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.extension', '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): project = mesonpy.Project(package_custom_target_dir, tmp_path) finder = _editable.MesonpyMetaFinder('package', {'package'}, os.fspath(tmp_path), project._build_command, True) 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 assert stdout.getvalue() == '' finally: del sys.meta_path[0] sys.modules.pop('pure', None) @pytest.mark.skipif(FREE_THREADED_BUILD and CYTHON_VERSION < (3, 1, 0), reason='Cython version too old, no free-threaded CPython support') 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') == '' @pytest.mark.parametrize('verbose', [False, True], ids=('', 'verbose')) def test_editable_rebuild_error(package_purelib_and_platlib, tmp_path, verbose): with mesonpy._project({'builddir': os.fspath(tmp_path)}) as project: finder = _editable.MesonpyMetaFinder( project._metadata.name, {'plat', 'pure'}, os.fspath(tmp_path), project._build_command, verbose=verbose, ) path = package_purelib_and_platlib / 'plat.c' code = path.read_text() try: # Install editable hooks sys.meta_path.insert(0, finder) # Insert invalid code in the extension module source code path.write_text('return') # Import module and trigger rebuild: the build fails and ImportError is raised stdout = io.StringIO() with redirect_stdout(stdout): with pytest.raises(ImportError, match='rebuilding the "purelib-and-platlib" ') as exc: import plat # noqa: F401 assert not verbose or stdout.getvalue().startswith('meson-python: building ') if sys.version_info >= (3, 11): assert verbose or hasattr(exc.value, '__notes__') assert verbose or 'ninja: build stopped: subcommand failed.' in exc.value.__notes__[0] else: assert verbose or 'ninja: build stopped: subcommand failed.' in exc.value.msg finally: del sys.meta_path[0] sys.modules.pop('pure', None) path.write_text(code) def test_editable_reconfigure_error(package_purelib_and_platlib, tmp_path): with mesonpy._project({'builddir': os.fspath(tmp_path)}) as project: finder = _editable.MesonpyMetaFinder( project._metadata.name, {'plat', 'pure'}, os.fspath(tmp_path), project._build_command, verbose=False, ) path = package_purelib_and_platlib / 'meson.build' code = path.read_text() try: # Install editable hooks sys.meta_path.insert(0, finder) # Emit an error (with unicode characters) during reconfigure with open(path, 'a', encoding='utf8') as f: f.write('\n\nerror(\'injected error \N{BOMB}\')\n') # Import module and trigger rebuild: the build fails and ImportErrror is raised stdout = io.StringIO() with redirect_stdout(stdout): with pytest.raises(ImportError, match='rebuilding the "purelib-and-platlib" ') as exc: import plat # noqa: F401 msg = exc.value.__notes__[0] if sys.version_info >= (3, 11) else exc.value.msg assert 'ERROR: Problem encountered: injected error' in msg assert 'ninja: error: rebuilding \'build.ninja\': subcommand failed' in msg finally: del sys.meta_path[0] sys.modules.pop('pure', None) path.write_text(code) def test_install_data(venv, editable_install_data, tmp_path): venv.pip('install', os.fspath(editable_install_data)) venv.python('-c', 'import package') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_metadata.py0000664000000000000000000000525215257562503017427 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import re import packaging.version import pyproject_metadata import pytest from mesonpy import Metadata try: import packaging.licenses as packaging_licenses except ImportError: packaging_licenses = None 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(): pyproject = {'project': { 'name': 'missing-version', }} match = '|'.join(( # pyproject-metatadata 0.8.0 and later re.escape('Field "project.version" missing and "version" not specified in "project.dynamic"'), # pyproject-metatadata 0.9.0 and later re.escape('Field "project.version" missing and \'version\' not specified in "project.dynamic"'), )) with pytest.raises(pyproject_metadata.ConfigurationError, match=match): Metadata.from_pyproject(pyproject, pathlib.Path()) @pytest.mark.skipif(packaging_licenses is None, reason='packaging too old') def test_normalize_license(): pyproject = {'project': { 'name': 'test', 'version': '1.2.3', 'license': 'mit or bsd-3-clause', }} metadata = Metadata.from_pyproject(pyproject, pathlib.Path()) assert metadata.license == 'MIT OR BSD-3-Clause' @pytest.mark.skipif(packaging_licenses is None, reason='packaging too old') def test_invalid_license(): pyproject = {'project': { 'name': 'test', 'version': '1.2.3', 'license': 'Foo', }} with pytest.raises(packaging_licenses.InvalidLicenseExpression, match='Unknown license: \'foo\''): Metadata.from_pyproject(pyproject, pathlib.Path()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_options.py0000664000000000000000000000244615257562503017344 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/test_output.py0000664000000000000000000000177515257562503017215 0ustar00rootroot# 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=1790895427.0 meson_python-0.22.1/tests/test_pep517.py0000664000000000000000000001274315257562503016673 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import re import shutil import subprocess import sys import textwrap 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'] @pytest.mark.parametrize('meson', [None, 'meson']) def test_get_meson_command(monkeypatch, meson): # The MESON environment variable affects the meson executable lookup and breaks the test. monkeypatch.delenv('MESON', raising=False) assert mesonpy._get_meson_command(meson) == ['meson'] def test_get_meson_command_bad_path(monkeypatch): # The MESON environment variable affects the meson executable lookup and breaks the test. monkeypatch.delenv('MESON', raising=False) with pytest.raises(mesonpy.ConfigError, match=re.escape('meson executable "bad" not found')): mesonpy._get_meson_command('bad') def test_get_meson_command_bad_python_path(monkeypatch): # The MESON environment variable affects the meson executable lookup and breaks the test. monkeypatch.delenv('MESON', raising=False) with pytest.raises(mesonpy.ConfigError, match=re.escape('Could not find the specified meson: "bad-python-path.py"')): mesonpy._get_meson_command('bad-python-path.py') def test_get_meson_command_wrong_version(monkeypatch, tmp_path): # The MESON environment variable affects the meson executable lookup and breaks the test. monkeypatch.delenv('MESON', raising=False) meson = tmp_path / 'meson.py' meson.write_text(textwrap.dedent(''' print('0.0.1') ''')) with pytest.raises(mesonpy.ConfigError, match=r'Could not find meson version [0-9\.]+ or newer, found 0\.0\.1\.'): mesonpy._get_meson_command(os.fspath(meson)) def test_get_meson_command_error(monkeypatch, tmp_path): # The MESON environment variable affects the meson executable lookup and breaks the test. monkeypatch.delenv('MESON', raising=False) meson = tmp_path / 'meson.py' meson.write_text(textwrap.dedent(''' import sys print('Just testing', file=sys.stderr) sys.exit(1) ''')) with pytest.raises(mesonpy.ConfigError, match=re.escape('Could not execute meson: Just testing')): mesonpy._get_meson_command(os.fspath(meson)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_project.py0000664000000000000000000004346415257562503017324 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import ast import os import platform import shutil import sys import sysconfig import textwrap from unittest.mock import Mock if sys.version_info < (3, 11): import tomli as tomllib else: import tomllib import pyproject_metadata import pytest import mesonpy from mesonpy._util import chdir from .conftest import MESON_VERSION, in_git_repo_context, metadata, package_dir def test_unsupported_python_version(package_unsupported_python_version): with pytest.raises(mesonpy.MesonBuilderError, match='The 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 @pytest.mark.skipif(MESON_VERSION < (1, 6, 0), reason='meson too old') @pytest.mark.filterwarnings('ignore:canonicalization and validation of license expression') def test_meson_build_metadata(tmp_path): tmp_path.joinpath('pyproject.toml').write_text(textwrap.dedent(''' [build-system] build-backend = 'mesonpy' requires = ['meson-python'] '''), encoding='utf8') tmp_path.joinpath('meson.build').write_text(textwrap.dedent(''' project('test', version: '1.2.3', license: 'MIT', license_files: 'LICENSE') '''), encoding='utf8') tmp_path.joinpath('LICENSE').write_text('') p = mesonpy.Project(tmp_path, tmp_path / 'build') assert metadata(bytes(p._metadata.as_rfc822())) == metadata(textwrap.dedent('''\ Metadata-Version: 2.4 Name: test Version: 1.2.3 License-Expression: MIT License-File: LICENSE ''')) @pytest.mark.skipif(MESON_VERSION < (1, 6, 0), reason='meson too old') @pytest.mark.filterwarnings('ignore:canonicalization and validation of license expression') def test_dynamic_license(tmp_path): tmp_path.joinpath('pyproject.toml').write_text(textwrap.dedent(''' [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'test' version = '1.0.0' dynamic = ['license'] '''), encoding='utf8') tmp_path.joinpath('meson.build').write_text(textwrap.dedent(''' project('test', license: 'MIT') '''), encoding='utf8') p = mesonpy.Project(tmp_path, tmp_path / 'build') assert metadata(bytes(p._metadata.as_rfc822())) == metadata(textwrap.dedent('''\ Metadata-Version: 2.4 Name: test Version: 1.0.0 License-Expression: MIT ''')) @pytest.mark.skipif(MESON_VERSION < (1, 6, 0), reason='meson too old') @pytest.mark.filterwarnings('ignore:canonicalization and validation of license expression') def test_dynamic_license_list(tmp_path): tmp_path.joinpath('pyproject.toml').write_text(textwrap.dedent(''' [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'test' version = '1.0.0' dynamic = ['license'] '''), encoding='utf8') tmp_path.joinpath('meson.build').write_text(textwrap.dedent(''' project('test', license: ['MIT', 'BSD-3-Clause']) '''), encoding='utf8') with pytest.raises(pyproject_metadata.ConfigurationError, match='Using a list of strings for the license'): mesonpy.Project(tmp_path, tmp_path / 'build') @pytest.mark.skipif(MESON_VERSION < (1, 6, 0), reason='meson too old') @pytest.mark.filterwarnings('ignore:canonicalization and validation of license expression') def test_dynamic_license_missing(tmp_path): tmp_path.joinpath('pyproject.toml').write_text(textwrap.dedent(''' [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'test' version = '1.0.0' dynamic = ['license'] '''), encoding='utf8') tmp_path.joinpath('meson.build').write_text(textwrap.dedent(''' project('test') '''), encoding='utf8') with pytest.raises(pyproject_metadata.ConfigurationError, match='Field "license" declared as dynamic but'): mesonpy.Project(tmp_path, tmp_path / 'build') @pytest.mark.skipif(MESON_VERSION < (1, 6, 0), reason='meson too old') @pytest.mark.filterwarnings('ignore:canonicalization and validation of license expression') def test_dynamic_license_files(tmp_path): tmp_path.joinpath('pyproject.toml').write_text(textwrap.dedent(''' [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'test' version = '1.0.0' dynamic = ['license', 'license-files'] '''), encoding='utf8') tmp_path.joinpath('meson.build').write_text(textwrap.dedent(''' project('test', license: 'MIT', license_files: ['LICENSE']) '''), encoding='utf8') tmp_path.joinpath('LICENSE').write_text('') p = mesonpy.Project(tmp_path, tmp_path / 'build') assert metadata(bytes(p._metadata.as_rfc822())) == metadata(textwrap.dedent('''\ Metadata-Version: 2.4 Name: test Version: 1.0.0 License-Expression: MIT License-File: LICENSE ''')) 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',), } 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' and 'meson compile' {'config-setup', 'cli-setup'}, {'config-compile', 'cli-compile'}, ] for expected_args, cmd_args in zip(expected, args, strict=True): assert expected_args.issubset(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) @pytest.mark.parametrize( ('cpu', 'cpu_family'), [ ('aarch64', 'aarch64'), ('armv7l', 'arm'), ('armv8l', 'arm'), ('i686', 'x86'), ('x86_64', 'x86_64'), ], ) @pytest.mark.parametrize('cross', [True, False]) def test_android_project(package_simple, monkeypatch, tmp_path, cpu, cpu_family, cross): # Mock being on Android monkeypatch.setattr(sys, 'platform', 'android') monkeypatch.setattr(sys, 'byteorder', 'little') monkeypatch.setattr(platform, 'system', Mock(return_value='Android')) monkeypatch.setattr(platform, 'machine', Mock(return_value=cpu)) monkeypatch.setattr(sysconfig, 'get_platform', Mock(return_value='android-24')) if cross: monkeypatch.setenv('CIBUILDWHEEL', '1') # Meson may require some tools to be configured when fatal warnings are enabled. # Set the same set of variables as cibuildwheel. for name in ['ar', 'as', 'cc', 'cxx', 'ld', 'nm', 'ranlib', 'readelf', 'strip']: monkeypatch.setenv(name.upper(), f'/path/to/{name}') # Create a project. project = mesonpy.Project(source_dir=package_simple, build_dir=tmp_path) # When cross-compiling, a cross file should be generated and used. setup_args = project._meson_args['setup'] cross_path = tmp_path / 'meson-python-cross-file.ini' if cross: assert setup_args[-2:] == ['--cross-file', str(cross_path)] cross_config = cross_path.read_text().splitlines() assert "system = 'android'" in cross_config assert "subsystem = 'android'" in cross_config assert "kernel = 'linux'" in cross_config assert f"cpu_family = '{cpu_family}'" in cross_config assert f"cpu = '{cpu}'" in cross_config assert "endian = 'little'" in cross_config assert 'needs_exe_wrapper = true' in cross_config else: assert '--cross-file' not in setup_args assert not cross_path.exists() @pytest.mark.skipif(sys.version_info < (3, 13), reason='requires Python 3.13 or higher') @pytest.mark.parametrize('multiarch', [ 'arm64-iphoneos', 'arm64-iphonesimulator', 'x86_64-iphonesimulator', ]) def test_ios_project(package_simple, monkeypatch, multiarch, tmp_path): arch, abi = multiarch.split('-') subsystem = 'ios-simulator' if abi == 'iphonesimulator' else 'ios' # Mock being on iOS monkeypatch.setattr(sys, 'platform', 'ios') monkeypatch.setattr(platform, 'machine', Mock(return_value=arch)) monkeypatch.setattr(sysconfig, 'get_platform', Mock(return_value=f'ios-13.0-{multiarch}')) ios_ver = platform.IOSVersionInfo('iOS', '13.0', 'iPhone', multiarch.endswith('simulator')) monkeypatch.setattr(platform, 'ios_ver', Mock(return_value=ios_ver)) # Create an iOS project. project = mesonpy.Project(source_dir=package_simple, build_dir=tmp_path) # Meson configuration points at the cross file assert project._meson_args['setup'][-2:] == ['--cross-file', os.fspath(tmp_path / 'meson-python-cross-file.ini')] # Meson config files exist, and have some relevant keys assert (tmp_path / 'meson-python-native-file.ini').exists() assert (tmp_path / 'meson-python-cross-file.ini').exists() cross_config = (tmp_path / 'meson-python-cross-file.ini').read_text() assert "\nsystem = 'ios'\n" in cross_config assert f"\nc = '{arch}-apple-{subsystem}-clang'\n" in cross_config assert f"\nsubsystem = '{subsystem}'\n" in cross_config @pytest.mark.parametrize('verbose', ['true', 'false']) def test_editable_verbose_pyproject(tmp_path, verbose): tmp_path.joinpath('pyproject.toml').write_text(textwrap.dedent(f''' [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'test' version = '1.0.0' [tool.meson-python] editable-verbose = {verbose} '''), encoding='utf8') tmp_path.joinpath('meson.build').write_text(textwrap.dedent(''' project('test') '''), encoding='utf8') project = mesonpy.Project(tmp_path, tmp_path / 'build') assert project._editable_verbose == (verbose == 'true') @pytest.mark.parametrize('settings,expected', [ ({}, True), ({'editable-verbose': ''}, True), ({'editable-verbose': 'true'}, True), ({'editable-verbose': 'false'}, False), ], ids=['', '-Ceditable-verbose', '-Ceditable-verbose=true', '-Ceditable-verbose=false']) def test_editable_verbose_settings(tmp_path, settings, expected): tmp_path.joinpath('pyproject.toml').write_text(textwrap.dedent(''' [build-system] build-backend = 'mesonpy' requires = ['meson-python'] [project] name = 'test' version = '1.0.0' [tool.meson-python] editable-verbose = true '''), encoding='utf8') tmp_path.joinpath('meson.build').write_text(textwrap.dedent(''' project('test') '''), encoding='utf8') with chdir(tmp_path): with mesonpy._project(settings) as project: assert project._editable_verbose == expected ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_rpath.py0000664000000000000000000000265415257562503016770 0ustar00rootroot# SPDX-FileCopyrightText: 2025 The meson-python developers # # SPDX-License-Identifier: MIT import sys import pytest import wheel.wheelfile from mesonpy._rpath import get_rpath, set_rpath @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') def test_rpath_get_set(wheel_sharedlib_in_package, tmp_path): artifact = wheel.wheelfile.WheelFile(wheel_sharedlib_in_package) artifact.extractall(tmp_path) obj = list(tmp_path.joinpath('mypkg').glob('_example.*'))[0] rpath = get_rpath(obj) assert rpath set_rpath(obj, rpath, []) rpath = get_rpath(obj) assert rpath == [] new_rpath = ['one', 'two'] set_rpath(obj, rpath, new_rpath) rpath = get_rpath(obj) assert rpath == new_rpath new_rpath = ['one', 'three', 'two'] set_rpath(obj, rpath, new_rpath) rpath = get_rpath(obj) assert rpath == new_rpath new_rpath = ['one'] set_rpath(obj, rpath, new_rpath) rpath = get_rpath(obj) assert rpath == new_rpath new_rpath = [ 'with two or three spaces', 'trailing space ', '/some funny absolute path/(library)', '@loader_path/Mach-O relative', '$ORIGIN/ELF relative', ] set_rpath(obj, rpath, new_rpath) rpath = get_rpath(obj) assert rpath == new_rpath new_rpath = ['alpha', 'beta'] set_rpath(obj, rpath, new_rpath) rpath = get_rpath(obj) assert rpath == new_rpath ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_sdist.py0000664000000000000000000002070115257562503016771 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import pathlib import stat import sys import tarfile import textwrap import time import pytest import mesonpy from .conftest import MESON_VERSION, in_git_repo_context, metadata def test_meson_build_metadata(sdist_library): with tarfile.open(sdist_library, 'r:gz') as sdist: sdist_pkg_info = sdist.extractfile('library-1.0.0/PKG-INFO').read() assert metadata(sdist_pkg_info) == metadata(textwrap.dedent('''\ Metadata-Version: 2.1 Name: library Version: 1.0.0 ''')) def test_pep621_metadata(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() meta = metadata(sdist_pkg_info) # Including the trailing newline in the expected value is inconvenient. meta['license'] = meta['license'].rstrip() assert meta == metadata(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,keyword with spaces 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() assert metadata(sdist_pkg_info) == metadata(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 = textwrap.dedent(''' def bar(): return 'foo' ''').strip() old = pathlib.Path('pure.py').read_text() with in_git_repo_context(): try: pathlib.Path('pure.py').write_text(new) pathlib.Path('other.py').touch() sdist_path = mesonpy.build_sdist(tmp_path) finally: pathlib.Path('pure.py').write_text(old) pathlib.Path('other.py').unlink() 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()} data = sdist.extractfile('pure-1.0.0/pure.py').read().replace(b'\r\n', b'\n') # Verify that uncommitted changes are not included in the sdist. 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 data == old.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 def test_long_path(sdist_long_path): # See https://github.com/mesonbuild/meson-python/pull/587#pullrequestreview-2020891328 # and https://github.com/mesonbuild/meson-python/pull/587#issuecomment-2075973593 with tarfile.open(sdist_long_path, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} assert names == { 'long_path-1.0.0/PKG-INFO', 'long_path-1.0.0/meson.build', 'long_path-1.0.0/pyproject.toml' } def test_reproducible(package_pure, tmp_path): with in_git_repo_context(): t1 = time.time() sdist_path_a = mesonpy.build_sdist(tmp_path / 'a') t2 = time.time() # Ensure that the two sdists are build at least one second apart. time.sleep(max(t1 + 1.0 - t2, 0.0)) sdist_path_b = mesonpy.build_sdist(tmp_path / 'b') assert sdist_path_a == sdist_path_b assert tmp_path.joinpath('a', sdist_path_a).read_bytes() == tmp_path.joinpath('b', sdist_path_b).read_bytes() # ``meson dist`` before Meson 1.9.2 does not handle tarballs # containing symbolic links to absolute paths on Python 3.14. # See https://github.com/mesonbuild/meson/issues/15142 @pytest.mark.skipif(sys.version_info >= (3, 14) and MESON_VERSION < (1, 9, 2), reason='incompatible Python version') @pytest.mark.filterwarnings('ignore:symbolic link') def test_symlinks(tmp_path, sdist_symlinks): with tarfile.open(sdist_symlinks, 'r:gz') as sdist: names = {member.name for member in sdist.getmembers()} mtimes = {member.mtime for member in sdist.getmembers()} # Check that the symlinks `baz.py` and `qux.py` pointing outside the # source tree are not included. These files are present in the # meson-python git repository but cannot be included in the meson-python # sdist. Thus this test is effective only when run from a git checkout. assert names == { 'symlinks-1.0.0/PKG-INFO', 'symlinks-1.0.0/meson.build', 'symlinks-1.0.0/pyproject.toml', 'symlinks-1.0.0/__init__.py', 'symlinks-1.0.0/ccc.py', 'symlinks-1.0.0/submodule/__init__.py', 'symlinks-1.0.0/submodule/aaa.py', 'symlinks-1.0.0/submodule/bbb.py', } # All the archive members have a valid mtime. assert 0 not in mtimes ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_tags.py0000664000000000000000000001724015257562503016605 0ustar00rootroot# 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 from unittest.mock import Mock import packaging.tags import pytest import mesonpy import mesonpy._tags from .conftest import FREE_THREADED_BUILD, 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(): """Get the filename suffix identifying stable ABI extension modules.""" # EXTENSION_SUFFIXES is ordered from the more to the less specific ABI. # On Python 3.15 or later, this resolves to ``.abi3t-${arch}`` for # free-threaded builds and to ``.abi3-${arch}`` on regular builds. # # Older Python versions do not support a stable ABI for free-threaded # builds, and do not support a platform-specific filename suffix, and # this resolves to simply ``.abi3``. # # On Windows, Python does not use a dedicated filename suffix for stable # ABI extension modules, and this resolves to ``.pyd``. # # Returns None on platforms not supporting the stable ABI (notably PyPy). for suffix in importlib.machinery.EXTENSION_SUFFIXES: if suffix.startswith('.abi3'): return suffix if suffix == '.pyd': return suffix return None SUFFIX = sysconfig.get_config_var('EXT_SUFFIX') ABI3SUFFIX = get_abi3_suffix() STABLE_ABI_KIND = 'abi3t' if FREE_THREADED_BUILD and sys.version_info >= (3, 15) else 'abi3' 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() for major in range(11, 13): monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'{major}.0') assert next(packaging.tags.mac_platforms((major, 0))) == mesonpy._tags.get_platform_tag() monkeypatch.setenv('MACOSX_DEPLOYMENT_TARGET', f'{major}') assert next(packaging.tags.mac_platforms((major, 0))) == 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') @pytest.mark.skipif(sys.version_info < (3, 13), reason='requires Python 3.13 or higher') @pytest.mark.skipif(sys.platform != 'darwin', reason='macOS specific test') def test_ios_platform_tag(monkeypatch): # Mock being on iOS monkeypatch.setattr(sys.implementation, '_multiarch', 'arm64-iphoneos') monkeypatch.setattr(sysconfig, 'get_platform', Mock(return_value='ios-13.0-arm64-iphoneos')) ios_ver = platform.IOSVersionInfo('iOS', '13.0', 'iPhone', False) monkeypatch.setattr(platform, 'ios_ver', Mock(return_value=ios_ver)) # Check the default value assert next(packaging.tags.ios_platforms((13, 0))) == mesonpy._tags.get_platform_tag() # Check the value when IPHONEOS_DEPLOYMENT_TARGET is set. for major in range(13, 20): for minor in range(3): monkeypatch.setenv('IPHONEOS_DEPLOYMENT_TARGET', f'{major}.{minor}') assert next(packaging.tags.ios_platforms((major, minor))) == mesonpy._tags.get_platform_tag() def wheel_builder_test_factory(content, pure=True, limited_api=False): manifest = defaultdict(list) for key, value in content.items(): manifest[key] = [mesonpy._Entry(pathlib.Path(x), os.path.join('build', x)) for x in value] return mesonpy._WheelBuilder(None, manifest, limited_api, False) 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 or SUFFIX}'], }, limited_api=True) # PyPy does not support the stable ABI. if not ABI3SUFFIX: abi = ABI elif FREE_THREADED_BUILD and sys.version_info >= (3, 15): abi = 'abi3.abi3t' else: abi = 'abi3' assert str(builder.tag) == f'{INTERPRETER}-{abi}-{PLATFORM}' @pytest.mark.xfail(not ABI3SUFFIX, reason='interpreter does not support the stable ABI') def test_tag_mixed_abi(): builder = wheel_builder_test_factory({ 'platlib': [f'extension{ABI3SUFFIX or SUFFIX}', 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}' @pytest.mark.skipif(not ABI3SUFFIX, reason='interpreter does not support the stable ABI') def test_tag_stable_abi_multiarch(): # Python 3.15 and later append the multiarch tuple to the stable ABI # filename suffix. Verify that it is ignored rather than causing the # module to be rejected: when cross compiling it differs from the one # of the build interpreter. builder = wheel_builder_test_factory({ 'platlib': [f'extension.{STABLE_ABI_KIND}-aarch64-linux-gnu.so'], }, pure=False, limited_api=True) abi = 'abi3.abi3t' if STABLE_ABI_KIND == 'abi3t' else 'abi3' assert str(builder.tag) == f'{INTERPRETER}-{abi}-{PLATFORM}' @pytest.mark.skipif(sys.implementation.name != 'cpython', reason='fallback implemented for CPython only') def test_abi_tag_fallback(monkeypatch): assert mesonpy._tags.get_abi_tag() == ABI sysconfig_get_config_var = sysconfig.get_config_var def get_config_var(name): value = sysconfig_get_config_var(name) if name == 'EXT_SUFFIX': value = '.' + value.split('.')[-1] return value # Remove $SOABI from $EXT_SUFFIX to simulate a Python interpreter # that does not implement PEP 3149. Verify that the fallback code # produces the same ABI tag. monkeypatch.setattr(sysconfig, 'get_config_var', get_config_var) assert mesonpy._tags.get_abi_tag() == ABI ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_wheel.py0000664000000000000000000005277615257562503016770 0ustar00rootroot# SPDX-FileCopyrightText: 2021 The meson-python developers # # SPDX-License-Identifier: MIT import os import re import shutil import stat import subprocess import sys import textwrap import packaging.tags import pytest import wheel.wheelfile import mesonpy from .conftest import EXT_SUFFIX, FREE_THREADED_BUILD, MESON_VERSION, adjust_packaging_platform_tag, metadata 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) # Support for removing build RPATH entries requires Meson 1.9 or later. BUILD_RPATH_SUPPORT = MESON_VERSION >= (1, 9) 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.filterwarnings('ignore:canonicalization and validation of license expression') def test_license_pep639(wheel_license_pep639): artifact = wheel.wheelfile.WheelFile(wheel_license_pep639) assert wheel_contents(artifact) == { 'license_pep639-1.0.0.dist-info/METADATA', 'license_pep639-1.0.0.dist-info/RECORD', 'license_pep639-1.0.0.dist-info/WHEEL', 'license_pep639-1.0.0.dist-info/licenses/LICENSES/BSD-3-Clause.txt', 'license_pep639-1.0.0.dist-info/licenses/LICENSES/MIT.txt', } assert metadata(artifact.read('license_pep639-1.0.0.dist-info/METADATA')) == metadata(textwrap.dedent('''\ Metadata-Version: 2.4 Name: license-pep639 Version: 1.0.0 License-Expression: MIT OR BSD-3-Clause License-File: LICENSES/BSD-3-Clause.txt License-File: LICENSES/MIT.txt ''')) @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') 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', } 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(MESON_VERSION < (1, 6, 0), reason='meson too old') @pytest.mark.filterwarnings('ignore:translated "install_rpath" argument for ') def test_sharedlib_in_package_legacy(venv, wheel_sharedlib_in_package_legacy): venv.pip('install', wheel_sharedlib_in_package_legacy) output = venv.python('-c', 'import mypkg; print(mypkg.example_sum(2, 5))') assert int(output) == 7 output = venv.python('-c', 'import mypkg; print(mypkg.example_prod(6, 7))') assert int(output) == 42 @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') def test_sharedlib_in_package_rpath(package_sharedlib_in_package, tmp_path): filename = mesonpy.build_wheel(tmp_path) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) artifact.extractall(tmp_path) origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN' def check(rpath, *expected): entries = [] for path in rpath: if path.startswith(origin): entries.append(path) continue # There may be RPATH entries added by the build environment. # However, these should be absolute paths and not point into # the source or build directory. assert not os.path.commonpath((path, str(package_sharedlib_in_package))) == str(package_sharedlib_in_package) assert not os.path.commonpath((path, str(tmp_path))) == str(tmp_path) assert entries == list(expected) or not BUILD_RPATH_SUPPORT and set(entries) >= set(expected) rpath = mesonpy._rpath.get_rpath(tmp_path / 'mypkg' / f'_example{EXT_SUFFIX}') check(rpath, origin) rpath = mesonpy._rpath.get_rpath(tmp_path / 'mypkg' / f'liblib{LIB_SUFFIX}') check(rpath, f'{origin}/sub') rpath = mesonpy._rpath.get_rpath(tmp_path / 'mypkg' / 'sub' / f'libsublib{LIB_SUFFIX}') check(rpath) @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') def test_sharedlib_in_package_rpath_ldflags(package_sharedlib_in_package, tmp_path, monkeypatch): origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN' extra_rpath = {f'{origin}/test-ldflags', '/usr/lib/test-ldflags'} ldflags = ' '.join(f'-Wl,-rpath,{p}' for p in extra_rpath) monkeypatch.setenv('LDFLAGS', ldflags) filename = mesonpy.build_wheel(tmp_path) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) artifact.extractall(tmp_path) for path in f'_example{EXT_SUFFIX}', f'liblib{LIB_SUFFIX}', f'sub/libsublib{LIB_SUFFIX}': rpath = set(mesonpy._rpath.get_rpath(tmp_path / 'mypkg' / path)) assert extra_rpath <= rpath def test_sharedlib_in_package(venv, wheel_sharedlib_in_package): venv.pip('install', wheel_sharedlib_in_package) output = venv.python('-c', 'import mypkg; print(mypkg.prodsum(2, 3, 4))') assert int(output) == 11 @pytest.mark.skipif(MESON_VERSION < (1, 3, 0), reason='meson too old') def test_link_library_in_subproject(venv, wheel_link_library_in_subproject): venv.pip('install', wheel_link_library_in_subproject) output = venv.python('-c', 'import foo; print(foo.example_sum(3, 6))') assert int(output) == 9 @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') def test_link_against_local_lib_rpath(package_link_against_local_lib, tmp_path): filename = mesonpy.build_wheel(tmp_path) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) artifact.extractall(tmp_path) origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN' def check(rpath, *expected): entries = [] for path in rpath: if path.startswith(origin) or path in expected: entries.append(path) continue # There may be RPATH entries added by the build environment. # However, these should be absolute paths and not point into # the source or build directory. assert not os.path.commonpath((path, str(package_link_against_local_lib))) == str(package_link_against_local_lib) assert not os.path.commonpath((path, str(tmp_path))) == str(tmp_path) assert entries == list(expected) or not BUILD_RPATH_SUPPORT and set(entries) >= set(expected) rpath = mesonpy._rpath.get_rpath(tmp_path / 'example' / f'_example{EXT_SUFFIX}') check(rpath, 'custom-rpath', f'{origin}/../.link_against_local_lib.mesonpy.libs') @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') @pytest.mark.skipif(shutil.which('pkg-config') is None, reason='requires pkg-config') def test_link_against_external_lib_rpath(package_link_against_external_lib, tmp_path, venv): if subprocess.run(['pkg-config', '--exists', 'geos']).returncode: pytest.skip('requires GEOS') version = subprocess.check_output(['pkg-config', '--modversion', 'geos'], text=True).strip() # Use an installed dependency without supplying an explicit RPATH. # Check its version too, to detect fallback to a different system copy. filename = mesonpy.build_wheel(tmp_path) venv.pip('install', tmp_path / filename) output = venv.python('-c', 'import external; print(external.version())') # GEOSversion() appends the C API version after "-CAPI-". assert output.strip().split('-CAPI-')[0] == version @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') def test_link_against_local_lib_rpath_ldflags(package_link_against_local_lib, tmp_path, monkeypatch): origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN' extra_rpath = {f'{origin}/test-ldflags', '/usr/lib/test-ldflags'} ldflags = ' '.join(f'-Wl,-rpath,{p}' for p in extra_rpath) monkeypatch.setenv('LDFLAGS', ldflags) filename = mesonpy.build_wheel(tmp_path) artifact = wheel.wheelfile.WheelFile(tmp_path / filename) artifact.extractall(tmp_path) rpath = set(mesonpy._rpath.get_rpath(tmp_path / 'example' / f'_example{EXT_SUFFIX}')) assert extra_rpath <= rpath @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') def test_uneeded_rpath(wheel_purelib_and_platlib, tmp_path): artifact = wheel.wheelfile.WheelFile(wheel_purelib_and_platlib) artifact.extractall(tmp_path) origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN' rpath = mesonpy._rpath.get_rpath(tmp_path / f'plat{EXT_SUFFIX}') assert not any(path.startswith(origin) for path in rpath) assert '/usr/local/lib' in rpath assert not any(path.endswith('private') for path in rpath) or not BUILD_RPATH_SUPPORT @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires RPATH support') @pytest.mark.filterwarnings('ignore:translated "install_rpath" argument for ') def test_rpath_install_precedence(venv, wheel_same_name_sharedlibs, tmp_path): artifact = wheel.wheelfile.WheelFile(wheel_same_name_sharedlibs) artifact.extractall(tmp_path) origin = '@loader_path' if sys.platform == 'darwin' else '$ORIGIN' rpath = mesonpy._rpath.get_rpath(tmp_path / 'same_name' / f'choice{EXT_SUFFIX}') assert rpath.index(f'{origin}/private') < rpath.index(f'{origin}/competing') venv.pip('install', wheel_same_name_sharedlibs) output = venv.python('-c', 'from same_name import choice; print(choice.value())') assert int(output) == 42 @pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='requires executable bit support') 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, project._allow_windows_shared_libs) 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 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 too old') @pytest.mark.skipif(FREE_THREADED_BUILD, reason='Free-threaded CPython does not support the limited API') @pytest.mark.xfail('__pypy__' in sys.builtin_module_names, reason='PyPy does not support the abi3 platform tag for wheels') 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 too old') @pytest.mark.skipif(FREE_THREADED_BUILD, reason='Free-threaded CPython does not support the limited API') @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 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', } # On Linux, Meson 1.10 or later is required, see https://github.com/mesonbuild/meson/pull/15141 @pytest.mark.skipif(sys.platform == 'linux' and MESON_VERSION < (1, 9, 99), reason='meson too old') @pytest.mark.skipif(sys.platform not in {'linux', 'darwin'}, reason='Not supported on this platform') def test_cmake_subproject(wheel_cmake_subproject): artifact = wheel.wheelfile.WheelFile(wheel_cmake_subproject) assert wheel_contents(artifact) == { 'cmake_subproject-1.dist-info/METADATA', 'cmake_subproject-1.dist-info/RECORD', 'cmake_subproject-1.dist-info/WHEEL', f'.cmake_subproject.mesonpy.libs/libcmaketest{LIB_SUFFIX}', f'cmakesubproject{EXT_SUFFIX}', } # Requires Meson 1.3.0, see https://github.com/mesonbuild/meson/pull/11745. @pytest.mark.skipif(MESON_VERSION < (1, 2, 99), reason='meson too old') @pytest.mark.skipif(sys.version_info < (3, 15), reason='Requires PEP 820 API, present since Python 3.15') def test_limited_api_free_threaded(wheel_limited_api_free_threaded): artifact = wheel.wheelfile.WheelFile(wheel_limited_api_free_threaded) name = artifact.parsed_filename assert name.group('pyver') == INTERPRETER assert name.group('abi') == ('abi3.abi3t' if FREE_THREADED_BUILD else 'abi3') assert name.group('plat') == PLATFORM ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/tests/test_wheelfile.py0000664000000000000000000000350315257562503017610 0ustar00rootroot# 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1790895427.0 meson_python-0.22.1/PKG-INFO0000644000000000000000000000412415257562503014164 0ustar00rootrootMetadata-Version: 2.4 Name: meson-python Version: 0.22.1 Summary: The Python build backend for Meson projects Keywords: meson,build,backend,pep517,package Maintainer-Email: Ralf Gommers , Daniele Nicolodi , Henry Schreiner License-Expression: MIT License-File: LICENSES/MIT.txt 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.10 Requires-Dist: meson>=0.64.0; python_version < "3.12" Requires-Dist: meson>=1.2.3; python_version >= "3.12" Requires-Dist: packaging>=23.2; sys_platform != "ios" Requires-Dist: packaging>=24.2; sys_platform == "ios" Requires-Dist: pyproject-metadata>=0.9.0 Requires-Dist: tomli>=1.0.0; python_version < "3.11" 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/