Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9b26304
set up cibuildwheel
IvanaGyro Nov 21, 2025
9960c82
Fix: expand ~ in CCACHE_CONFIGPATH to actual home directory
b95702041 Jan 31, 2026
04934a9
Fix: add cblas.h symlink for Linux builds
b95702041 Jan 31, 2026
c01e17a
Fix: add openblas_config.h symlink for Linux builds
b95702041 Jan 31, 2026
b177936
Fix: ensure all OpenBLAS headers are accessible
b95702041 Jan 31, 2026
e317a6a
Fix: install core dev tools for gcc-toolset compatibility
b95702041 Jan 31, 2026
f2b3cf3
Fix: add CFLAGS and CXXFLAGS for gcc-toolset include paths
b95702041 Jan 31, 2026
c46b562
Fix: add CFLAGS and CXXFLAGS for Linux gcc-toolset
b95702041 Jan 31, 2026
86de99e
fix: remove CFLAGS and CXXFLAGS to fix math.h not found error
b95702041 Jan 31, 2026
02126f6
fix: add setuptools for distutils compatibility with Python 3.12+
b95702041 Jan 31, 2026
3041121
fix: use dnf instead of yum for manylinux_2_34
b95702041 Jan 31, 2026
ac4f5ea
fix: detect available package manager in manylinux
b95702041 Feb 1, 2026
b029f41
fix: restore before_all.sh to working version
b95702041 Feb 1, 2026
44ad9bc
Fix: restore all Linux build fixes for manylinux_2_28
b95702041 Feb 1, 2026
ca6690c
fix: change to manylinux_2_28
b95702041 Feb 1, 2026
4bbeea1
fix: disable Boost CMake config for manylinux_2_28
b95702041 Feb 1, 2026
7a56f85
fix: allow Boost MODULE mode for manylinux_2_28
b95702041 Feb 1, 2026
2ca5be9
fix: use full path for dnf in manylinux_2_28
b95702041 Feb 1, 2026
62eeb1f
debug: check available package managers in manylinux_2_28
b95702041 Feb 1, 2026
9c61140
fix: install ccache via pipx in manylinux
b95702041 Feb 1, 2026
2f972cf
fix: install ccache from binary release
b95702041 Feb 1, 2026
01a7f3c
fix: install boost and dependencies via dnf/yum
b95702041 Feb 1, 2026
5a9d1e9
fix: add fallback dummy ccache if binary fails
b95702041 Feb 2, 2026
ae4720d
fix: add musllinux (apk) support
b95702041 Feb 2, 2026
07d192a
fix: add conditional compilation for execinfo.h to support musl libc
b95702041 Feb 2, 2026
f9f436b
refactor: use package manager for ccache, move Boost cmake flag to ci…
b95702041 Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .github/workflows/ci-cmake_tests.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
name: Tests and Codecov
on:
pull_request:
branches:
- master
workflow_dispatch:
jobs:
BuildAndTest:
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/clang-format-check.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
name: clang-format Check
on:
pull_request:
workflow_dispatch:
jobs:
formatting-check:
Expand Down
3 changes: 0 additions & 3 deletions .github/workflows/conda_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:

jobs:
Expand Down
78 changes: 78 additions & 0 deletions .github/workflows/release_pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Release to PyPI

on:
pull_request:
workflow_dispatch:

jobs:
BuildWheel:
name: BuildWheel-${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-14, macos-15-intel]
# os: [ubuntu-latest]
defaults:
run:
shell: bash -l {0}

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

# When re-running a PR job, GitHub Actions uses the merge commit created at
# the time of the original run, not a fresh merge with the latest target branch.
# This step ensures we always test against the most recent target branch.
- name: Merge with latest target branch (pull_request only)
if: github.event_name == 'pull_request'
run: |
git fetch origin ${{ github.event.pull_request.base.ref }}
git merge --no-edit origin/${{ github.event.pull_request.base.ref }}

