Skip to content

Commit

Permalink
watcher-py: with meson and cibuildwheel
Browse files Browse the repository at this point in the history
  • Loading branch information
Will committed Jul 14, 2024
1 parent 131c03e commit dc9b159
Show file tree
Hide file tree
Showing 10 changed files with 123 additions and 106 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/watcher-py-wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Watcher Py Wheels

on:
push:
branches: [ release, next ]
pull_request:
branches: [ release, next ]


jobs:
watcher_py_wheels:
# Ref: https://cibuildwheel.pypa.io/en/stable/setup
strategy:
matrix:
# macos-13 is an intel runner, macos-14 is apple silicon
os: [ ubuntu-latest, windows-latest, macos-13, macos-14 ]
name: Build wheels on ${{matrix.os}}
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- uses: pypa/cibuildwheel@v2.19.2
env:
MACOSX_DEPLOYMENT_TARGET: "10.14"
with:
package-dir: .
output-dir: wheelhouse
config-file: pyproject.toml
- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{matrix.os}}-${{strategy.job-index}}
path: wheelhouse/*.whl
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.cache
compile_commands.json
tmp_test_watcher
virtualenv
/out
/result
/watcher
Expand Down
60 changes: 39 additions & 21 deletions libcwatcher/cross-compile.sh
Original file line number Diff line number Diff line change
@@ -1,24 +1,42 @@
#! /usr/bin/env bash
set -e
[ -d "$(dirname "$0")/out" ] || mkdir "$(dirname "$0")/out"
cd "$(dirname "$0")"
linux-cross-compilation-containers/build-containers.sh
[ -f out/meson.build ] || cp meson.build out
[ -d out/src ] || cp -r src out
[ -d out/include ] || cp -r include out
(
cd out
SRC=$PWD
docker run --platform linux/amd64 --rm -v "$SRC:/src" meson-builder-x86_64-unknown-linux-gnu:latest
docker run --platform linux/arm64 --rm -v "$SRC:/src" meson-builder-aarch64-unknown-linux-gnu:latest
docker run --platform linux/arm/v7 --rm -v "$SRC:/src" meson-builder-armv7-unknown-linux-gnueabihf:latest
)
[ "$(uname)" = Darwin ] && {
[ -d out/x86_64-apple-darwin ] || meson setup --cross-file cross-files/x86_64-apple-darwin.txt out/x86_64-apple-darwin
[ -d out/aarch64-apple-darwin ] || meson setup --cross-file cross-files/aarch64-apple-darwin.txt out/aarch64-apple-darwin
meson compile -C out/x86_64-apple-darwin
meson compile -C out/aarch64-apple-darwin
[ "${1:-}" = --clean ] && {
rm -rf "$(dirname "$0")/out"
exit
}
[ "${1:-}" = --show-artifacts ] && {
for pattern in '*.a' '*.so' '*.dylib'
do find "$(dirname "$0")/out" -type f -name "$pattern"
done
exit
}
[ "${1:---build}" = --build ] && {
[ -d "$(dirname "$0")/out" ] || mkdir "$(dirname "$0")/out"
cd "$(dirname "$0")"
linux-cross-compilation-containers/build-containers.sh
[ -f out/meson.build ] || cp meson.build out
[ -d out/src ] || cp -r src out
[ -d out/include ] || cp -r include out
(
cd out
SRC=$PWD
docker run --platform linux/amd64 --rm -v "$SRC:/src" meson-builder-x86_64-unknown-linux-gnu:latest
docker run --platform linux/arm64 --rm -v "$SRC:/src" meson-builder-aarch64-unknown-linux-gnu:latest
docker run --platform linux/arm/v7 --rm -v "$SRC:/src" meson-builder-armv7-unknown-linux-gnueabihf:latest
)
[ "$(uname)" = Darwin ] && {
[ -d out/x86_64-apple-darwin ] || meson setup --cross-file cross-files/x86_64-apple-darwin.txt out/x86_64-apple-darwin
[ -d out/aarch64-apple-darwin ] || meson setup --cross-file cross-files/aarch64-apple-darwin.txt out/aarch64-apple-darwin
meson compile -C out/x86_64-apple-darwin
meson compile -C out/aarch64-apple-darwin
}
echo '-------- Artifacts --------'
for pattern in '*.a' '*.so' '*.dylib'
do find out -type f -name "$pattern" -exec file {} \;
done
echo '~~~~~~~~~~~~~~~~~~~~~~~~~~~'
for pattern in '*.a' '*.so' '*.dylib'
do find out -type f -name "$pattern"
done
echo '---------------------------'
}
for pattern in '*.a' '*.so' '*.dylib'
do find out -type f -name "$pattern" -exec file {} \;
done
35 changes: 9 additions & 26 deletions libcwatcher/meson.build
Original file line number Diff line number Diff line change
@@ -1,45 +1,28 @@
project(
'libcwatcher',
['cpp', 'c'],
version : '0.12.0', # hook: tool/release
default_options : ['c_std=c99', 'cpp_std=c++20'],
)

# I know it's not the convential way to version a shared library...
# I know it's not the convential way to version a library...
# But I'm not sure how to do it the "right" way in Meson.
libname = 'cwatcher-' + meson.project_version()
libcwatcher_name = 'cwatcher-' + meson.project_version()

if target_machine.system() == 'darwin'
deps = dependency(['CoreServices', 'CoreFoundation'])
libcwatcher_deps = [dependency('CoreServices'), dependency('CoreFoundation')]
else
deps = dependency('threads')
libcwatcher_deps = [dependency('threads')]
endif

cwatcher_shared_lib = shared_library(
libname,
['src/watcher-cabi.cpp'],
include_directories : ['include'],
dependencies : deps,
build_rpath : '/usr/local/lib',
install_rpath : '/usr/local/lib',
install : true,
)

cwatcher_static_lib = static_library(
libname,
libcwatcher = library(
libcwatcher_name,
['src/watcher-cabi.cpp'],
include_directories : ['include'],
dependencies : deps,
dependencies : libcwatcher_deps,
build_rpath : '/usr/local/lib',
install_rpath : '/usr/local/lib',
install : true,
)

executable(
test_libcwatcher = executable(
'test-watcher-cabi',
['src/test-watcher-cabi.c'],
include_directories : ['include'],
link_with : [cwatcher_shared_lib],
link_with : [libcwatcher],
build_rpath : '/usr/local/lib',
install_rpath : '/usr/local/lib',
install : false,
Expand Down
8 changes: 8 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
project(
'watcher',
['cpp', 'c'],
version : '0.12.0', # hook: tool/release
default_options : ['c_std=c99', 'cpp_std=c++20'],
)
subdir('libcwatcher')
subdir('watcher-py')
20 changes: 20 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[build-system]
build-backend = "mesonpy"
requires = ["meson >= 1.0.0", "meson-python >= 0.14.0"]

[project]
name = "watcher"
version = "0.12.0"
authors = [{name = "Will"}]
homepage = "https://github.com/e-dant/watcher"
description = "Filesystem watcher. Works anywhere. Simple, efficient, and friendly."
license.text = "MIT"
keywords = [ "watcher", "filesystem", "events", "async" ]
packages = [{include = "watcher"}]

[tool.cibuildwheel]
free-threaded-support = true
manylinux-x86_64-image = "manylinux2014"
manylinux-i686-image = "manylinux2014"
manylinux-pypy_x86_64-image = "manylinux2014"
manylinux-pypy_i686-image = "manylinux2014"
29 changes: 0 additions & 29 deletions watcher-py/build.py

This file was deleted.

2 changes: 2 additions & 0 deletions watcher-py/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
py = import('python').find_installation()
py.install_sources(['watcher/__init__.py', 'watcher/watcher.py'])
21 changes: 0 additions & 21 deletions watcher-py/pyproject.toml

This file was deleted.

22 changes: 13 additions & 9 deletions watcher-py/watcher/watcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class _CEvent(ctypes.Structure):


def _lazy_static_solib_handle() -> ctypes.CDLL:
def so_file_ending():
def native_solib_file_ending():
match os.uname().sysname:
case "Darwin":
return "dylib"
Expand All @@ -33,15 +33,19 @@ def so_file_ending():
case _:
return "so"

def libcwatcher_path():
def libcwatcher_lib_path():
version = "0.12.0" # hook: tool/release
libname = f"libcwatcher-{version}.{so_file_ending()}"
heredir = os.path.dirname(os.path.abspath(__file__))
return os.path.join(heredir, "lib", libname)
dir_path = os.path.join(heredir, ".watcher.mesonpy.libs")
lib_name = f"libcwatcher-{version}.{native_solib_file_ending()}"
lib_path = os.path.join(dir_path, lib_name)
if not os.path.exists(lib_path):
raise RuntimeError(f"Could not find '{lib_path}', did the install dir change?")
return lib_path

global _LIB
if _LIB is None:
_LIB = ctypes.CDLL(libcwatcher_path())
_LIB = ctypes.CDLL(libcwatcher_lib_path())
_LIB.wtr_watcher_open.argtypes = [ctypes.c_char_p, _CCallback, ctypes.c_void_p]
_LIB.wtr_watcher_open.restype = ctypes.c_void_p
_LIB.wtr_watcher_close.argtypes = [ctypes.c_void_p]
Expand Down Expand Up @@ -98,8 +102,9 @@ class Event:

class Watch:
def __init__(self, path: str, callback: Callable[[Event], None]):
def callback_bridge(event, _):
callback(_c_event_to_event(event))
def callback_bridge(c_event: _CEvent, _) -> None:
py_event = _c_event_to_event(c_event)
callback(py_event)

self._lib = _lazy_static_solib_handle()
self._path = path.encode("utf-8")
Expand All @@ -113,8 +118,7 @@ def callback_bridge(event, _):

def close(self):
if self._watcher:
if not self._lib.wtr_watcher_close(self._watcher):
raise RuntimeError("Internal error while closing a watcher")
self._lib.wtr_watcher_close(self._watcher)
self._watcher = None

def __del__(self):
Expand Down

0 comments on commit dc9b159

Please sign in to comment.