From a701e0c296578803b8beb4ea5c8d462c8c4921a7 Mon Sep 17 00:00:00 2001 From: skyler14 Date: Tue, 22 Jul 2025 16:59:28 -0700 Subject: [PATCH 1/3] adjust CMake to support installing via Apple Silicon --- CMakeLists.txt | 28 +++++++++++++++++++++++----- requirements.txt | 4 ++-- setup.py | 31 +++++++++++++++++++++++++------ 3 files changed, 50 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f86869..d88b9fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.18) project(SymSpellCppPy) set(CMAKE_CXX_STANDARD 14) @@ -6,6 +6,12 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS ON) set(CMAKE_BUILD_TYPE "Release") +# Apple Silicon specific optimizations +if(APPLE AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") + set(CMAKE_OSX_ARCHITECTURES "arm64") + message(STATUS "Detected Apple Silicon, enabling arm64 optimizations") +endif() + option(BUILD_FOR_PYTHON "Build for Python" OFF) option(BUILD_FOR_TEST "Build Tests" ON) @@ -16,17 +22,29 @@ if (BUILD_FOR_PYTHON) set(CMAKE_BUILD_TYPE "Release") Include(FetchContent) + # Use newer pybind11 version with better CMake support FetchContent_Declare( pybind11 GIT_REPOSITORY https://github.com/pybind/pybind11.git - GIT_TAG v2.10.4) + GIT_TAG v2.11.1) FetchContent_MakeAvailable(pybind11) pybind11_add_module(SymSpellCppPy MODULE SymSpellCppPy.cpp) target_sources(SymSpellCppPy PRIVATE library.cpp library.h) target_link_libraries(SymSpellCppPy PRIVATE SymSpellCpp) - target_compile_options(SymSpellCppPy PRIVATE - $<$:-O3 -DNDEBUG -march=native -mtune=native -fvisibility=hidden - -flto -ffat-lto-objects>) + + # Platform-specific compile options + if(APPLE AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") + # Apple Silicon optimizations + target_compile_options(SymSpellCppPy PRIVATE + $<$:-O3 -DNDEBUG -mcpu=apple-m1 -fvisibility=hidden + -flto -ffat-lto-objects>) + else() + # Standard x86_64 optimizations + target_compile_options(SymSpellCppPy PRIVATE + $<$:-O3 -DNDEBUG -march=native -mtune=native -fvisibility=hidden + -flto -ffat-lto-objects>) + endif() + message(STATUS "Build for Python = " ${BUILD_FOR_PYTHON}) else () Include(FetchContent) diff --git a/requirements.txt b/requirements.txt index 9ce6a53..d5478dc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -setuptools -pybind11 +setuptools>=40.6.0 +pybind11>=2.11.0 recommonmark sphinx_rtd_theme \ No newline at end of file diff --git a/setup.py b/setup.py index 1a1a0f9..57ccfb4 100644 --- a/setup.py +++ b/setup.py @@ -32,10 +32,15 @@ def run(self): raise RuntimeError("CMake must be installed to build the following extensions: " + ", ".join(e.name for e in self.extensions)) + cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1)) + if platform.system() == "Windows": - cmake_version = LooseVersion(re.search(r'version\s*([\d.]+)', out.decode()).group(1)) if cmake_version < '3.1.0': raise RuntimeError("CMake >= 3.1.0 is required on Windows") + else: + if cmake_version < '3.18.0': + raise RuntimeError("CMake >= 3.18.0 is required for Apple Silicon support. " + "Please update CMake: brew install cmake") for ext in self.extensions: self.build_extension(ext) @@ -58,6 +63,10 @@ def build_extension(self, ext): cmake_args += ["-DCMAKE_BUILD_WITH_INSTALL_RPATH=TRUE"] cmake_args += ["-DCMAKE_INSTALL_RPATH={}".format("$ORIGIN")] + # Apple Silicon specific settings + if platform.system() == "Darwin" and platform.machine() == "arm64": + cmake_args += ["-DCMAKE_OSX_ARCHITECTURES=arm64"] + if platform.system() == "Windows": cmake_args += ['-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{}={}'.format(cfg.upper(), extdir)] if sys.maxsize > 2 ** 32: @@ -70,6 +79,11 @@ def build_extension(self, ext): env = os.environ.copy() env['CXXFLAGS'] = '{} -DVERSION_INFO=\\"{}\\"'.format(env.get('CXXFLAGS', ''), self.distribution.get_version()) + + # Add Apple Silicon optimization flags + if platform.system() == "Darwin" and platform.machine() == "arm64": + env['CXXFLAGS'] = '{} -mcpu=apple-m1'.format(env.get('CXXFLAGS', '')) + if not os.path.exists(self.build_temp): os.makedirs(self.build_temp) subprocess.check_call(['cmake', ext.sourcedir] + cmake_args, cwd=self.build_temp, env=env) @@ -88,7 +102,14 @@ def build_extension(self, ext): test_suite="tests/SymSpellCppPyTest.py", ext_modules=[CMakeExtension('SymSpellCppPy')], cmdclass=versioneer.get_cmdclass(dict(build_ext=CMakeBuild)), - python_requires=">=3.4", + python_requires=">=3.7", + install_requires=[ + "pybind11>=2.11.0", + ], + setup_requires=[ + "pybind11>=2.11.0", + "setuptools>=40.6.0", + ], zip_safe=False, url="https://github.com/viig99/SymSpellCppPy", classifiers=[ @@ -98,13 +119,11 @@ def build_extension(self, ext): "License :: OSI Approved :: MIT License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.4", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11" + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12" ] ) From 42f07c09559f53cf43ca3a12144650583e7a64a8 Mon Sep 17 00:00:00 2001 From: skyler14 Date: Tue, 22 Jul 2025 17:29:43 -0700 Subject: [PATCH 2/3] Apple Silicone workflow to build pip install for it --- .github/workflows/build-wheels.yml | 61 ++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/build-wheels.yml diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml new file mode 100644 index 0000000..0d75a1e --- /dev/null +++ b/.github/workflows/build-wheels.yml @@ -0,0 +1,61 @@ +name: Build wheels + +on: + push: + branches: [ master, main ] + tags: [ v* ] + pull_request: + branches: [ master, main ] + +jobs: + build_wheels: + name: Build wheels on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest, macos-14] # macos-14 is Apple Silicon + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.8' + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install pybind11>=2.11.0 setuptools>=40.6.0 + + - name: Build wheels + uses: pypa/cibuildwheel@v2.16.2 + env: + # Skip 32-bit builds and older Python versions + CIBW_SKIP: "*-win32 *-manylinux_i686 pp* cp36-* cp37-*" + # Apple Silicon specific settings + CIBW_ARCHS_MACOS: "x86_64 arm64" + # Ensure we have CMake 3.18+ and pybind11 2.11+ + CIBW_BEFORE_ALL_MACOS: "brew install cmake && pip install 'pybind11>=2.11.0'" + CIBW_BEFORE_ALL_LINUX: "yum install -y cmake3 && pip install 'pybind11>=2.11.0'" + CIBW_BEFORE_ALL_WINDOWS: "pip install 'pybind11>=2.11.0'" + # Test that the wheels work + CIBW_TEST_COMMAND: "python -c \"import SymSpellCppPy; symspell = SymSpellCppPy.SymSpell(); print('✅ Import and basic functionality test passed')\"" + + - uses: actions/upload-artifact@v3 + with: + path: ./wheelhouse/*.whl + + upload_pypi: + needs: [build_wheels] + runs-on: ubuntu-latest + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') + steps: + - uses: actions/download-artifact@v3 + with: + name: artifact + path: dist + + - uses: pypa/gh-action-pypi-publish@v1.8.10 + with: + password: ${{ secrets.PYPI_API_TOKEN }} From c68720c489fb7e9ce022d6c6e3307966ee8bd9a2 Mon Sep 17 00:00:00 2001 From: skyler14 Date: Mon, 28 Jul 2025 11:29:44 -0700 Subject: [PATCH 3/3] Apply suggestions from code review Add better architecture support for Apple Silicon (and Linux in build.whl), Copilot recommendations Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/build-wheels.yml | 14 ++++++++++++-- CMakeLists.txt | 2 +- setup.py | 4 ++-- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml index 0d75a1e..917edcc 100644 --- a/.github/workflows/build-wheels.yml +++ b/.github/workflows/build-wheels.yml @@ -32,12 +32,22 @@ jobs: uses: pypa/cibuildwheel@v2.16.2 env: # Skip 32-bit builds and older Python versions - CIBW_SKIP: "*-win32 *-manylinux_i686 pp* cp36-* cp37-*" + CIBW_SKIP: "*-win32 *-manylinux_i686 pp* cp36-*" # Apple Silicon specific settings CIBW_ARCHS_MACOS: "x86_64 arm64" # Ensure we have CMake 3.18+ and pybind11 2.11+ CIBW_BEFORE_ALL_MACOS: "brew install cmake && pip install 'pybind11>=2.11.0'" - CIBW_BEFORE_ALL_LINUX: "yum install -y cmake3 && pip install 'pybind11>=2.11.0'" + CIBW_BEFORE_ALL_LINUX: | + if command -v yum > /dev/null; then + yum install -y cmake3; + elif command -v apt > /dev/null; then + apt update && apt install -y cmake; + elif command -v zypper > /dev/null; then + zypper install -y cmake; + else + echo "Unsupported package manager. Please install cmake manually." && exit 1; + fi + pip install 'pybind11>=2.11.0' CIBW_BEFORE_ALL_WINDOWS: "pip install 'pybind11>=2.11.0'" # Test that the wheels work CIBW_TEST_COMMAND: "python -c \"import SymSpellCppPy; symspell = SymSpellCppPy.SymSpell(); print('✅ Import and basic functionality test passed')\"" diff --git a/CMakeLists.txt b/CMakeLists.txt index d88b9fb..c8e3f86 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if (BUILD_FOR_PYTHON) if(APPLE AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64") # Apple Silicon optimizations target_compile_options(SymSpellCppPy PRIVATE - $<$:-O3 -DNDEBUG -mcpu=apple-m1 -fvisibility=hidden + $<$:-O3 -DNDEBUG -march=armv8.4-a -fvisibility=hidden -flto -ffat-lto-objects>) else() # Standard x86_64 optimizations diff --git a/setup.py b/setup.py index 57ccfb4..6a8a0e9 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ def run(self): else: if cmake_version < '3.18.0': raise RuntimeError("CMake >= 3.18.0 is required for Apple Silicon support. " - "Please update CMake: brew install cmake") + "Please update CMake by visiting https://cmake.org/download/ or using your system's package manager.") for ext in self.extensions: self.build_extension(ext) @@ -82,7 +82,7 @@ def build_extension(self, ext): # Add Apple Silicon optimization flags if platform.system() == "Darwin" and platform.machine() == "arm64": - env['CXXFLAGS'] = '{} -mcpu=apple-m1'.format(env.get('CXXFLAGS', '')) + env['CXXFLAGS'] = '{} -mcpu=apple-a14'.format(env.get('CXXFLAGS', '')) if not os.path.exists(self.build_temp): os.makedirs(self.build_temp)