diff --git a/.github/workflows/build-wheel-linux.yml b/.github/workflows/build-wheel-linux.yml new file mode 100644 index 00000000..92fce300 --- /dev/null +++ b/.github/workflows/build-wheel-linux.yml @@ -0,0 +1,46 @@ +# (C) Copyright 2024- ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. + + +name: Build Python Wheel for Linux + +on: + # Trigger the workflow manually + workflow_dispatch: ~ + + # Allow to be called from another workflow + workflow_call: ~ + + # TODO automation trigger + +jobs: + build: + name: Build manylinux_2_28 + runs-on: [self-hosted, Linux, platform-builder-Rocky-8.6] + # TODO which manylinux do we want to build for? 2014? 2_28? 2_34? Matrix? + container: + image: eccr.ecmwf.int/wheelmaker/2_28:latest + credentials: + username: ${{ secrets.ECMWF_DOCKER_REGISTRY_USERNAME }} + password: ${{ secrets.ECMWF_DOCKER_REGISTRY_ACCESS_TOKEN }} + steps: + # TODO convert this to be matrix-friendly. Note it's a bit tricky since + # we'd ideally not reexecute the compile step multiple times, but it + # (non-essentially) depends on a matrix-based step + # NOTE we dont use action checkout because it doesnt cleanup after itself correctly + - run: git clone --depth=1 --branch="${GITHUB_REF#refs/heads/}" https://github.com/$GITHUB_REPOSITORY /proj + - run: cd /proj && /buildscripts/prepare_deps.sh ./python_wrapper/buildconfig 3.11 + - run: cd /proj && /buildscripts/compile.sh ./python_wrapper/buildconfig + - run: cd /proj && PYTHONPATH=/buildscripts /buildscripts/wheel-linux.sh ./python_wrapper/buildconfig 3.11 + - run: cd /proj && /buildscripts/test-wheel.sh ./python_wrapper/buildconfig 3.11 /tmp/build/wheel/*whl + - run: cd /proj && /buildscripts/upload-pypi.sh /tmp/build/wheel/*whl + env: + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + # NOTE temporary thing until all the mess gets cleared + - run: rm -rf ./* ./.git ./.github diff --git a/.gitignore b/.gitignore index e4cea70b..350c3457 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,7 @@ doc/latex .*un~ *.ccls-cache share +__pycache__/ +*.pyc +*.egg-info/ + diff --git a/python_interface/README.md b/python_interface/README.md new file mode 100644 index 00000000..e349a5da --- /dev/null +++ b/python_interface/README.md @@ -0,0 +1,7 @@ +This is just a placeholder for proper python interface of metkit -- for now we just showcase `findlibs`-based finding of `.so`, and loading via cffi. + +To demonstrate functionality, install `eckit` and `metkit` binary wheels in your venv, and then you can `pip install -e . && python -c 'import metkit; metkit.version()`. + +To be done: +1. proper cffi setup +2. wheel building (note this is **not** a binary wheel! That happens in `../python_wrapper`, and contains no python code) diff --git a/python_interface/pyproject.toml b/python_interface/pyproject.toml new file mode 100644 index 00000000..d109e433 --- /dev/null +++ b/python_interface/pyproject.toml @@ -0,0 +1,8 @@ +[build-system] +requires = ["setuptools >= 61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "metkit" +version = "0.0.0" +dependencies = ["cffi", "findlibs", "metkitlib"] diff --git a/python_interface/src/metkit/__init__.py b/python_interface/src/metkit/__init__.py new file mode 100644 index 00000000..dceae240 --- /dev/null +++ b/python_interface/src/metkit/__init__.py @@ -0,0 +1,18 @@ +import cffi +import findlibs + +_lib = None + +# TODO expose the full functionality + +def _get_lib(): + global _lib + if _lib is None: + ffi = cffi.FFI() + ffi.cdef("unsigned int metkit_version_int();") + loc = findlibs.find("metkit", "metkitlib") + _lib = ffi.dlopen(loc) + return _lib + +def metkit_version_int() -> int: + return _get_lib().metkit_version_int() diff --git a/python_wrapper/buildconfig b/python_wrapper/buildconfig new file mode 100644 index 00000000..30eb14e3 --- /dev/null +++ b/python_wrapper/buildconfig @@ -0,0 +1,16 @@ +# (C) Copyright 2024- ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. + +# to be source'd by wheelmaker's compile.sh *and* wheel-linux.sh +# NOTE replace the whole thing with pyproject.toml? Less powerful, and quaint to use for sourcing ecbuild invocation +# TODO we duplicate information -- pyproject.toml's `name` and `packages` are derivable from $NAME and must stay consistent + +NAME="metkit" +CMAKE_PARAMS="-DECKIT_PATH=/tmp/prereqs/eckitlib" +PYPROJECT_DIR="python_wrapper" +DEPENDENCIES='["eckitlib"]' diff --git a/python_wrapper/setup.cfg b/python_wrapper/setup.cfg new file mode 100644 index 00000000..3826781a --- /dev/null +++ b/python_wrapper/setup.cfg @@ -0,0 +1,5 @@ +[metadata] +description = "metkitlib" +long_description = file: README.md +long_description_content_type = text/markdown +author = file: AUTHORS diff --git a/python_wrapper/setup.py b/python_wrapper/setup.py new file mode 100644 index 00000000..c64ad6d7 --- /dev/null +++ b/python_wrapper/setup.py @@ -0,0 +1,2 @@ +from setup_utils import plain_setup +plain_setup()