Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python: Use meson-python instead of setuptools #644

Merged
merged 9 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/build-and-test-device.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ on:
- 'CMakeLists.txt'
- '.github/workflows/build-and-test-device.yaml'
- 'src/nanoarrow/**'
- 'python/setup.py'
- 'python/meson.build'
- 'python/src/nanoarrow/meson.build'

permissions:
contents: read
Expand Down
37 changes: 30 additions & 7 deletions .github/workflows/python-wheels.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ on:
- main
paths:
- '.github/workflows/python-wheels.yaml'
- 'python/setup.py'
- 'python/meson.build'
- 'python/src/nanoarrow/meson.build'
- 'python/pyproject.toml'
- 'python/bootstrap.py'
- 'python/generate_dist.py'
- 'python/MANIFEST.in'
push:
branches:
Expand Down Expand Up @@ -93,12 +95,13 @@ jobs:
strategy:
matrix:
config:
- {os: "ubuntu-20.04", label: "pyodide", platform: "pyodide"}
- {os: "ubuntu-20.04", label: "linux", platform: "auto"}
- {os: "windows-2019", label: "windows", platform: "auto"}
- {os: "macOS-13", label: "macOS", platform: "auto"}
- {os: "macOS-14", label: "macOS-arm64", platform: "auto"}
- {os: ["self-hosted", "arm"], label: "linux-arm64", platform: "auto"}
- {os: "ubuntu-20.04", label: "pyodide", platform: "pyodide", arch: "auto"}
- {os: "ubuntu-20.04", label: "linux", platform: "auto", arch: "auto"}
- {os: "windows-2019", label: "windows-x86", platform: "auto", arch: "x86"}
- {os: "windows-2019", label: "windows-amd64", platform: "auto", arch: "AMD64"}
- {os: "macOS-13", label: "macOS", platform: "auto", arch: "auto"}
- {os: "macOS-14", label: "macOS-arm64", platform: "auto", arch: "auto"}
- {os: ["self-hosted", "arm"], label: "linux-arm64", platform: "auto", arch: "auto"}

steps:
- uses: actions/checkout@v4
Expand All @@ -107,9 +110,28 @@ jobs:
fetch-tags: true

- uses: actions/setup-python@v5
if: matrix.config.arch != 'x86'
with:
python-version: "3.12"

- name: Setup MSVC (64-bit)
if: matrix.config.arch == 'AMD64'
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64

- uses: actions/setup-python@v5
if: matrix.config.arch == 'x86'
with:
python-version: "3.12"
architecture: x86

- name: Setup MSVC (32-bit)
if: matrix.config.arch == 'x86'
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x86

- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.21.1

Expand All @@ -125,6 +147,7 @@ jobs:
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests -vv
CIBW_PLATFORM: ${{ matrix.config.platform }}
CIBW_ARCHS: ${{ matrix.config.arch }}

