From b661d0d5db8770f7bfa858a86dcdd0f6d9746639 Mon Sep 17 00:00:00 2001 From: Yashas Ambati Date: Wed, 16 Apr 2025 14:13:48 -0400 Subject: [PATCH] Changes to build macOS wheels for 10.15 or newer --- .../scripts/python_wheels/cibw_before_all.sh | 51 +++++++++++++++---- .github/workflows/build-cibw.yml | 47 +++++++++++------ 2 files changed, 71 insertions(+), 27 deletions(-) diff --git a/.github/scripts/python_wheels/cibw_before_all.sh b/.github/scripts/python_wheels/cibw_before_all.sh index 2398877a8..98179ad14 100644 --- a/.github/scripts/python_wheels/cibw_before_all.sh +++ b/.github/scripts/python_wheels/cibw_before_all.sh @@ -15,16 +15,46 @@ export PYTHON="python${PYTHON_VERSION}" if [ "$(uname)" == "Linux" ]; then # manylinux2014 is based on CentOS 7, so use yum to install dependencies yum install -y wget - - # Install Boost from source - wget https://archives.boost.io/release/1.87.0/source/boost_1_87_0.tar.gz --quiet - tar -xzf boost_1_87_0.tar.gz - cd boost_1_87_0 - ./bootstrap.sh --prefix=/opt/boost - ./b2 install --prefix=/opt/boost --with=all - cd .. elif [ "$(uname)" == "Darwin" ]; then - brew install wget cmake boost + brew install cmake + + # If MACOSX_DEPLOYMENT_TARGET is not explicitly set, default to the version of the host system. + if [[ -z "${MACOSX_DEPLOYMENT_TARGET}" ]]; then + export MACOSX_DEPLOYMENT_TARGET="$(sw_vers -productVersion | cut -d '.' -f 1-2)" + fi +fi + +# Install Boost from source +wget https://archives.boost.io/release/1.87.0/source/boost_1_87_0.tar.gz --quiet +tar -xzf boost_1_87_0.tar.gz +cd boost_1_87_0 + +BOOST_PREFIX="$HOME/opt/boost" +./bootstrap.sh --prefix=${BOOST_PREFIX} + +if [ "$(uname)" == "Linux" ]; then + ./b2 install --prefix=${BOOST_PREFIX} --with=all -d0 +elif [ "$(uname)" == "Darwin" ]; then + ./b2 install --prefix=${BOOST_PREFIX} --with=all -d0 \ + cxxflags="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}" \ + linkflags="-mmacosx-version-min=${MACOSX_DEPLOYMENT_TARGET}" +fi +cd .. + +# Export paths so CMake or build system can find Boost +export BOOST_ROOT="${BOOST_PREFIX}" +export BOOST_INCLUDEDIR="${BOOST_PREFIX}/include" +export BOOST_LIBRARYDIR="${BOOST_PREFIX}/lib" + +# Ensure runtime linker can find Boost libraries +export LD_LIBRARY_PATH="${BOOST_LIBRARYDIR}:$LD_LIBRARY_PATH" # For Linux +export REPAIR_LIBRARY_PATH="${BOOST_LIBRARYDIR}:$DYLD_LIBRARY_PATH" # For macOS, REPAIR_LIBRARY_PATH is used by delocate + +if [ "$(uname)" == "Darwin" ]; then + # Explicitly add rpath to Boost dylibs so delocate can find them + for dylib in ${BOOST_LIBRARYDIR}/*.dylib; do + install_name_tool -add_rpath "@loader_path" "$dylib" + done fi $(which $PYTHON) -m pip install -r $PROJECT_DIR/python/dev_requirements.txt @@ -50,9 +80,8 @@ cmake $PROJECT_DIR \ -DGTSAM_ALLOW_DEPRECATED_SINCE_V43=OFF \ -DCMAKE_INSTALL_PREFIX=$PROJECT_DIR/gtsam_install -cd $PROJECT_DIR/build/python - # Install the Python wrapper module and generate Python stubs +cd $PROJECT_DIR/build/python if [ "$(uname)" == "Linux" ]; then make -j $(nproc) install make -j $(nproc) python-stubs diff --git a/.github/workflows/build-cibw.yml b/.github/workflows/build-cibw.yml index f0b93aef1..95a2e8dfd 100644 --- a/.github/workflows/build-cibw.yml +++ b/.github/workflows/build-cibw.yml @@ -76,22 +76,22 @@ jobs: manylinux_image: manylinux2014 # MacOS x86_64 - # - os: macos-13 - # python_version: "3.10" - # cibw_python_version: 310 - # platform_id: macosx_x86_64 - # - os: macos-13 - # python_version: "3.11" - # cibw_python_version: 311 - # platform_id: macosx_x86_64 - # - os: macos-13 - # python_version: "3.12" - # cibw_python_version: 312 - # platform_id: macosx_x86_64 - # - os: macos-13 - # python_version: "3.13" - # cibw_python_version: 313 - # platform_id: macosx_x86_64 + - os: macos-13 + python_version: "3.10" + cibw_python_version: 310 + platform_id: macosx_x86_64 + - os: macos-13 + python_version: "3.11" + cibw_python_version: 311 + platform_id: macosx_x86_64 + - os: macos-13 + python_version: "3.12" + cibw_python_version: 312 + platform_id: macosx_x86_64 + - os: macos-13 + python_version: "3.13" + cibw_python_version: 313 + platform_id: macosx_x86_64 steps: - name: Checkout @@ -130,6 +130,14 @@ jobs: run: | cmake . -B build -DGTSAM_BUILD_PYTHON=1 -DGTSAM_PYTHON_VERSION=${{ matrix.python_version }} + # If on macOS, we previously installed boost using homebrew for the first build. + # We need to uninstall it before building the wheels with cibuildwheel, which will + # install boost from source. + - name: Uninstall Boost (MacOS) + if: runner.os == 'macOS' + run: | + brew uninstall boost + - name: Build and test wheels env: # Generate the platform identifier. See https://cibuildwheel.pypa.io/en/stable/options/#build-skip. @@ -139,6 +147,13 @@ jobs: CIBW_ARCHS: all CIBW_ENVIRONMENT_PASS_LINUX: DEVELOP TIMESTAMP + # Set the minimum required MacOS version for the wheels. + MACOSX_DEPLOYMENT_TARGET: 10.15 + + # Set DYLD_LIBRARY_PATH to REPAIR_LIBRARY_PATH, which is set in cibw_before_all.sh. REPAIR_LIBRARY_PATH + # simply appends BOOST_LIBRARYDIR to the path, which is required during during link-time repair. + CIBW_REPAIR_WHEEL_COMMAND_MACOS: DYLD_LIBRARY_PATH=$REPAIR_LIBRARY_PATH delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} + # Use build instead of pip wheel to build the wheels. This is recommended by PyPA. # See https://cibuildwheel.pypa.io/en/stable/options/#build-frontend. CIBW_BUILD_FRONTEND: "build"