Skip to content

ENH: Add windows support #184

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 57 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
8e99db3
Bump iqtree2 from `1320c4c` to `39cbee5`
dependabot[bot] Mar 19, 2025
6911d6a
DEV: ignore dll files
rmcar17 Mar 19, 2025
52dab31
DEV: update libiqtree function signatures and add custom type convert…
rmcar17 Mar 19, 2025
971bb3e
DEV: ensure DLLs are included in build on windows
rmcar17 Mar 19, 2025
4af4b53
BUG: on windows, change out of tmp directory before cleaning up
rmcar17 Mar 19, 2025
48dcde4
TST: skip tests which throw error on IQ-TREE side on windows
rmcar17 Mar 19, 2025
b2273f6
ENH: include cstddef for other platforms
rmcar17 Mar 19, 2025
fbe6bba
MAINT: ignore attr-defined typing error for non-windows
rmcar17 Mar 19, 2025
e814a74
DEV: add windows build scripts
rmcar17 Mar 20, 2025
40196d3
DEV: build windows when building iqtree and cache correct files.
rmcar17 Mar 20, 2025
5e65f8a
DEV: test build process on windows
rmcar17 Mar 20, 2025
29f586f
DEV: install boost through action on windows, remove non-available ch…
rmcar17 Mar 20, 2025
6d7cf29
DEV: set boost env variables
rmcar17 Mar 20, 2025
7792886
DEV: debug boost env vars
rmcar17 Mar 20, 2025
14cef0a
DEV: removed path debugs, manually specify boost dirs
rmcar17 Mar 20, 2025
d570951
DEV: manually specify toolchain, downgrade llvm
rmcar17 Mar 20, 2025
fca8540
DEV: add lib.exe to path
rmcar17 Mar 20, 2025
688e589
DEV: debug msvc path
rmcar17 Mar 20, 2025
d1e4d61
DEV: try running wswhere through cmd
rmcar17 Mar 20, 2025
a189060
DEV: try configuring MSVC
rmcar17 Mar 20, 2025
26acfa1
DEV: use cmd to setup VS env
rmcar17 Mar 20, 2025
b6d38b5
DEV: use action to setup msvc
rmcar17 Mar 20, 2025
d52c8b4
DEV: continue build process with found lib
rmcar17 Mar 20, 2025
25611ac
DEV: only brew install on mac
rmcar17 Mar 20, 2025
ecb84ea
DEV: use different caches on unix/windows
rmcar17 Mar 20, 2025
fa7083d
DEV: Install llvm when testing windows ci, make build_iqtree compatib…
rmcar17 Mar 20, 2025
289e9df
DEV: re-enable full CI matrix
rmcar17 Mar 20, 2025
002f74e
DEV: use runner.os for choosing before_all script
rmcar17 Mar 20, 2025
fec36ab
DEV: standardise cache names
rmcar17 Mar 20, 2025
2d0f3b2
DEV: use correct input for cache key
rmcar17 Mar 20, 2025
631298f
DEV: add windows to cibuildwheel
rmcar17 Mar 20, 2025
19b0648
DEV: run before_all_windows script with bash
rmcar17 Mar 20, 2025
2c221e4
DEV: debug BOOST env vars
rmcar17 Mar 20, 2025
0914a96
DEV: attempt hardcoding boost paths
rmcar17 Mar 20, 2025
060b659
DEV: fix BOOST lib path
rmcar17 Mar 20, 2025
d9673de
DEV: remove hardcoding of BOOST paths
rmcar17 Mar 20, 2025
a4d9bd1
DEV: hardcode paths again
rmcar17 Mar 20, 2025
a8e8476
DEV: normalise slashes in before_all_windows
rmcar17 Mar 20, 2025
9f9669c
MAINT: remove extra space
rmcar17 Mar 20, 2025
c0d4be7
MAINT: update python version (#4)
rmcar17 Mar 20, 2025
84dad45
Merge branch 'main' into windows-support
rmcar17 Mar 20, 2025
505c1d9
DEV: update iqtree to error handling version
rmcar17 Mar 23, 2025
e4ad032
DEV: update return/arg types for calling IQ-TREE
rmcar17 Mar 23, 2025
bc80ae0
DEV: remove pytest skips on windows
rmcar17 Mar 23, 2025
466e979
DEV: rebase windows-support on main (#5)
rmcar17 May 12, 2025
819e003
ENH: fix memory leak in `StringResult`
rmcar17 May 19, 2025
edb6dbe
ENH: free error message memory post-check
rmcar17 May 19, 2025
b352953
ENH: simplify memory freeing for StringResult
rmcar17 May 19, 2025
2ff1f61
ENH: reduce memory leaks for `DoubleArrayResult`
rmcar17 May 19, 2025
6aaa517
MAINT: don't need to use namespace for `free`
rmcar17 May 20, 2025
10a489f
ENH: reduce memory leaks from DoubleArray
rmcar17 May 20, 2025
578e749
MAINT: standardise string usage
rmcar17 May 20, 2025
245a806
MAINT: simplify `tmpDoubles` creation
rmcar17 May 20, 2025
8595210
DEV: add `delvewheel` as dev dependency
rmcar17 May 21, 2025
c32708a
MAINT: format TOML file
rmcar17 May 21, 2025
a8bb1bd
Merge branch 'main' into windows-support
rmcar17 May 21, 2025
a6b45a0
DEV: add scriv fragment for windows support
rmcar17 May 21, 2025
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
63 changes: 56 additions & 7 deletions .github/actions/build-iqtree/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,68 @@ runs:
IQ_TREE_2_SHA=$(git rev-parse HEAD)
echo "iqtree2-sha=${IQ_TREE_2_SHA}" >> "$GITHUB_OUTPUT"

- uses: actions/cache@v4
id: cache
- name: Cache IQ-TREE 2 (Windows)
if: runner.os == 'Windows'
uses: actions/cache@v4
id: cache-windows
with:
key: libiqtree-${{ inputs.os }}-${{ steps.iqtree2-sha.outputs.iqtree2-sha }}
path: |
src/piqtree/_libiqtree/iqtree2.lib
src/piqtree/_libiqtree/iqtree2.dll
lookup-only: true

- name: Cache IQ-TREE 2 (Linux/macOS)
if: runner.os != 'Windows'
uses: actions/cache@v4
id: cache-unix
with:
key: libiqtree-${{ inputs.os }}-${{ steps.iqtree2-sha.outputs.iqtree2-sha }}
path: src/piqtree/_libiqtree/libiqtree2.a
path: |
src/piqtree/_libiqtree/libiqtree2.a
lookup-only: true

- name: Combine Cache Hits
id: cache
shell: bash
run: |
if [[ "${{ steps.cache-windows.outputs.cache-hit }}" == 'true' || "${{ steps.cache-unix.outputs.cache-hit }}" == 'true' ]]; then
echo "cache-hit=true" >> "$GITHUB_OUTPUT"
else
echo "cache-hit=false" >> "$GITHUB_OUTPUT"
fi

- name: Install Boost
if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true'
uses: MarkusJx/[email protected]
id: install-boost
with:
boost_version: 1.84.0
platform_version: 2022
toolset: mingw

- name: Set Boost Environment Variables
if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true'
shell: bash
run: |
echo "Boost_INCLUDE_DIR=${{ steps.install-boost.outputs.BOOST_ROOT }}/include" >> "$GITHUB_ENV"
echo "Boost_LIBRARY_DIRS=${{ steps.install-boost.outputs.BOOST_ROOT }}/lib" >> "$GITHUB_ENV"

- name: Setup MSVC Developer Command Prompt
if: runner.os == 'Windows' && steps.cache.outputs.cache-hit != 'true'
uses: ilammy/msvc-dev-cmd@v1

- name: Build IQ-TREE
shell: bash
if: steps.cache.outputs.cache-hit != 'true'
run: |
if [[ "${{ inputs.os }}" == "ubuntu-latest" ]]; then
sudo ./build_tools/before_all_linux.sh
if [[ "${{ runner.os }}" == "Linux" ]]; then
sudo ./build_tools/before_all_linux.sh
elif [[ "${{ runner.os }}" == "macOS" ]]; then
./build_tools/before_all_mac.sh
elif [[ "${{ runner.os }}" == "Windows" ]]; then
./build_tools/before_all_windows.sh
else
./build_tools/before_all_mac.sh
fi
echo "Unrecognized OS: '${{ inputs.os }}'."
exit 1
fi
23 changes: 19 additions & 4 deletions .github/actions/setup-piqtree/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,24 @@ runs:
- uses: "actions/setup-python@v5"
with:
python-version: ${{ inputs.python-version }}

- uses: actions/cache/restore@v4

- name: Cache IQ-TREE 2 (Windows)
if: runner.os == 'Windows'
uses: actions/cache/restore@v4
id: cache-windows
with:
key: ${{ inputs.cache-key }}
path: src/piqtree/_libiqtree/libiqtree2.a
fail-on-cache-miss: true
path: |
src/piqtree/_libiqtree/iqtree2.lib
src/piqtree/_libiqtree/iqtree2.dll
fail-on-cache-miss: true

- name: Cache IQ-TREE 2 (Linux/macOS)
if: runner.os != 'Windows'
uses: actions/cache/restore@v4
id: cache-unix
with:
key: ${{ inputs.cache-key }}
path: |
src/piqtree/_libiqtree/libiqtree2.a
fail-on-cache-miss: true
24 changes: 22 additions & 2 deletions .github/workflows/build_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
fail-fast: false
matrix:
include:
# manylinux (x86)
# manylinux x86_64
- os: ubuntu-latest
platform_id: manylinux_x86_64

Expand All @@ -22,6 +22,10 @@ jobs:
- os: macos-14
platform_id: macosx_arm64

# Windows x86_64
- os: windows-latest
platform_id: win_amd64

steps:
- uses: "actions/checkout@v4"
with:
Expand All @@ -35,21 +39,37 @@ jobs:
platforms: arm64

- name: Set macOS Deployment Target
if: ${{startsWith(matrix.os, 'macos')}}
if: runner.os == 'macOS'
run: |
if [[ "${{ matrix.os }}" == "macos-13" ]]; then
echo "MACOSX_DEPLOYMENT_TARGET=13.0" >> $GITHUB_ENV
elif [[ "${{ matrix.os }}" == "macos-14" ]]; then
echo "MACOSX_DEPLOYMENT_TARGET=14.0" >> $GITHUB_ENV
fi

- name: Install Boost
if: runner.os == 'Windows'
uses: MarkusJx/[email protected]
id: install-boost
with:
boost_version: 1.84.0
platform_version: 2022
toolset: mingw

- name: Setup MSVC Developer Command Prompt
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1

- name: Build wheels
uses: pypa/[email protected]
env: # Can specify per os - e.g. CIBW_BEFORE_ALL_LINUX, CIBW_BEFORE_ALL_MACOS, CIBW_BEFORE_ALL_WINDOWS
CIBW_BEFORE_ALL_LINUX: ./build_tools/before_all_linux.sh
CIBW_BEFORE_ALL_MACOS: ./build_tools/before_all_mac.sh
CIBW_BEFORE_ALL_WINDOWS: bash ./build_tools/before_all_windows.sh
CIBW_ENVIRONMENT_WINDOWS: Boost_INCLUDE_DIR='${{ steps.install-boost.outputs.BOOST_ROOT }}/include' Boost_LIBRARY_DIRS='${{ steps.install-boost.outputs.BOOST_ROOT }}/lib'
CIBW_ARCHS_LINUX: ${{endsWith(matrix.platform_id, '_x86_64') && 'x86_64' || 'aarch64'}}
CIBW_ARCHS_MACOS: ${{endsWith(matrix.platform_id, 'universal2') && 'universal2' || 'auto'}}
CIBW_ARCHS_WINDOWS: ${{endsWith(matrix.platform_id, '_amd64') && 'AMD64' || 'ARM64'}}
CIBW_BUILD: "*${{matrix.platform_id}}"
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
Expand Down
13 changes: 9 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-13, macos-14] # Intel linux, Intel Mac, ARM Mac
os: [ubuntu-latest, macos-13, macos-14, windows-latest] # Intel linux, Intel Mac, ARM Mac, Windows

steps:
- uses: "actions/checkout@v4"
Expand All @@ -35,7 +35,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-13, macos-14] # Intel linux, Intel Mac, ARM Mac
os: [ubuntu-latest, macos-13, macos-14, windows-latest] # Intel linux, Intel Mac, ARM Mac, Windows
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: "actions/checkout@v4"
Expand All @@ -48,10 +48,15 @@ jobs:
python-version: ${{ matrix.python-version }}
cache-key: libiqtree-${{ matrix.os }}-${{ needs.build-iqtree.outputs.iqtree2-sha }}

