diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..081a5a8 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,88 @@ +# This file is autogenerated by maturin v1.7.4 +# To update, run +# +# maturin generate-ci github --platform linux --platform macos +# +# manual edits: +# - to limit the number of ubuntu variants +# - do the rust build step +# - to add the RUSTFLAGS environment variable +# - to specify python version used by maturin + +name: CI + +on: + push: + branches: + - master + pull_request: + workflow_call: + +permissions: + contents: read + +jobs: + linux: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + platform: + - runner: ubuntu-22.04 + target: x86_64 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-python@v5 + - name: Build bindings + run: | + tools/build.sh + - name: Build wheels + uses: PyO3/maturin-action@v1 + env: + RUSTFLAGS: -L espeak-ng/src/.libs + with: + target: ${{ matrix.platform.target }} + # only CPython and PyPy (which fail) so specify the full path to the CPythons + args: --release --out dist --interpreter /usr/local/bin/python3.9 --interpreter /usr/local/bin/python3.11 + sccache: 'true' + manylinux: auto + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-linux-${{ matrix.platform.target }} + path: dist + + macos: + runs-on: ${{ matrix.platform.runner }} + strategy: + matrix: + # Fix up the python versions that maturin detects, as some break + platform: + - runner: macos-13 + target: x86_64 + python_args: --interpreter /Users/runner/hostedtoolcache/Python/3.9.20/x64/bin/python3.9 --interpreter /usr/local/bin/python3.11 + - runner: macos-14 + target: aarch64 + python_args: --interpreter python3.9 --interpreter python3.11 + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - uses: actions/setup-python@v5 + - name: Build bindings + run: | + tools/build.sh + - name: Build wheels + uses: PyO3/maturin-action@v1 + env: + RUSTFLAGS: -L espeak-ng/src/.libs + with: + target: ${{ matrix.platform.target }} + args: --release --out dist ${{ matrix.platform.python_args }} + sccache: 'true' + - name: Upload wheels + uses: actions/upload-artifact@v4 + with: + name: wheels-macos-${{ matrix.platform.target }} + path: dist diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..fc5944e --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,31 @@ +name: Publish Wheels + +on: + release: + types: [published] + +permissions: + contents: read + +jobs: + run-build-workflow: + uses: ./.github/workflows/build.yml + + pypi-publish: + name: Publish to PyPi + needs: run-build-workflow + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + pattern: wheels-* + merge-multiple: true + path: dist/ + - name: List artifacts downloaded + run: ls -R dist + - name: Publish package + uses: pypa/gh-action-pypi-publish@release/v1.8 diff --git a/README.md b/README.md index 14ca2db..d072cf7 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,9 @@ Currently, this only provides text phonemization functions, not invoking full TT On Linux, espeak is statically linked into the built wheel, but there is a runtime dependency on espeak-ng-data. This can be satisfied by `sudo apt install espeak-ng-data` (or the equivalent for your distro). -On Mac the data and necessary shared library can be installed with `brew tap bplevin36/espeak-ng && brew install espeak-ng --without-pcaudiolib --without-waywardgeek-sonic`. You will need to have XCode tools and GNU autotools installed (if they aren't already). +On Mac the data and necessary shared library can be installed with `brew tap bplevin36/espeak-ng && brew install bplevin36/espeak-ng/espeak-ng --without-pcaudiolib --without-waywardgeek-sonic`. You will need to have XCode tools and GNU autotools installed (if they aren't already). + +On macOS under ARM you will need to set `export DYLD_FALLBACK_LIBRARY_PATH=/opt/homebrew/lib` for the example to work, due to a failure at import to find the dynamic link as ARM homebrew lib directories aren't in the standard search path. ## Usage Example ``` @@ -26,6 +28,7 @@ On Mac the data and necessary shared library can be installed with `brew tap bpl ## Building Requires Rust (and cargo) as well as GNU autotools and python packages [`maturin`](https://github.com/PyO3/maturin) and `twine` +On Mac GNU autotools can be installed with `brew install libtool automake autoconf` 1. Clone (including submodules) 2. Build espeak-ng in-tree with: @@ -39,3 +42,5 @@ Requires Rust (and cargo) as well as GNU autotools and python packages [`maturin 3. Build wheels with `RUSTFLAGS='-L espeak-ng/src/.libs' maturin build --release` (on Linux this requires the [maturin docker container](https://hub.docker.com/r/konstin2/maturin)) 4. Install to local python with `pip install target/wheels/.whl` 5. Publish to PyPi using `twine` + +tools/build.sh will automate 1-3 for you if you have the correct tools configured, it is designed to work in a GitHub Action. \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index f1c43e4..d316afe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["maturin>=0.10,<0.11"] +requires = ["maturin>=1,<2"] build-backend = "maturin" [project] diff --git a/src/lib.rs b/src/lib.rs index 0c1e914..01db6e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,8 @@ fn ensure_initialized() -> PyResult<()> { } let try_paths = [ "/usr/lib/x86_64-linux-gnu/espeak-ng-data", // linux apt install location - "/usr/local/Cellar/espeak-ng/1.50/share/espeak-ng-data", // mac brew install location + "/opt/homebrew/Cellar/espeak-ng/1.50/share/espeak-ng-data", // mac ARM brew install location + "/usr/local/Cellar/espeak-ng/1.50/share/espeak-ng-data", // mac x64 brew install location "/usr/local/share/espeak-ng-data", // source install locations "/usr/share/espeak-ng-data", ]; @@ -50,7 +51,7 @@ fn ensure_initialized() -> PyResult<()> { #[cfg(target_os = "macos")] let msg = r#"Error while initializing espeak. If it's not installed, try running: - `brew install anarchivist/espeak-ng/espeak-ng --without-pcaudiolib --without-waywardgeek-sonic`"#; + `brew tap bplevin36/espeak-ng && brew install bplevin36/espeak-ng/espeak-ng --without-pcaudiolib --without-waywardgeek-sonic`"#; #[cfg(target_os = "linux")] let msg = r#"Error while initializing espeak. If you haven't installed the data files, run: `sudo apt install espeak-ng-data`"#; diff --git a/tools/build.sh b/tools/build.sh new file mode 100755 index 0000000..b6bae24 --- /dev/null +++ b/tools/build.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e +SCRIPT_DIR=$(cd $(dirname $0); pwd) +PARENT_DIR=$(dirname $SCRIPT_DIR) + +echo $PARENT_DIR +cd $PARENT_DIR/espeak-ng +if [[ "$(uname)" == "Darwin" ]]; then + brew install automake libtool autoconf + rm CHANGELOG.md + echo "Changelog dummy" > ChangeLog.md +fi +ls + +# Fix error on Ubuntu 22.04+ +# See https://stackoverflow.com/questions/76060903/gcc-multiple-definition-of-error-on-ubuntu-22-04-after-updating-from-ubuntu-2 +export CFLAGS="-fcommon" + +./autogen.sh +./configure --without-klatt --without-pcaudiolib --without-mbrola --without-sonic --without-async +make