From 412b076763592ebb77a04c570185cbfc6ae07b72 Mon Sep 17 00:00:00 2001 From: David Huggins-Daines Date: Thu, 1 Feb 2024 00:00:55 +0000 Subject: [PATCH 1/4] fix: switch to scikit-build-core for python 3.12 compat --- CMakeLists.txt | 4 +-- py/CMakeLists.txt | 23 ++++++++----- pyproject.toml | 86 ++++++++++++++++++++++++++++++++++++----------- setup.cfg | 24 ------------- setup.py | 13 ------- 5 files changed, 82 insertions(+), 68 deletions(-) delete mode 100644 setup.cfg delete mode 100644 setup.py diff --git a/CMakeLists.txt b/CMakeLists.txt index bccca9c..1191007 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ -cmake_minimum_required(VERSION 3.14) # I like pie +cmake_minimum_required(VERSION 3.15) include(CheckTypeSize) include(CheckSymbolExists) include(CheckLibraryExists) include(TestBigEndian) -project(soundswallower VERSION 0.6.0 +project(soundswallower VERSION 0.6.1 DESCRIPTION "An even smaller speech recognizer") if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) diff --git a/py/CMakeLists.txt b/py/CMakeLists.txt index 63e9c78..5cbd6ef 100644 --- a/py/CMakeLists.txt +++ b/py/CMakeLists.txt @@ -1,18 +1,23 @@ -find_package(PythonExtensions REQUIRED) -find_package(Python COMPONENTS Interpreter Development) -find_package(Cython) +find_package(Python COMPONENTS Interpreter Development.Module REQUIRED) +find_program(CYTHON "cython") set_property(TARGET soundswallower PROPERTY POSITION_INDEPENDENT_CODE on) -add_cython_target(_soundswallower _soundswallower.pyx) -add_library(_soundswallower MODULE ${_soundswallower}) -target_link_libraries(_soundswallower soundswallower) +add_custom_command( + OUTPUT _soundswallower.c + DEPENDS _soundswallower.pyx + VERBATIM + COMMAND "${CYTHON}" "${CMAKE_CURRENT_SOURCE_DIR}/_soundswallower.pyx" + --output-file "${CMAKE_CURRENT_BINARY_DIR}/_soundswallower.c") + +python_add_library(_soundswallower MODULE + "${CMAKE_CURRENT_BINARY_DIR}/_soundswallower.c" WITH_SOABI) +target_link_libraries(_soundswallower PRIVATE soundswallower) target_include_directories( _soundswallower PRIVATE ${PYTHON_INCLUDE_DIR} _soundswallower PRIVATE ${PROJECT_SOURCE_DIR}/src _soundswallower PRIVATE ${PROJECT_SOURCE_DIR}/include _soundswallower PRIVATE ${CMAKE_BINARY_DIR} # for config.h ) -python_extension_module(_soundswallower) -install(TARGETS _soundswallower LIBRARY DESTINATION py/soundswallower) -install(DIRECTORY ${PROJECT_SOURCE_DIR}/model DESTINATION py/soundswallower) +install(TARGETS _soundswallower LIBRARY DESTINATION soundswallower) +install(DIRECTORY ${PROJECT_SOURCE_DIR}/model DESTINATION soundswallower) diff --git a/pyproject.toml b/pyproject.toml index bc87400..c2cf532 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,26 +1,72 @@ [build-system] requires = [ - "setuptools>=45,<64", - "wheel", - "scikit-build~=0.15", - "cmake", - "Cython", - "ninja" + "scikit-build-core", + "Cython" ] -build-backend = "setuptools.build_meta" +build-backend = "scikit_build_core.build" + +[project] +name = "soundswallower" +version = "0.6.1" +description = "An even smaller speech recognizer" +readme = "README.md" +authors = [ + {name = "David Huggins-Daines", email = "dhd@ecolingui.ca"} +] +keywords = ["asr", "speech"] +classifiers = [ + "Development Status :: 3 - Alpha", + "Programming Language :: C", + "Programming Language :: Cython", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Topic :: Multimedia :: Sound/Audio :: Speech", +] + +[project.urls] +Homepage = "https://github.com/ReadAlongs/SoundSwallower" +Documentation = "https://soundswallower.readthedocs.io/" +Repository = "https://github.com/ReadAlongs/SoundSwallower.git" +Issues = "https://github.com/ReadAlongs/SoundSwallower/issues" + +[project.scripts] +soundswallower = "soundswallower.cli:main" + [tool.cibuildwheel] -# Build the versions found in Ubuntu LTS, the stable PyPy, Anaconda on Windows -# ...and some other versions we want for Windows +# Build a reduced selection of binaries as there are tons of them build = [ - "pp38*", - "cp36-manylinux_*", - "cp38-manylinux_*", - "cp37-win*", - "cp38-win*", - "cp39-win*", - "cp310-*" + "pp310*", + "cp38-*", + "cp310-*", + "cp311-*", + "cp312-*", +] +# Build only universal wheels for Mac where possible, and skip 32-bit +# builds to avoid building a gigabyte of stuff all the time +skip = [ + "cp*-macosx_x86_64", + "cp*-macosx_arm64", + "*_i686", + "*-win32", ] -# PyPy 3.8 will choke on CPython 3.8 build leftovers... -before-build = "rm -rf _skbuild" -# PyPy builds are broken on Windows, and skip 32-bit and musl -skip = ["*musl*", "*_i686", "*-win32", "pp*win*"] + +[tool.cibuildwheel.macos] +archs = ["x86_64", "universal2", "arm64"] + +[tool.isort] +profile = "black" + +[tool.flake8] +extend-ignore = "E203" +max-line-length = "88" + +[tool.scikit-build] +cmake.verbose = true +logging.level = "INFO" +wheel.packages = ["py/soundswallower"] diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 2a29301..0000000 --- a/setup.cfg +++ /dev/null @@ -1,24 +0,0 @@ -[metadata] -name = soundswallower -version = 0.6.0 -description = An even smaller speech recognizer -long_description = file: README.md -long_description_content_type = text/markdown -author = David Huggins-Daines -author_email = dhdaines@gmail.com -license = MIT -platforms = any -url = https://github.com/ReadAlongs/SoundSwallower -project_urls = - Documentation = https://soundswallower.readthedocs.io/ - Tracker = https://github.com/ReadAlongs/SoundSwallower/issues -keywords = asr, speech -classifiers = - Development Status :: 3 - Alpha - Programming Language :: C - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.7 - License :: OSI Approved :: MIT License - Operating System :: OS Independent - Natural Language :: English - Natural Language :: French diff --git a/setup.py b/setup.py deleted file mode 100644 index eb8566e..0000000 --- a/setup.py +++ /dev/null @@ -1,13 +0,0 @@ -from setuptools import find_packages -from skbuild import setup - -setup( - packages=find_packages("py", exclude=["test"]), - package_dir={"": "py"}, - package_data={"soundswallower": ["py.typed", "_soundswallower.pyi"]}, - entry_points={ - "console_scripts": [ - "soundswallower = soundswallower.cli:main", - ], - }, -) From bbc934f52702dff7bcafaa427679398e31c39749 Mon Sep 17 00:00:00 2001 From: David Huggins-Daines Date: Thu, 1 Feb 2024 00:02:42 +0000 Subject: [PATCH 2/4] feat: update cibuildwheel --- .github/workflows/build_wheels.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index 3c4463c..05b11db 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -4,6 +4,8 @@ on: push: branches: - master + workflow_dispatch: + jobs: build_sdist: name: Build source distribution @@ -23,13 +25,13 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, windows-2019, macos-11] + os: [ubuntu-latest, windows-latest, macos-latest] steps: - uses: actions/checkout@v3 - name: Build wheels - uses: pypa/cibuildwheel@v2.8.1 + uses: pypa/cibuildwheel@v2.16.5 - uses: actions/upload-artifact@v3 with: From 3863c7bd4c17c7fb1b9117cd51f4b11ee786ccca Mon Sep 17 00:00:00 2001 From: David Huggins-Daines Date: Thu, 1 Feb 2024 00:31:31 +0000 Subject: [PATCH 3/4] tests: fix hash tests --- tests/_hash_delete1.res | 8 ++++---- tests/_hash_delete2.res | 10 +++++----- tests/_hash_delete3.res | 10 +++++----- tests/_hash_delete4.res | 10 +++++----- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/_hash_delete1.res b/tests/_hash_delete1.res index 1fb4237..12b0fd5 100644 --- a/tests/_hash_delete1.res +++ b/tests/_hash_delete1.res @@ -1,6 +1,6 @@ Hash with chaining representation of the hash table -|key:-bla|len:4|val=8|->NULL -|key:-hmmdump|len:8|val=1|->|key:-subvq|len:6|val=7|->|key:-outlatdir|len:10|val=3|->NULL -|key:-svq4svq|len:8|val=2|->|key:-lminmemory|len:11|val=6|->NULL -|key:-beam|len:5|val=5|->NULL +|key:-bla|len:4|val=0x8|->NULL +|key:-hmmdump|len:8|val=0x1|->|key:-subvq|len:6|val=0x7|->|key:-outlatdir|len:10|val=0x3|->NULL +|key:-svq4svq|len:8|val=0x2|->|key:-lminmemory|len:11|val=0x6|->NULL +|key:-beam|len:5|val=0x5|->NULL The total number of keys =7 diff --git a/tests/_hash_delete2.res b/tests/_hash_delete2.res index 5f8151a..4962776 100644 --- a/tests/_hash_delete2.res +++ b/tests/_hash_delete2.res @@ -1,7 +1,7 @@ Hash with chaining representation of the hash table -|key:-bla|len:4|val=8|->NULL -|key:-hmmdump|len:8|val=1|->|key:-outlatdir|len:10|val=3|->NULL -|key:-svq4svq|len:8|val=2|->|key:-lminmemory|len:11|val=6|->NULL -|key:-lm|len:3|val=4|->NULL -|key:-beam|len:5|val=5|->NULL +|key:-bla|len:4|val=0x8|->NULL +|key:-hmmdump|len:8|val=0x1|->|key:-outlatdir|len:10|val=0x3|->NULL +|key:-svq4svq|len:8|val=0x2|->|key:-lminmemory|len:11|val=0x6|->NULL +|key:-lm|len:3|val=0x4|->NULL +|key:-beam|len:5|val=0x5|->NULL The total number of keys =7 diff --git a/tests/_hash_delete3.res b/tests/_hash_delete3.res index 949300e..e9e5d8a 100644 --- a/tests/_hash_delete3.res +++ b/tests/_hash_delete3.res @@ -1,7 +1,7 @@ Hash with chaining representation of the hash table -|key:-bla|len:4|val=8|->NULL -|key:-hmmdump|len:8|val=1|->|key:-subvq|len:6|val=7|->|key:-outlatdir|len:10|val=3|->NULL -|key:-lminmemory|len:11|val=6|->NULL -|key:-lm|len:3|val=4|->NULL -|key:-beam|len:5|val=5|->NULL +|key:-bla|len:4|val=0x8|->NULL +|key:-hmmdump|len:8|val=0x1|->|key:-subvq|len:6|val=0x7|->|key:-outlatdir|len:10|val=0x3|->NULL +|key:-lminmemory|len:11|val=0x6|->NULL +|key:-lm|len:3|val=0x4|->NULL +|key:-beam|len:5|val=0x5|->NULL The total number of keys =7 diff --git a/tests/_hash_delete4.res b/tests/_hash_delete4.res index 5ee8c03..4f6de02 100644 --- a/tests/_hash_delete4.res +++ b/tests/_hash_delete4.res @@ -1,7 +1,7 @@ Hash with chaining representation of the hash table -|key:-bla|len:4|val=8|->NULL -|key:-subvq|len:6|val=7|->|key:-outlatdir|len:10|val=3|->NULL -|key:-svq4svq|len:8|val=2|->|key:-lminmemory|len:11|val=6|->NULL -|key:-lm|len:3|val=4|->NULL -|key:-beam|len:5|val=5|->NULL +|key:-bla|len:4|val=0x8|->NULL +|key:-subvq|len:6|val=0x7|->|key:-outlatdir|len:10|val=0x3|->NULL +|key:-svq4svq|len:8|val=0x2|->|key:-lminmemory|len:11|val=0x6|->NULL +|key:-lm|len:3|val=0x4|->NULL +|key:-beam|len:5|val=0x5|->NULL The total number of keys =7 From 692feae693d4620df87b4b29ce09a0f506f51a05 Mon Sep 17 00:00:00 2001 From: David Huggins-Daines Date: Thu, 1 Feb 2024 00:57:23 +0000 Subject: [PATCH 4/4] fix: emscripten gratuitously changing things again --- js/api.js | 24 ++++++++++++------------ js/library_funcs.txt | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/js/api.js b/js/api.js index 1d20437..545e642 100644 --- a/js/api.js +++ b/js/api.js @@ -29,7 +29,7 @@ class Decoder { if (config === undefined) config = {}; if (Module.defaultModel !== null && config.hmm === undefined) config.hmm = Module.get_model_path(Module.defaultModel); - const cjson = allocateUTF8(JSON.stringify(config)); + const cjson = stringToNewUTF8(JSON.stringify(config)); const cconfig = Module._config_parse_json(0, cjson); Module._free(cjson); this.cdecoder = Module._decoder_create(cconfig); @@ -57,7 +57,7 @@ class Decoder { * @throws {ReferenceError} Throws ReferenceError if key is not a known parameter. */ set_config(key, val) { - const ckey = allocateUTF8(key); + const ckey = stringToNewUTF8(key); const cconfig = Module._decoder_config(this.cdecoder); const type = Module._config_typeof(cconfig, ckey); if (type == 0) { @@ -65,7 +65,7 @@ class Decoder { throw new ReferenceError(`Unknown configuration parameter ${key}`); } if (type & ARG_STRING) { - const cval = allocateUTF8(val); + const cval = stringToNewUTF8(val); Module._config_set_str(cconfig, ckey, cval); Module._free(cval); } else if (type & ARG_FLOATING) { @@ -85,7 +85,7 @@ class Decoder { * @throws {ReferenceError} Throws ReferenceError if key is not a known parameter. */ unset_config(key) { - const ckey = allocateUTF8(key); + const ckey = stringToNewUTF8(key); const cconfig = Module._decoder_config(this.cdecoder); const type = Module._config_typeof(cconfig, ckey); if (type == 0) { @@ -102,7 +102,7 @@ class Decoder { * @throws {ReferenceError} Throws ReferenceError if key is not a known parameter. */ get_config(key) { - const ckey = allocateUTF8(key); + const ckey = stringToNewUTF8(key); const cconfig = Module._decoder_config(this.cdecoder); const type = Module._config_typeof(cconfig, ckey); if (type == 0) { @@ -131,7 +131,7 @@ class Decoder { * @param {string} key Key whose existence to check. */ has_config(key) { - const ckey = allocateUTF8(key); + const ckey = stringToNewUTF8(key); const cconfig = Module._decoder_config(this.cdecoder); const rv = Module._config_typeof(cconfig, ckey) != 0; Module._free(ckey); @@ -415,7 +415,7 @@ class Decoder { */ lookup_word(word) { this.assert_initialized(); - const cword = allocateUTF8(word); + const cword = stringToNewUTF8(word); const cpron = Module._decoder_lookup_word(this.cdecoder, cword); Module._free(cword); if (cpron == 0) return null; @@ -441,8 +441,8 @@ class Decoder { throw new Error( `Word at position ${i} has missing text or pronunciation` ); - const ctext = allocateUTF8(text); - const cpron = allocateUTF8(pron); + const ctext = stringToNewUTF8(text); + const cpron = stringToNewUTF8(pron); const update = i == words.length - 1; const wid = Module._decoder_add_word(this.cdecoder, ctext, cpron, update); Module._free(ctext); @@ -463,13 +463,13 @@ class Decoder { const logmath = Module._decoder_logmath(this.cdecoder); const config = Module._decoder_config(this.cdecoder); const lw = this.get_config("lw"); - const cjsgf = allocateUTF8(jsgf_string); + const cjsgf = stringToNewUTF8(jsgf_string); const jsgf = Module._jsgf_parse_string(cjsgf, 0); Module._free(cjsgf); if (jsgf == 0) throw new Error("Failed to parse JSGF"); let rule; if (toprule !== null) { - const crule = allocateUTF8(toprule); + const crule = stringToNewUTF8(toprule); rule = Module._jsgf_get_rule(jsgf, crule); Module._free(crule); if (rule == 0) throw new Error("Failed to find top rule " + toprule); @@ -490,7 +490,7 @@ class Decoder { */ set_align_text(text) { this.assert_initialized(); - const ctext = allocateUTF8(text); + const ctext = stringToNewUTF8(text); const rv = Module._decoder_set_align_text(this.cdecoder, ctext); Module._free(ctext); if (rv < 0) throw new Error("Failed to set alignment text"); diff --git a/js/library_funcs.txt b/js/library_funcs.txt index 2410bdf..3332ab7 100644 --- a/js/library_funcs.txt +++ b/js/library_funcs.txt @@ -1,2 +1,2 @@ -$allocateUTF8 +$stringToNewUTF8 $ccall