- name: Install llvm
if: matrix.os != 'ubuntu-latest'
- name: Install llvm (macOS)
if: runner.os == 'macOS'
run: |
brew install llvm

- name: Install llvm (Windows)
if: runner.os == 'Windows'
run: |
choco install -y llvm --version=14.0.6 --allow-downgrade

- name: Run Nox Testing
run: |
Expand Down
28 changes: 25 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
fail-fast: false
matrix:
include:
# manylinux (x86)
# manylinux x86_64
- os: ubuntu-latest
platform_id: manylinux_x86_64

Expand All @@ -22,6 +22,10 @@ jobs:
- os: macos-14
platform_id: macosx_arm64

# Windows x86_64
- os: windows-latest
platform_id: win_amd64

steps:
- uses: "actions/checkout@v4"
with:
Expand All @@ -35,23 +39,41 @@ jobs:
platforms: arm64

- name: Set macOS Deployment Target
if: ${{startsWith(matrix.os, 'macos')}}
if: runner.os == 'macOS'
run: |
if [[ "${{ matrix.os }}" == "macos-13" ]]; then
echo "MACOSX_DEPLOYMENT_TARGET=13.0" >> $GITHUB_ENV
elif [[ "${{ matrix.os }}" == "macos-14" ]]; then
echo "MACOSX_DEPLOYMENT_TARGET=14.0" >> $GITHUB_ENV
fi