- name: Cache Ccache Directory (pull_request)
if: ${{ github.event_name == 'pull_request' }}
uses: actions/cache@v4
with:
path: |
~/.ccache
key: ccache-${{ runner.os }}-${{ github.event.pull_request.head.ref }}-${{ github.sha }}
restore-keys: |
ccache-${{ runner.os }}-${{ github.event.pull_request.head.ref }}-
ccache-${{ runner.os }}-${{ github.event.pull_request.base.ref }}-

- name: Set Ccache Directory
run: |
echo "Start building---------------------------------"
export CCACHE_DIR="${HOME}/.ccache"

- name: Setup macOS
if: matrix.os == 'macos-15-intel' || matrix.os == 'macos-14'
run: |
if [[ ${{ matrix.os }} == 'macos-15-intel' ]]; then
echo "MACOSX_DEPLOYMENT_TARGET=15.0" >> "$GITHUB_ENV"
elif [[ ${{ matrix.os }} == 'macos-14' ]]; then
echo "MACOSX_DEPLOYMENT_TARGET=14.0" >> "$GITHUB_ENV"
fi

- name: Build Wheels
uses: pypa/cibuildwheel@v3.3.0
env:
CMAKE_C_COMPILER_LAUNCHER: ccache
CMAKE_CXX_COMPILER_LAUNCHER: ccache
CMAKE_CUDA_COMPILER_LAUNCHER: ccache
# DO NOT enable this line because the script for conda build is not
# executed in a interactive shell, and "~" will not be expanded to the
# home directory. Export CCACHE_DIR in the run command instead.
# CCACHE_DIR: ~/.ccache
CCACHE_MAXSIZE: 1G # The limit of actions/cache is 10GB
# Pass environment variables into cibuildwheel build environments
# This is only needed on Linux becuase the wheels are built in docker
# images only on Linux.
CIBW_ENVIRONMENT_PASS_LINUX: CMAKE_C_COMPILER_LAUNCHER CMAKE_CXX_COMPILER_LAUNCHER CMAKE_CUDA_COMPILER_LAUNCHER CCACHE_MAXSIZE

