Skip to content

Commit

Permalink
Revert "Use wider-compatible LLVM-OpenMP, bundle libgfortran dylibs…
Browse files Browse the repository at this point in the history
… for macOS wheels (pybamm-team#4092)" (pybamm-team#4109)

This reverts commit becb1a4.
  • Loading branch information
agriyakhetarpal authored and js1tr3 committed Aug 12, 2024
1 parent c5012ba commit 98b45ab
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 143 deletions.
70 changes: 20 additions & 50 deletions .github/workflows/publish_pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-13]
os: [ubuntu-latest, macos-12]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand All @@ -110,6 +110,15 @@ jobs:
- name: Clone pybind11 repo (no history)
run: git clone --depth 1 --branch v2.11.1 https://github.com/pybind/pybind11.git

# sometimes gfortran cannot be found, so reinstall gcc just to be sure
- name: Install SuiteSparse and SUNDIALS on macOS
if: matrix.os == 'macos-12'
run: |
brew install graphviz libomp
brew reinstall gcc
python -m pip install cmake wget
python scripts/install_KLU_Sundials.py
- name: Build wheels on Linux
run: pipx run cibuildwheel --output-dir wheelhouse
if: matrix.os == 'ubuntu-latest'
Expand Down Expand Up @@ -145,57 +154,18 @@ jobs:
- name: Clone pybind11 repo (no history)
run: git clone --depth 1 --branch v2.11.1 https://github.com/pybind/pybind11.git