- uses: actions/upload-artifact@v4
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,8 @@ __pycache__
subprojects/*
!subprojects/packagefiles
!subprojects/*.wrap
python/subprojects/*
!python/subprojects/packagefiles
!python/subprojects/*.wrap

compile_commands.json
1 change: 1 addition & 0 deletions dev/release/rat_exclude_files.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ dist/flatcc.c
src/nanoarrow/ipc/flatcc_generated.h
thirdparty/*
python/src/nanoarrow/dlpack_abi.h
python/subprojects/arrow-nanoarrow
2 changes: 1 addition & 1 deletion dev/release/source_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ main() {
# Resolve all hard and symbolic links
rm -rf "${base_name}.tmp/"
mv "${base_name}/" "${base_name}.tmp/"
cp -R -L "${base_name}.tmp" "${base_name}"
cp -R -d "${base_name}.tmp" "${base_name}"
rm -rf "${base_name}.tmp/"

# Create new tarball
Expand Down
6 changes: 5 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ if get_option('ipc')
)
nanoarrow_ipc_dep = declare_dependency(include_directories: [incdir],
link_with: nanoarrow_ipc_lib,
dependencies: [nanoarrow_dep, flatcc_dep])
dependencies: [nanoarrow_dep])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was a mistake to include the flatcc_dep transitively here; I think its only required to build the nanoarrow_ipc lib itself, but shouldn't be required by libraries that want to use nanoarrow_ipc (?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unclear on the difference but yes, the flatcc headers are deliberately not included in nanoarrow's public headers such that a library using nanoarrow does not need flatcc/* files in the include path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea this removal here essentially removes the flatcc headers from being included by downstream targets that use the nanoarrow_ipc_dep; this is akin to changing the flatcc target inclusion from PUBLIC to PRIVATE in CMake

endif

needs_device = get_option('device') or get_option('metal') or get_option('cuda')
Expand Down Expand Up @@ -137,6 +137,10 @@ if needs_device
install: true,
cpp_args: device_defines,
)

nanoarrow_device_dep = declare_dependency(include_directories: [incdir],
link_with: nanoarrow_device_lib,
dependencies: device_deps)
endif

needs_testing = get_option('testing') or get_option('tests')
Expand Down
1 change: 0 additions & 1 deletion python/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
# specific language governing permissions and limitations
# under the License.

vendor/
src/nanoarrow/_*.c

# Byte-compiled / optimized / DLL files
Expand Down
57 changes: 22 additions & 35 deletions python/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.

import argparse
import pathlib
import re
import subprocess
Expand Down Expand Up @@ -222,15 +223,7 @@ def _write_defs(self, output):
output.write(b"\n")


# Runs cmake -DNANOARROW_BUNDLE=ON if cmake exists or copies nanoarrow.c/h
# from ../dist if it does not. Running cmake is safer because it will sync
# any changes from nanoarrow C library sources in the checkout but is not
# strictly necessary for things like installing from GitHub.
def copy_or_generate_nanoarrow_c():
this_dir = pathlib.Path(__file__).parent.resolve()
source_dir = this_dir.parent
vendor_dir = this_dir / "vendor"

def copy_or_generate_nanoarrow_c(target_dir: pathlib.Path):
vendored_files = [
"nanoarrow.h",
"nanoarrow.c",
Expand All @@ -239,37 +232,25 @@ def copy_or_generate_nanoarrow_c():
"nanoarrow_device.h",
"nanoarrow_device.c",
]
dst = {name: vendor_dir / name for name in vendored_files}

for f in dst.values():
f.unlink(missing_ok=True)
dst = {name: target_dir / name for name in vendored_files}

is_cmake_dir = (source_dir / "CMakeLists.txt").exists()
is_in_nanoarrow_repo = (
is_cmake_dir and (source_dir / "src" / "nanoarrow" / "nanoarrow.h").exists()
)

if not is_in_nanoarrow_repo:
raise ValueError(
"Attempt to build source distribution outside the nanoarrow repo"
)
this_dir = pathlib.Path(__file__).parent.resolve()
arrow_proj_dir = this_dir / "subprojects" / "arrow-nanoarrow"

vendor_dir.mkdir(exist_ok=True)
subprocess.run(
[
sys.executable,
source_dir / "ci" / "scripts" / "bundle.py",
arrow_proj_dir / "ci" / "scripts" / "bundle.py",
"--symbol-namespace",
"PythonPkg",
"--header-namespace",
"",
"--source-output-dir",
vendor_dir,
target_dir,
"--include-output-dir",
vendor_dir,
target_dir,
"--with-device",
"--with-ipc",
"--with-flatcc",
],
)

Expand All @@ -278,18 +259,24 @@ def copy_or_generate_nanoarrow_c():


# Runs the pxd generator with some information about the file name
def generate_nanoarrow_pxds():
this_dir = pathlib.Path(__file__).parent.resolve()

def generate_nanoarrow_pxds(target_dir: pathlib.Path):
NanoarrowPxdGenerator().generate_pxd(
this_dir / "vendor" / "nanoarrow.h", this_dir / "vendor" / "nanoarrow_c.pxd"
target_dir / "nanoarrow.h", target_dir / "nanoarrow_c.pxd"
)
NanoarrowDevicePxdGenerator().generate_pxd(
this_dir / "vendor" / "nanoarrow_device.h",
this_dir / "vendor" / "nanoarrow_device_c.pxd",
target_dir / "nanoarrow_device.h",
target_dir / "nanoarrow_device_c.pxd",
)


if __name__ == "__main__":
copy_or_generate_nanoarrow_c()
generate_nanoarrow_pxds()
parser = argparse.ArgumentParser()
parser.add_argument(
"--output-dir", help="Target directory where files should be written"
)

args = parser.parse_args()
target_dir = pathlib.Path(args.output_dir).resolve()

copy_or_generate_nanoarrow_c(target_dir)
generate_nanoarrow_pxds(target_dir)
59 changes: 59 additions & 0 deletions python/generate_dist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

import os
import pathlib
import shutil


def main():
src_dir = pathlib.Path(os.environ["MESON_SOURCE_ROOT"]).parent.resolve()
dist_dir = pathlib.Path(os.environ["MESON_DIST_ROOT"]).resolve()
subproj_dir = dist_dir / "subprojects" / "arrow-nanoarrow"

if subproj_dir.is_symlink():
subproj_dir.unlink()

subproj_dir.mkdir(parents=True)
shutil.copy(src_dir / "meson.build", subproj_dir / "meson.build")
shutil.copy(src_dir / "meson.options", subproj_dir / "meson.options")

# Copy over any subproject dependency / wrap files
subproj_subproj_dir = subproj_dir / "subprojects"
subproj_subproj_dir.mkdir()
for f in (src_dir / "subprojects").glob("*.wrap"):
shutil.copy(f, subproj_subproj_dir / f.name)
shutil.copytree(
src_dir / "subprojects" / "packagefiles", subproj_subproj_dir / "packagefiles"
)

target_src_dir = subproj_dir / "src"
shutil.copytree(src_dir / "src", target_src_dir)

# CMake isn't actually required for building, but the bundle.py script reads from
# its configuration
shutil.copy(src_dir / "CMakeLists.txt", subproj_dir / "CMakeLists.txt")

subproj_ci_scripts_dir = subproj_dir / "ci" / "scripts"
subproj_ci_scripts_dir.mkdir(parents=True)
shutil.copy(
src_dir / "ci" / "scripts" / "bundle.py", subproj_ci_scripts_dir / "bundle.py"
)


if __name__ == "__main__":
main()
38 changes: 38 additions & 0 deletions python/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

project(
'nanoarrow',
'c', 'cython',
version: run_command(['src/nanoarrow/_version.py', '--print'], check: true).stdout().strip(),
license: 'Apache-2.0',
meson_version: '>=1.2.0',
default_options: [
'warning_level=2',
'c_std=c99',
'default_library=static',
# We need to set these options at the project default_option level
# due to https://github.com/mesonbuild/meson/issues/6728
'arrow-nanoarrow:ipc=true',
'arrow-nanoarrow:device=true',
'arrow-nanoarrow:namespace=PythonPkg',
],
)

subdir('src/nanoarrow')

meson.add_dist_script('python', meson.current_source_dir() / 'generate_dist.py')
12 changes: 10 additions & 2 deletions python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ Changelog = "https://github.com/apache/arrow-nanoarrow/blob/main/CHANGELOG.md"

[build-system]
requires = [
"setuptools >= 61.0.0",
"meson>=1.3.0",
"meson-python",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably need a version constraint here?

"Cython"
]
build-backend = "setuptools.build_meta"
build-backend = "mesonpy"

[tool.meson-python.args]
install = ['--skip-subprojects']
dist = ['--include-subprojects']

[tool.pytest.ini_options]
norecursedirs = "subprojects/arrow-nanoarrow"
Loading
Loading