-
Notifications
You must be signed in to change notification settings - Fork 16
Refactor Windows on ARM build script #193
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
Changes from 7 commits
4519ac1
6db66ce
96da14b
4337ce5
6845b50
7dd7a74
08f09df
25cf4f6
4cd205d
3a2752e
472f034
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
name: Windows-on-ARM | ||
|
||
on: | ||
push: | ||
branches: [ main ] | ||
pull_request: | ||
branches: [ main ] | ||
|
||
env: | ||
OPENBLAS_COMMIT: "v0.3.29" | ||
OPENBLAS_ROOT: "c:\\opt" | ||
# Preserve working directory for calls into bash | ||
# Without this, invoking bash will cd to the home directory | ||
CHERE_INVOKING: "yes" | ||
BASH_PATH: "C:\\Program Files\\Git\\bin\\bash.exe" | ||
PLAT: arm64 | ||
INTERFACE64: 0 | ||
BUILD_BITS: 32 | ||
|
||
jobs: | ||
build: | ||
runs-on: windows-11-arm | ||
timeout-minutes: 90 | ||
|
||
steps: | ||
|
||
- uses: actions/[email protected] | ||
|
||
- name: Set up Python | ||
uses: actions/setup-python@v5 | ||
with: | ||
python-version: 3.12 | ||
architecture: arm64 | ||
|
||
- name: Setup visual studio | ||
uses: microsoft/setup-msbuild@v2 | ||
|
||
- name: Download, install 7zip. | ||
run: | | ||
Invoke-WebRequest https://www.7-zip.org/a/7z2409-arm64.exe -UseBasicParsing -OutFile 7z_arm.exe | ||
Start-Process -FilePath ".\7z_arm.exe" -ArgumentList "/S" -Wait | ||
echo "C:\Program Files\7-Zip" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | ||
|
||
- name: Download and install LLVM installer | ||
run: | | ||
Invoke-WebRequest https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.5/LLVM-19.1.5-woa64.exe -UseBasicParsing -OutFile LLVM-woa64.exe | ||
Start-Process -FilePath ".\LLVM-woa64.exe" -ArgumentList "/S" -Wait | ||
echo "C:\Program Files\LLVM\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | ||
|
||
- name: Update CMake for WoA | ||
run: | | ||
pip install cmake | ||
get-command cmake | ||
|
||
- name: Build | ||
run: | | ||
git submodule update --init --recursive | ||
.\tools\build_steps_win_arm64.bat | ||
|
||
- name: Pack | ||
run: | | ||
cd local | ||
cp -r "scipy_openblas${env:BUILD_BITS}" $env:BUILD_BITS | ||
7z a ../builds/openblas-${env:PLAT}-${env:INTERFACE64}.zip -tzip $env:BUILD_BITS | ||
|
||
- name: Test 32-bit interface wheel | ||
run: | | ||
python -m pip install --no-index --find-links dist scipy_openblas32 | ||
python -m scipy_openblas32 | ||
python -c "import scipy_openblas32; print(scipy_openblas32.get_pkg_config())" | ||
|
||
- uses: actions/[email protected] | ||
with: | ||
name: wheels-${{ env.PLAT }}-${{ env.INTERFACE64 }} | ||
path: dist/scipy_openblas*.whl | ||
|
||
- uses: actions/[email protected] | ||
with: | ||
name: openblas-${{ env.PLAT }}-${{ env.INTERFACE64 }} | ||
path: builds/openblas*.zip | ||
|
||
- name: Install Anaconda client | ||
run: | | ||
Invoke-WebRequest https://static.rust-lang.org/rustup/dist/aarch64-pc-windows-msvc/rustup-init.exe -UseBasicParsing -Outfile rustup-init.exe | ||
.\rustup-init.exe -y | ||
$env:PATH="$env:PATH;$env:USERPROFILE\.cargo\bin" | ||
pip install anaconda-client | ||
|
||
- name: Upload | ||
# see https://github.com/marketplace/actions/setup-miniconda for why | ||
# `-el {0}` is required. | ||
shell: bash -el {0} | ||
env: | ||
ANACONDA_SCIENTIFIC_PYTHON_UPLOAD: ${{ secrets.ANACONDA_SCIENTIFIC_PYTHON_UPLOAD }} | ||
run: | | ||
source tools/upload_to_anaconda_staging.sh | ||
upload_wheels |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,52 +1,83 @@ | ||
:: Build script for scipy_openblas wheel on Windows on ARM64 | ||
|
||
:: Usage: build_steps_win_arm64.bat [build_bits] | ||
:: e.g build_steps_win_arm64.bat 64 | ||
:: Usage: build_steps_win_arm64.bat [build_bits] [if_bits] | ||
:: e.g build_steps_win_arm64.bat 64 64 | ||
|
||
:: BUILD_BITS (default binary architecture, 32 or 64, unspec -> 64). | ||
:: build_bits (default binary architecture, 32 or 64, unspec -> 64). | ||
:: if_bits (default interface size, 32 or 64, unspec -> 32) | ||
:: If INTERFACE64 environment variable is 1, then if_bits defaults to 64 | ||
:: Expects these binaries on the PATH: | ||
:: clang-cl, flang-new, cmake, perl | ||
|
||
:: First commit containing WoA build fixes. | ||
:: Minimum OpenBLAS commit to build; we'll update to this if commit not | ||
:: present. | ||
set first_woa_buildable_commit="de2380e5a6149706a633322a16a0f66faa5591fc" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we in a position to update the submodule OpenBLAS to some commit that contains the WoA build updates as above? Otherwise - what should we do with the noted version if we have to do the update above? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not at the moment — we'll update the submodule once the SUFFIX64_UNDERSCORE issue is fixed upstream. That way, we produce the correct libname for 64-bit interface builds as scipy_openblas64_. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Harishmcw - yes, we do not use a compatible OpenBLAS at the moment, but the question was whether we could update to one as part of this change. Otherwise, I guess we could cherry-pick the build changes, so that the user would get the right version (e.g. v0.3.29) in terms of execution results. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The current OpenBLAS submodule commit we're using already includes all the Win ARM64-related changes, so no update is needed at this point. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Harishmcw - if you look at the code in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is fine to change the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @mattip - any preference for the newer (post WoA fixes) commit? Current And then we can change the logic to error if the OpenBLAS commit doesn't contain the WoA fixes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any commit is fine, as long as the first fields of the version matches There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated to the current HEAD of the OpenBLAS |
||
|
||
@echo off | ||
setlocal enabledelayedexpansion | ||
|
||
if "%1"=="" ( | ||
set BUILD_BIT=64 | ||
set build_bits=64 | ||
) else ( | ||
set build_bits=%1 | ||
) | ||
if "%INTERFACE64%"=="1" ( | ||
set "if_default=64" | ||
) else ( | ||
set "if_default=32" | ||
) | ||
if "%2"=="" ( | ||
set "if_bits=%if_default%" | ||
) else ( | ||
set BUILD_BIT=%1 | ||
set "if_bits=%2" | ||
) | ||
echo Building for %BUILD_BIT%-bit configuration... | ||
echo Building for %build_bits%-bit configuration... | ||
|
||
:: Define destination directory | ||
move "..\local\scipy_openblas64" "..\local\scipy_openblas32" | ||
set "DEST_DIR=%CD%\..\local\scipy_openblas32" | ||
cd .. | ||
|
||
:: Check if 'openblas' folder exists and is empty | ||
if exist "openblas" ( | ||
dir /b "openblas" | findstr . >nul | ||
if errorlevel 1 ( | ||
echo OpenBLAS folder exists but is empty. Deleting and recloning... | ||
rmdir /s /q "openblas" | ||
pushd "%~dp0\.." | ||
set "ob_out_root=%CD%\local\scipy_openblas" | ||
set "ob_64=%ob_out_root%64" | ||
set "ob_32=%ob_out_root%32" | ||
set "local_dir=%CD%\local" | ||
for /d %%D in ("%local_dir%\*") do ( | ||
if /I not "%%~nxD"=="scipy_openblas64" ( | ||
rmdir /S /Q "%%D" | ||
) | ||
) | ||
|
||
:: Clone OpenBLAS if not present | ||
if not exist "openblas" ( | ||
echo Cloning OpenBLAS repository with submodules... | ||
git clone --recursive https://github.com/OpenMathLib/OpenBLAS.git OpenBLAS | ||
if errorlevel 1 exit /b 1 | ||
if "%if_bits%"=="64" ( | ||
set "DEST_DIR=%ob_64%" | ||
) else ( | ||
if exist "%ob_64%" ( | ||
xcopy /Y /H "%ob_64%\*.py" "%CD%\ob64_backup\" | ||
move "%ob_64%" "%ob_32%" | ||
set "DEST_DIR=%ob_32%" | ||
) | ||
) | ||
|
||
:: Clone OpenBLAS | ||
echo Cloning OpenBLAS repository with submodules... | ||
git submodule update --init --recursive OpenBLAS | ||
if errorlevel 1 exit /b 1 | ||
|
||
:: Enter OpenBLAS directory and checkout develop branch | ||
cd openblas | ||
git checkout develop | ||
|
||
echo Checked out to the latest branch of OpenBLAS. | ||
:: Enter OpenBLAS directory and checkout buildable commit | ||
cd OpenBLAS | ||
git merge-base --is-ancestor %first_woa_buildable_commit% HEAD 2>NUL | ||
if errorlevel 1 ( | ||
echo Updating to WoA buildable commit for OpenBLAS | ||
git checkout %first_woa_buildable_commit% | ||
) | ||
|
||
:: Set suffixed-ILP64 flags | ||
if "%if_bits%"=="64" ( | ||
set "interface_flags=-DINTERFACE64=1 -DSYMBOLSUFFIX=64_" | ||
) else ( | ||
set "interface_flags=" | ||
) | ||
|
||
:: Create build directory and navigate to it | ||
if not exist build mkdir build | ||
cd build | ||
if exist build (rmdir /S /Q build || exit /b 1) | ||
mkdir build || exit /b 1 & cd build || exit /b 1 | ||
|
||
echo Setting up ARM64 Developer Command Prompt and running CMake... | ||
|
||
|
@@ -55,36 +86,42 @@ for /f "usebackq tokens=*" %%i in (`"C:\Program Files (x86)\Microsoft Visual Stu | |
|
||
:: Run CMake and Ninja build | ||
cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release -DTARGET=ARMV8 -DBUILD_SHARED_LIBS=ON -DARCH=arm64 ^ | ||
-DBINARY=%BUILD_BIT% -DCMAKE_SYSTEM_PROCESSOR=ARM64 -DCMAKE_C_COMPILER=clang-cl ^ | ||
-DCMAKE_Fortran_COMPILER=flang-new -DSYMBOLPREFIX="scipy_" -DLIBNAMEPREFIX="scipy_" | ||
-DBINARY=%build_bits% -DCMAKE_SYSTEM_PROCESSOR=ARM64 -DCMAKE_C_COMPILER=clang-cl ^ | ||
-DCMAKE_Fortran_COMPILER=flang-new -DSYMBOLPREFIX="scipy_" -DLIBNAMEPREFIX="scipy_" %interface_flags% | ||
if errorlevel 1 exit /b 1 | ||
|
||
ninja | ||
if errorlevel 1 exit /b 1 | ||
|
||
echo Build complete. Returning to Batch. | ||
|
||
:: Rewrite the name of the project to scipy-openblas32 | ||
echo Rewrite to scipy_openblas32 | ||
cd ../.. | ||
powershell -Command "(Get-Content 'pyproject.toml') -replace 'openblas64', 'openblas32' | Set-Content 'pyproject.toml'" | ||
powershell -Command "(Get-Content 'local\scipy_openblas32\__main__.py') -replace 'openblas64', 'openblas32' | Out-File 'local\scipy_openblas32\__main__.py' -Encoding utf8" | ||
powershell -Command "(Get-Content 'local\scipy_openblas32\__init__.py') -replace 'openblas64', 'openblas32' | Out-File 'local\scipy_openblas32\__init__.py' -Encoding utf8" | ||
powershell -Command "(Get-Content 'local\scipy_openblas32\__init__.py') -replace 'openblas_get_config64_', 'openblas_get_config' | Out-File 'local\scipy_openblas32\__init__.py' -Encoding utf8" | ||
powershell -Command "(Get-Content 'local\scipy_openblas32\__init__.py') -replace 'cflags =.*', 'cflags = \"-DBLAS_SYMBOL_PREFIX=scipy_\"' | Out-File 'local\scipy_openblas32\__init__.py' -Encoding utf8" | ||
if "%if_bits%"=="32" ( | ||
echo Rewrite to scipy_openblas32 | ||
cd ../.. | ||
set out_pyproject=pyproject_64_32.toml | ||
powershell -Command "(Get-Content 'pyproject.toml') -replace 'openblas64', 'openblas32' | Set-Content !out_pyproject!" | ||
powershell -Command "(Get-Content 'local\scipy_openblas32\__main__.py') -replace 'openblas64', 'openblas32' | Out-File 'local\scipy_openblas32\__main__.py' -Encoding utf8" | ||
powershell -Command "(Get-Content 'local\scipy_openblas32\__init__.py') -replace 'openblas64', 'openblas32' | Out-File 'local\scipy_openblas32\__init__.py' -Encoding utf8" | ||
powershell -Command "(Get-Content 'local\scipy_openblas32\__init__.py') -replace 'openblas_get_config64_', 'openblas_get_config' | Out-File 'local\scipy_openblas32\__init__.py' -Encoding utf8" | ||
powershell -Command "(Get-Content 'local\scipy_openblas32\__init__.py') -replace 'cflags =.*', 'cflags = \"-DBLAS_SYMBOL_PREFIX=scipy_\"' | Out-File 'local\scipy_openblas32\__init__.py' -Encoding utf8" | ||
) | ||
|
||
:: Prepare destination directory | ||
cd OpenBLAS/build | ||
echo Preparing destination directory at %DEST_DIR%... | ||
if not exist "%DEST_DIR%\lib\cmake\openblas" mkdir "%DEST_DIR%\lib\cmake\openblas" | ||
if not exist "%DEST_DIR%\lib\cmake\OpenBLAS" mkdir "%DEST_DIR%\lib\cmake\OpenBLAS" | ||
if not exist "%DEST_DIR%\include" mkdir "%DEST_DIR%\include" | ||
|
||
:: Move library files | ||
echo Moving library files... | ||
if exist lib\release ( | ||
move /Y lib\release\*.dll "%DEST_DIR%\lib\" | ||
if errorlevel 1 exit /b 1 | ||
move /Y lib\release\*.dll.a "%DEST_DIR%\lib\scipy_openblas.lib" | ||
for %%f in (lib\release\*.dll.a) do ( | ||
set "orig_name=%%~nxf" | ||
call set "base_name=%%orig_name:.dll.a=%%" | ||
move /Y "%%f" "%DEST_DIR%\lib\!base_name!.lib" | ||
) | ||
if errorlevel 1 exit /b 1 | ||
) else ( | ||
echo Error: lib/release directory not found! | ||
|
@@ -99,7 +136,7 @@ if exist openblasconfigversion.cmake copy /Y openblasconfigversion.cmake "%DEST_ | |
:: Copy header files | ||
echo Copying generated header files... | ||
if exist generated xcopy /E /Y generated "%DEST_DIR%\include\" | ||
if exist lapacke_mangling copy /Y lapacke_mangling "%DEST_DIR%\include\" | ||
if exist lapacke_mangling.h copy /Y lapacke_mangling.h "%DEST_DIR%\include\" | ||
if exist openblas_config.h copy /Y openblas_config.h "%DEST_DIR%\include\" | ||
|
||
|
||
|
@@ -113,12 +150,32 @@ cd ../.. | |
|
||
:: Build the Wheel & Install It | ||
echo Running 'python -m build' to build the wheel... | ||
python -m build | ||
if errorlevel 1 exit /b 1 | ||
|
||
python -c "import build" 2>NUL || pip install build | ||
if "%if_bits%"=="64" ( | ||
python -m build | ||
if errorlevel 1 exit /b 1 | ||
) else ( | ||
move /Y pyproject.toml pyproject.toml.bak | ||
move /Y %out_pyproject% pyproject.toml | ||
python -m build | ||
if errorlevel 1 exit /b 1 | ||
move /Y pyproject.toml.bak pyproject.toml | ||
) | ||
if "%if_bits%"=="32" ( | ||
move /Y "%CD%\ob64_backup" "%ob_64%" | ||
) | ||
|
||
:: Rename the wheel | ||
for %%f in (dist\*any.whl) do ( | ||
set WHEEL_FILE=dist\%%f | ||
set "filename=%%~nxf" | ||
set "newname=!filename:any.whl=win_arm64.whl!" | ||
ren "dist\!filename!" "!newname!" | ||
) | ||
|
||
:: Locate the built wheel | ||
for /f %%f in ('dir /b dist\scipy_openblas*.whl 2^>nul') do set WHEEL_FILE=dist\%%f | ||
|
||
if not defined WHEEL_FILE ( | ||
echo Error: No wheel file found in dist folder. | ||
exit /b 1 | ||
|
@@ -129,4 +186,4 @@ pip install "%WHEEL_FILE%" | |
if errorlevel 1 exit /b 1 | ||
|
||
echo Done. | ||
exit /b 0 | ||
exit /b 0 |
Uh oh!
There was an error while loading. Please reload this page.