- name: Build wheels on macOS arm64
- name: Install SuiteSparse and SUNDIALS on macOS
run: |
python -m pip install cibuildwheel
python -m cibuildwheel --output-dir wheelhouse
env:
MACOSX_DEPLOYMENT_TARGET: 11.0
# Sourced from
# License: BSD-3-Clause
# https://github.com/scipy/scipy/blob/f2d4775e7762fad984f8f0acd8227c725ff21630/tools/wheels/cibw_before_build_macos.sh#L23-L49
CIBW_BEFORE_ALL_MACOS: |
set -e -x
# download gfortran with proper macos minimum version (11.0)
curl -L https://github.com/isuruf/gcc/releases/download/gcc-11.3.0-2/gfortran-darwin-arm64-native.tar.gz -o gfortran.tar.gz
GFORTRAN_SHA256=$(shasum --algorithm 256 gfortran.tar.gz)
KNOWN_SHA256="84364eee32ba843d883fb8124867e2bf61a0cd73b6416d9897ceff7b85a24604 gfortran.tar.gz"
if [ "$GFORTRAN_SHA256" != "$KNOWN_SHA256" ]; then
echo "SHA256 mismatch for gfortran.tar.gz"
echo "expected: $KNOWN_SHA256"
echo "got: $GFORTRAN_SHA256"
exit 1
fi
mkdir -p gfortran_installed/
tar -xv -C gfortran_installed/ -f gfortran.tar.gz
brew install graphviz libomp
brew reinstall gcc
python -m pip install cmake pipx
python scripts/install_KLU_Sundials.py
export FC=$(pwd)/gfortran_installed/gfortran-darwin-arm64-native/bin/gfortran
export PATH=$(pwd)/gfortran_installed/gfortran-darwin-arm64-native/bin:$PATH
# link libgfortran.5.dylib, libgfortran.dylib, libquadmath.0.dylib, libquadmath.dylib, libgcc_s.1.1.dylib
# and place them in $HOME/.local/lib, and then change rpath
# note: libgcc_s.1.dylib not present for arm64, skip for now
# to $HOME/.local/lib
mkdir -p $HOME/.local/lib
lib_dir=$(pwd)/gfortran_installed/gfortran-darwin-arm64-native/lib
for lib in libgfortran.5.dylib libgfortran.dylib libquadmath.0.dylib libquadmath.dylib libgcc_s.1.1.dylib; do
cp $lib_dir/$lib $HOME/.local/lib/
install_name_tool -id $HOME/.local/lib/$lib $HOME/.local/lib/$lib
done
export SDKROOT=${SDKROOT:-$(xcrun --show-sdk-path)}
python -m pip install cmake wget
python scripts/install_KLU_Sundials.py
CIBW_BEFORE_BUILD_MACOS: python -m pip install --upgrade pip cmake casadi setuptools wheel delocate
# Use higher macOS target for now: https://github.com/casadi/casadi/issues/3698
CIBW_REPAIR_WHEEL_COMMAND_MACOS: |
delocate-listdeps {wheel} && delocate-wheel -v -w {dest_dir} {wheel} --require-target-macos-version 11.1
for file in {dest_dir}/*.whl; do mv "$file" "${file//macosx_11_1/macosx_11_0}"; done
- name: Build wheels on macOS arm64
run: python -m pipx run cibuildwheel --output-dir wheelhouse
env:
CIBW_BEFORE_BUILD: python -m pip install cmake casadi setuptools wheel delocate
CIBW_REPAIR_WHEEL_COMMAND: delocate-listdeps {wheel} && delocate-wheel -v -w {dest_dir} {wheel}
CIBW_TEST_COMMAND: python -c "import pybamm; pybamm.IDAKLUSolver()"

- name: Upload wheels for macOS arm64
Expand Down
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,3 @@ results/

# tests
test_callback.log

# openmp downloads
install_KLU_Sundials/openmp-*
install_KLU_Sundials/usr/
1 change: 0 additions & 1 deletion .lycheeignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# a list of links/files to be ignored by lychee link checker (see workflow file)
https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/v%7BSUITESPARSE_VERSION%7D.tar.gz
https://github.com/LLNL/sundials/releases/download/v%7BSUNDIALS_VERSION%7D/sundials-%7BSUNDIALS_VERSION%7D.tar.gz
https://mac.r-project.org/openmp/openmp-%7BOPENMP_VERSION%7D-darwin20-Release.tar.gz

# Errors in docs/source/user_guide/getting_started.md
file:///home/runner/work/PyBaMM/PyBaMM/docs/source/user_guide/api_docs
Expand Down
17 changes: 8 additions & 9 deletions docs/source/user_guide/installation/install-from-source.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ You can install the above with
Where ``X`` is the version sub-number.

.. tab:: macOS
.. tab:: MacOS

.. code:: bash
brew install python openblas gcc gfortran graphviz cmake pandoc
brew install python openblas gcc gfortran graphviz libomp cmake pandoc
.. note::

Expand Down Expand Up @@ -82,9 +82,8 @@ If you are running windows, you can simply skip this section and jump to :ref:`p
# in the PyBaMM/ directory
nox -s pybamm-requires
This will download, compile and install the SuiteSparse and SUNDIALS (with OpenMP) libraries
and the ``pybind11`` headers.
SuiteSparse and SUNDIALS are installed in ``~/.local`` by default.
This will download, compile and install the SuiteSparse and SUNDIALS libraries.
Both libraries are installed in ``~/.local``.

For users requiring more control over the installation process, the ``pybamm-requires`` session supports additional command-line arguments:

Expand All @@ -111,7 +110,7 @@ If you'd rather do things yourself,

1. Make sure you have CMake installed
2. Compile and install SuiteSparse (PyBaMM only requires the ``KLU`` component).
3. Compile and install SUNDIALS with `OpenMP support <https://mac.r-project.org/openmp/>`_.
3. Compile and install SUNDIALS.
4. Clone the pybind11 repository in the ``PyBaMM/`` directory (make sure the directory is named ``pybind11``).


Expand Down Expand Up @@ -316,12 +315,12 @@ source files to your current directory.
``ValueError: Integrator name ida does not exist``, or
``ValueError: Integrator name cvode does not exist``.

**Solution:** This could mean that you have not linked to
SUNDIALS correctly, check the instructions given above and make
**Solution:** This could mean that you have not installed
``scikits.odes`` correctly, check the instructions given above and make
sure each command was successful.

One possibility is that you have not set your ``LD_LIBRARY_PATH`` to
point to the SUNDIALS library, type ``echo $LD_LIBRARY_PATH`` and make
point to the sundials library, type ``echo $LD_LIBRARY_PATH`` and make
sure one of the directories printed out corresponds to where the
SUNDIALS libraries are located.

Expand Down
101 changes: 22 additions & 79 deletions scripts/install_KLU_Sundials.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,18 @@

SUITESPARSE_VERSION = "6.0.3"
SUNDIALS_VERSION = "6.5.0"

SUITESPARSE_URL = f"https://github.com/DrTimothyAldenDavis/SuiteSparse/archive/v{SUITESPARSE_VERSION}.tar.gz"
SUNDIALS_URL = f"https://github.com/LLNL/sundials/releases/download/v{SUNDIALS_VERSION}/sundials-{SUNDIALS_VERSION}.tar.gz"

SUITESPARSE_CHECKSUM = (
"7111b505c1207f6f4bd0be9740d0b2897e1146b845d73787df07901b4f5c1fb7"
)
SUNDIALS_CHECKSUM = "4e0b998dff292a2617e179609b539b511eb80836f5faacf800e688a886288502"

# universal binaries for macOS 11.0 and later; sourced from https://mac.r-project.org/openmp/
OPENMP_VERSION = "16.0.4"
OPENMP_URL = (
f"https://mac.r-project.org/openmp/openmp-{OPENMP_VERSION}-darwin20-Release.tar.gz"
)
OPENMP_CHECKSUM = "a763f0bdc9115c4f4933accc81f514f3087d56d6528778f38419c2a0d2231972"


DEFAULT_INSTALL_DIR = os.path.join(os.getenv("HOME"), ".local")


def safe_remove_dir(path):
"""Remove a directory or file if it exists."""
try:
if os.path.isfile(path):
os.remove(path)
elif os.path.isdir(path):
shutil.rmtree(path)
except Exception as e:
print(f"Error while removing {path}: {e}")
if os.path.exists(path):
shutil.rmtree(path)


def install_suitesparse(download_dir):
Expand All @@ -61,11 +44,11 @@ def install_suitesparse(download_dir):
env = os.environ.copy()
for libdir in ["SuiteSparse_config", "AMD", "COLAMD", "BTF", "KLU"]:
build_dir = os.path.join(suitesparse_src, libdir)
# Set an RPATH in order for libsuitesparseconfig.dylib to find libomp.dylib
# We want to ensure that libsuitesparseconfig.dylib is not repeated in
# multiple paths at the time of wheel repair. Therefore, it should not be
# built with an RPATH since it is copied to the install prefix.
if libdir == "SuiteSparse_config":
env["CMAKE_OPTIONS"] = (
f"-DCMAKE_INSTALL_PREFIX={install_dir} -DCMAKE_INSTALL_RPATH={install_dir}/lib"
)
env["CMAKE_OPTIONS"] = f"-DCMAKE_INSTALL_PREFIX={install_dir}"
else:
# For AMD, COLAMD, BTF and KLU; do not set a BUILD RPATH but use an
# INSTALL RPATH in order to ensure that the dynamic libraries are found
Expand Down Expand Up @@ -103,9 +86,20 @@ def install_sundials(download_dir, install_dir):
# try to find OpenMP on mac
if platform.system() == "Darwin":
# flags to find OpenMP on mac
OpenMP_C_FLAGS = f"-Xpreprocessor -fopenmp -lomp -L{os.path.join(KLU_LIBRARY_DIR)} -I{os.path.join(KLU_INCLUDE_DIR)}"
OpenMP_C_LIB_NAMES = "omp"
OpenMP_omp_LIBRARY = os.path.join(KLU_LIBRARY_DIR, "libomp.dylib")
if platform.processor() == "arm":
OpenMP_C_FLAGS = (
"-Xpreprocessor -fopenmp -I/opt/homebrew/opt/libomp/include"
)
OpenMP_C_LIB_NAMES = "omp"
OpenMP_omp_LIBRARY = "/opt/homebrew/opt/libomp/lib/libomp.dylib"
elif platform.processor() == "i386":
OpenMP_C_FLAGS = "-Xpreprocessor -fopenmp -I/usr/local/opt/libomp/include"
OpenMP_C_LIB_NAMES = "omp"
OpenMP_omp_LIBRARY = "/usr/local/opt/libomp/lib/libomp.dylib"
else:
raise NotImplementedError(
f"Unsupported processor architecture: {platform.processor()}. Only 'arm' and 'i386' architectures are supported."
)

cmake_args += [
"-DOpenMP_C_FLAGS=" + OpenMP_C_FLAGS,
Expand All @@ -129,47 +123,6 @@ def install_sundials(download_dir, install_dir):
subprocess.run(make_cmd, cwd=build_dir, check=True)


# Relevant for macOS only because recent Xcode Clang versions do not include OpenMP headers.
# Other compilers (e.g. GCC) include the OpenMP specification by default.
def set_up_openmp(download_dir, install_dir):
print("-" * 10, "Extracting OpenMP archive", "-" * 40)

openmp_dir = f"openmp-{OPENMP_VERSION}"
openmp_src = os.path.join(download_dir, openmp_dir)

# extract OpenMP archive
with tarfile.open(
os.path.join(download_dir, f"{openmp_dir}-darwin20-Release.tar.gz")
) as tar:
tar.extractall(openmp_src)

# create directories
os.makedirs(os.path.join(install_dir, "lib"), exist_ok=True)
os.makedirs(os.path.join(install_dir, "include"), exist_ok=True)

# copy files
shutil.copy(
os.path.join(openmp_src, "usr", "local", "lib", "libomp.dylib"),
os.path.join(install_dir, "lib"),
)
for file in os.listdir(os.path.join(openmp_src, "usr", "local", "include")):
shutil.copy(
os.path.join(openmp_src, "usr", "local", "include", file),
os.path.join(install_dir, "include"),
)

# fix rpath; for some reason the downloaded dylib has an absolute path
# to /usr/local/lib/, so use self-referential rpath
subprocess.check_call(
[
"install_name_tool",
"-id",
"@rpath/libomp.dylib",
f"{os.path.join(install_dir, 'lib', 'libomp.dylib')}",
]
)


def check_libraries_installed(install_dir):
# Define the directories to check for SUNDIALS and SuiteSparse libraries
lib_dirs = [install_dir]
Expand Down Expand Up @@ -217,7 +170,7 @@ def check_libraries_installed(install_dir):
suitesparse_files = [file + ".dylib" for file in suitesparse_files]
else:
raise NotImplementedError(
f"Unsupported operating system: {platform.system()}. This script supports only Linux and macOS."
f"Unsupported operating system: {platform.system()}. This script currently supports only Linux and macOS."
)

suitesparse_lib_found = True
Expand All @@ -239,16 +192,6 @@ def check_libraries_installed(install_dir):
return sundials_lib_found, suitesparse_lib_found


def check_openmp_installed_on_macos(install_dir):
openmp_lib_found = isfile(join(install_dir, "lib", "libomp.dylib"))
openmp_headers_found = isfile(join(install_dir, "include", "omp.h"))
if not openmp_lib_found or not openmp_headers_found:
print("libomp.dylib or omp.h not found. Proceeding with OpenMP installation.")
else:
print(f"libomp.dylib and omp.h found in {install_dir}.")
return openmp_lib_found


def calculate_sha256(file_path):
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
Expand Down Expand Up @@ -324,7 +267,7 @@ def parallel_download(urls, download_dir):

# Get installation location
parser = argparse.ArgumentParser(
description="Download, compile and install SUNDIALS and SuiteSparse."
description="Download, compile and install Sundials and SuiteSparse."
)
parser.add_argument(
"--force",
Expand Down

0 comments on commit 98b45ab

Please sign in to comment.