- uses: actions/upload-artifact@v4
with:
name: cibw-wheels-${{ matrix.os }}-${{ strategy.job-index }}
path: ./wheelhouse/*.whl
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ if(USE_CUDA)
set(CMAKE_CUDA_USE_RESPONSE_FILE_FOR_OBJECTS 0)
endif()


# Print all environment variables for debugging
message(STATUS "==================== Environment Variables ====================")
execute_process(COMMAND ${CMAKE_COMMAND} -E environment
OUTPUT_VARIABLE ENV_OUTPUT)
message(STATUS "${ENV_OUTPUT}")
message(STATUS "================================================================")

# C++ uses link-time optimization anyway; this enables additionally -flto=auto,
# for parallel compilation
# It cannot enable on MacOS since it causes building errors when linking the library libcytnx.a.
Expand Down Expand Up @@ -243,7 +251,7 @@ endif()
# #####################################################################

# ## Boost
find_package(Boost CONFIG REQUIRED)
find_package(Boost REQUIRED)
target_include_directories(cytnx SYSTEM
PUBLIC
${Boost_INCLUDE_DIRS}
Expand Down
7 changes: 7 additions & 0 deletions include/cytnx_error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
#include <iostream>
#include <stdexcept>

#if defined(__GLIBC__)
#include <execinfo.h>
#define HAS_EXECINFO 1
#else
#define HAS_EXECINFO 0
#endif

#ifdef _MSC_VER
#define __PRETTY_FUNCTION__ __FUNCTION__
Expand All @@ -34,6 +39,7 @@ static inline void error_msg(char const *const func, const char *const file, int
va_end(args);
// std::cerr << output_str << std::endl;
std::cerr << output_str << std::endl;
#if HAS_EXECINFO
std::cerr << "Stack trace:" << std::endl;
void *array[10];
size_t size;
Expand All @@ -43,6 +49,7 @@ static inline void error_msg(char const *const func, const char *const file, int
std::cerr << strings[i] << std::endl;
}
free(strings);
#endif
throw std::logic_error(output_str);
}
// } catch (const char *output_msg) {
Expand Down
34 changes: 33 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["scikit-build-core >=0.11", "pybind11 >=3.0"]
requires = ["scikit-build-core >=0.11", "pybind11 >=3.0", "setuptools"]
build-backend = "scikit_build_core.build"

[project]
Expand Down Expand Up @@ -43,6 +43,10 @@ cmake.args = [
# conflicts against the build process of HPTT.
"-G Unix Makefiles",
]
# Force the build directory to be "build" instead of a random temp folder. This helps
# ccache caches the compiler outputs successfully.
build-dir = "build/{wheel_tag}"
# cp39-cp39-macosx_14_0_arm64

[tool.scikit-build.metadata.version]
provider = "scikit_build_core.metadata.regex"
Expand All @@ -53,3 +57,31 @@ set\(\w+?VERSION_MINOR\s+(?P<minor>\d+)\)
set\(\w+?VERSION_PATCH\s+(?P<patch>\d+)\)
'''
result = "{major}.{minor}.{patch}"

[tool.cibuildwheel]
# The image used to build wheels for x86_64 on Linux is manylinux_2_28, which supports
# older version of Linux than manylinux_2_34. However, manylinux_2_28 is AlmaLinux 8
# based and AlmaLinux 8 ships Boost v1.66. The Boost's CMake configuration files are only
# available since v1.70, so AlmaLinux 9 based manylinux_2_34 is picked here.
# There is a caveat for manylinux_2_34. manylinux_2_34 assume the machines use x86-64-v2
# architecture which is an extension of x86_64, so the wheels built with manylinux_2_34
# may not support older machines. See https://github.com/pypa/manylinux?tab=readme-ov-file#manylinux_2_34-almalinux-9-based---alpha
# for more information.
manylinux-x86_64-image = "manylinux_2_28"
before-build = "python ./tools/cibuildwheel_before_build.py"

[tool.cibuildwheel.linux]
# before-all = "apt-get install -y arpack boost ccache libomp openblas"
before-all = "bash ./tools/cibuildwheel_before_all.sh"
# To include LAPACKE header.
environment = { CMAKE_PREFIX_PATH = "/usr/include/openblas", CPATH = "/usr/include/openblas", CCACHE_CONFIGPATH = "~/ccache.conf", CMAKE_ARGS = "-DBoost_NO_BOOST_CMAKE=ON" }

[tool.cibuildwheel.macos]
before-all = "brew update; brew install arpack boost ccache libomp openblas"
environment = { CMAKE_PREFIX_PATH = "$(brew --prefix arpack):$(brew --prefix boost):$(brew --prefix libomp):$(brew --prefix openblas)", PATH = "$(brew --prefix ccache)/libexec:$PATH", CCACHE_CONFIGPATH = "~/ccache.conf" }

# [tool.cibuildwheel]
# before-build = "bash {project}/tools/cibuildwheel_before_build.sh"
# # environment = { CMAKE_PREFIX_PATH = "$(brew --prefix openblas)", PATH = "$(brew --prefix ccache)/libexec:$PATH" }
# # Alternative static configuration for macOS:
# environment = { CMAKE_PREFIX_PATH = "/opt/homebrew/opt/openblas", PATH = "/opt/homebrew/opt/ccache/libexec:$PATH" }
24 changes: 24 additions & 0 deletions tools/cibuildwheel_before_all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
set -xe

# Install required packages based on distro
if command -v apk &> /dev/null; then
# musllinux (Alpine)
apk add --no-cache boost-dev openblas-dev arpack-dev ccache
elif command -v dnf &> /dev/null; then
# manylinux_2_28+ (AlmaLinux/RHEL)
dnf install -y boost-devel openblas-devel arpack-devel ccache
elif command -v yum &> /dev/null; then
# manylinux2014 (CentOS)
yum install -y boost-devel openblas-devel arpack-devel ccache
else
echo "WARNING: No package manager found"
fi

# Create symlinks for OpenBLAS headers if available
if [ -d /usr/include/openblas ]; then
ln -sf /usr/include/openblas/lapacke.h /usr/include/lapacke.h
ln -sf /usr/include/openblas/lapack.h /usr/include/lapack.h
ln -sf /usr/include/openblas/lapacke_mangling.h /usr/include/lapacke_mangling.h
ln -sf /usr/include/openblas/cblas.h /usr/include/cblas.h
ln -sf /usr/include/openblas/openblas_config.h /usr/include/openblas_config.h
fi
25 changes: 25 additions & 0 deletions tools/cibuildwheel_before_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os
import pathlib
import sys

import packaging.tags
tag = f'cp{sys.version_info.major}{sys.version_info.minor}'

ccache_config_path = os.getenv('CCACHE_CONFIGPATH')

# Expand ~ to actual home directory
ccache_config_path = os.path.expanduser(ccache_config_path)
if not ccache_config_path:
raise RuntimeError('The CCACHE_CONFIGPATH environment variable must be set.')

print("ccache_config_path:", ccache_config_path)
print("ccache_config_path:", pathlib.Path(ccache_config_path).absolute())


wheel_tag = str(next(packaging.tags.sys_tags()))
print("wheel_tag:", wheel_tag)

with open(ccache_config_path, 'w') as f:
f.writelines([
f'base_dir = /project/build/{wheel_tag}'
])
55 changes: 55 additions & 0 deletions tools/cibuildwheel_before_build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
set -xe

# Install OpenBLAS
# python -m pip install scipy-openblas64
# blas_lib_dir=$(python -c "import scipy_openblas64; print(scipy_openblas64.get_lib_dir())")
# blas_lib_name=$(python -c "import scipy_openblas64; print(scipy_openblas64.get_library())")
# # This handles different extensions (.so on Linux, .dylib on macOS)
# blas_lib_file=$(find "$blas_lib_dir" -name "*${blas_lib_name}.*" -type f | head -n 1)
# export BLAS_LIBRARIES="$blas_lib_file"

# # Verify BLAS_LIBRARIES points to an existing file
# if [ -f "$BLAS_LIBRARIES" ]; then
# echo "✓ BLAS_LIBRARIES points to existing file: $BLAS_LIBRARIES"
# else
# echo "✗ ERROR: BLAS_LIBRARIES does not point to a valid file: $BLAS_LIBRARIES"
# exit 1
# fi

# BLA_SIZEOF_INTEGER=8 matches the ILP64 openblas64_ interface
# that scipy-openblas64 provides; this avoids CMake thinking
# it found a 32-bit BLAS.
# export BLA_SIZEOF_INTEGER=8


uname -s
# Set up Homebrew for Linux
# Homebrew was removed from PATH on Linux:
# https://github.com/actions/runner-images/issues/6283
if [[ "$(uname -s)" == "Linux" ]]; then
# Find linuxbrew from root folder recursively
# Common locations: /home/linuxbrew/.linuxbrew, /home/*/linuxbrew/.linuxbrew
# brew_find=$(find / -name "*linuxbrew*" -type d 2>/dev/null)
# linuxbrew_bin=$(echo $brew_find | head -n 1)
# if [ -n "$linuxbrew_bin" ] && [ -d "$linuxbrew_bin/bin" ]; then
# echo "Found linuxbrew at: $linuxbrew_bin"
# export PATH="$linuxbrew_bin/bin:$PATH"
# else
# echo "Warning: linuxbrew not found, trying default path"
# export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH"
# fi
export PATH="/host/home/linuxbrew/.linuxbrew/bin:$PATH"
fi

# Install boost, ccache and arpack-ng
# All Ubuntu and macOS GitHub action runners have Homebrew installed.
brew install boost ccache arpack openblas

brew --prefix openblas
ls $(brew --prefix openblas)
brew --prefix ccache
ls $(brew --prefix ccache)
brew --prefix arpack
ls $(brew --prefix arpack)
brew --prefix boost
ls $(brew --prefix boost)