- name: Install Boost
if: runner.os == 'Windows'
uses: MarkusJx/[email protected]
id: install-boost
with:
boost_version: 1.84.0
platform_version: 2022
toolset: mingw

- name: Setup MSVC Developer Command Prompt
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1

- name: Build wheels
uses: pypa/[email protected]
env: # Can specify per os - e.g. CIBW_BEFORE_ALL_LINUX, CIBW_BEFORE_ALL_MACOS, CIBW_BEFORE_ALL_WINDOWS
CIBW_BEFORE_ALL_LINUX: ./build_tools/before_all_linux.sh
CIBW_BEFORE_ALL_MACOS: ./build_tools/before_all_mac.sh
CIBW_BEFORE_ALL_WINDOWS: bash ./build_tools/before_all_windows.sh
CIBW_ENVIRONMENT_WINDOWS: Boost_INCLUDE_DIR='${{ steps.install-boost.outputs.BOOST_ROOT }}/include' Boost_LIBRARY_DIRS='${{ steps.install-boost.outputs.BOOST_ROOT }}/lib'
CIBW_ARCHS_LINUX: ${{endsWith(matrix.platform_id, '_x86_64') && 'x86_64' || 'aarch64'}}
CIBW_ARCHS_MACOS: ${{endsWith(matrix.platform_id, 'universal2') && 'universal2' || 'auto'}}
CIBW_ARCHS_WINDOWS: ${{endsWith(matrix.platform_id, '_amd64') && 'AMD64' || 'ARM64'}}
CIBW_BUILD: "*${{matrix.platform_id}}"
CIBW_TEST_REQUIRES: pytest
CIBW_TEST_COMMAND: pytest {package}/tests
CIBW_TEST_SKIP: "*-macosx_universal2:x86_64" # skip x86 on m1 mac
CIBW_SKIP: pp* # Disable building PyPy wheels on all platforms

- name: Upload wheels
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

# piqtree specific ignores
src/piqtree/_libiqtree/**/*.a
src/piqtree/_libiqtree/**/*.dll
src/piqtree/_libiqtree/**/*.lib
src/*.dll

# docs
data
Expand Down
13 changes: 13 additions & 0 deletions build_tools/before_all_windows.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Install dependencies using choco

export Boost_INCLUDE_DIR=$(echo $Boost_INCLUDE_DIR | sed 's|\\|/|g')
export Boost_LIBRARY_DIRS=$(echo $Boost_LIBRARY_DIRS | sed 's|\\|/|g')

echo "Boost_INCLUDE_DIR: $Boost_INCLUDE_DIR"
echo "Boost_LIBRARY_DIRS: $Boost_LIBRARY_DIRS"

choco install -y llvm --version=14.0.6 --allow-downgrade
choco install -y eigen

# Build IQ-TREE
bash build_tools/build_iqtree.sh
30 changes: 28 additions & 2 deletions build_tools/build_iqtree.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,37 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
echo $CXXFLAGS
cmake -DBUILD_LIB=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..
gmake -j
elif [[ "$OSTYPE" == "msys"* || "$OSTYPE" == "cygwin"* ]]; then
echo "Building for Windows."

if [[ -n "$BOOST_ROOT" ]]; then
export Boost_INCLUDE_DIR="${BOOST_ROOT}"
export Boost_LIBRARY_DIRS="${BOOST_ROOT}"
fi

cmake -G "MinGW Makefiles" \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_FLAGS=--target=x86_64-pc-windows-gnu \
-DCMAKE_CXX_FLAGS=--target=x86_64-pc-windows-gnu \
-DCMAKE_MAKE_PROGRAM=make \
-DBoost_INCLUDE_DIR=$Boost_INCLUDE_DIR \
-DBoost_LIBRARY_DIRS=$Boost_LIBRARY_DIRS \
-DIQTREE_FLAGS="cpp14" \
-DBUILD_LIB=ON \
..
make -j
else
echo "Building for linux."
echo "Building for Linux."
cmake -DBUILD_LIB=ON ..
make -j
fi

cd ../..
mv iqtree2/build/libiqtree2.a src/piqtree/_libiqtree/

if [[ "$OSTYPE" == "darwin"* || "$OSTYPE" == "linux"* ]]; then
mv iqtree2/build/libiqtree2.a src/piqtree/_libiqtree/
elif [[ "$OSTYPE" == "msys"* || "$OSTYPE" == "cygwin"* ]]; then
mv iqtree2/build/iqtree2.lib src/piqtree/_libiqtree/
mv iqtree2/build/iqtree2.dll src/piqtree/_libiqtree/
fi
2 changes: 1 addition & 1 deletion iqtree2
7 changes: 6 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["setuptools >= 61.0", "pybind11 >= 2.12"]
requires = ["setuptools >= 61.0", "pybind11 >= 2.12", "delvewheel >= 1.10"]
build-backend = "setuptools.build_meta"

[project]
Expand Down Expand Up @@ -152,6 +152,11 @@ dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
"src/piqtree/_app/__init__.py" = [
"N801", # apps follow function naming convention
]
"src/piqtree/__init__.py" = [
"E402", # handle DLLs before imports
"PTH118", # os operations for DLL path
"PTH120", # os operations for DLL path
]
"src/piqtree/model/_substitution_model.py" = ["N815"] # use IQ-TREE naming scheme

[tool.ruff.format]
Expand Down
Loading