Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
95 changes: 95 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,101 @@ jobs:
python -c "from urllib.request import urlretrieve; urlretrieve('${{ env.BUILDER_HOST }}/${{ env.BUILDER_SOURCE }}/${{ env.BUILDER_VERSION }}/builder.pyz?run=${{ env.RUN }}', 'builder.pyz')"
python builder.pyz build -p ${{ env.PACKAGE_NAME }} --python "${{ steps.python38.outputs.python-path }}"

windows-arm64:
runs-on: windows-11-arm
strategy:
fail-fast: false
matrix:
include:
- build-python: '3.11'
test-python: '3.11'
expected-tag: 'cp311-abi3-win_arm64'
- build-python: '3.11'
test-python: '3.12'
expected-tag: 'cp311-abi3-win_arm64'
- build-python: '3.13'
test-python: '3.13'
expected-tag: 'cp313-abi3-win_arm64'
- build-python: '3.13'
test-python: '3.14'
expected-tag: 'cp313-abi3-win_arm64'
- build-python: '3.13t'
test-python: '3.13t'
expected-tag: 'cp313-cp313t-win_arm64'
- build-python: '3.14t'
test-python: '3.14t'
expected-tag: 'cp314-cp314t-win_arm64'
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.build-python }}
architecture: arm64
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: arm64
- name: Build Windows ARM64 wheel
shell: pwsh
run: |
python -m pip install --upgrade build
python -m build --wheel
$wheel = @(Get-Item "dist\awscrt-*-${{ matrix.expected-tag }}.whl")
$allWheels = @(Get-Item dist\*.whl)
if ($wheel.Count -ne 1 -or $allWheels.Count -ne 1) {
throw 'Expected exactly one wheel with tag ${{ matrix.expected-tag }}'
}
python -c "import sys, zipfile; p=sys.argv[1]; expected='Tag: ' + sys.argv[2]; z=zipfile.ZipFile(p); wheel=z.read(next(n for n in z.namelist() if n.endswith('.dist-info/WHEEL'))).decode().splitlines(); assert expected in wheel, (expected, wheel)" $wheel[0].FullName '${{ matrix.expected-tag }}'
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.test-python }}
architecture: arm64
- name: Test installed wheel
shell: pwsh
env:
AWS_TEST_LOCALHOST: '1'
run: |
python -m venv ..\awscrt-test
$wheel = @(Get-Item "dist\awscrt-*-${{ matrix.expected-tag }}.whl")
if ($wheel.Count -ne 1) {
throw 'Expected exactly one wheel with tag ${{ matrix.expected-tag }}'
}
..\awscrt-test\Scripts\python.exe -m pip install $wheel[0].FullName
..\awscrt-test\Scripts\python.exe -m pip install 'websockets>=13.1' 'h2==4.1.0'
Copy-Item test "$env:RUNNER_TEMP\test" -Recurse
$httpTests = "$env:RUNNER_TEMP\crt\aws-c-http\tests"
New-Item $httpTests -ItemType Directory -Force | Out-Null
Copy-Item crt\aws-c-http\tests\mock_server $httpTests -Recurse
Copy-Item crt\aws-c-http\tests\resources $httpTests -Recurse
Push-Location $env:RUNNER_TEMP
try {
# These tests depend on httpbin.org returning 404, but the service currently returns 503.
$testScript = @(
'import unittest'
"excluded = {'test_aiohttp_client.AIOHttp2RemoteEndStreamTest.test_h2_remote_end_stream_ordering', 'test_http_client.Http2RemoteEndStreamTest.test_h2_remote_end_stream_ordering'}"
'excluded_found = set()'
"discovered = unittest.defaultTestLoader.discover('test')"
'filtered = unittest.TestSuite()'
'def add_tests(suite):'
' for test in suite:'
' if isinstance(test, unittest.TestSuite):'
' add_tests(test)'
' elif test.id() in excluded:'
' excluded_found.add(test.id())'
' else:'
' filtered.addTest(test)'
'add_tests(discovered)'
"if excluded_found != excluded: raise RuntimeError(f'Expected exclusions {excluded}, found {excluded_found}')"
"if filtered.countTestCases() == 0: raise RuntimeError('No tests discovered')"
'result = unittest.TextTestRunner(verbosity=2, failfast=True).run(filtered)'
'raise SystemExit(0 if result.wasSuccessful() else 1)'
) -join "`n"
& "$env:GITHUB_WORKSPACE\..\awscrt-test\Scripts\python.exe" -c $testScript
} finally {
Pop-Location
}

macos:
runs-on: macos-14 # latest
permissions:
Expand Down
37 changes: 37 additions & 0 deletions continuous-delivery/build-wheels-winarm64.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@echo off

if not defined PYTHON311_ARM64 goto missing_python
if not defined PYTHON313_ARM64 goto missing_python
if not defined PYTHON313T_ARM64 goto missing_python
if not defined PYTHON314T_ARM64 goto missing_python

"%PYTHON311_ARM64%" -c "import sys, sysconfig; raise SystemExit(0 if sys.version_info[:2] == (3, 11) and sysconfig.get_platform() == 'win-arm64' and not sysconfig.get_config_var('Py_GIL_DISABLED') else 1)" || goto wrong_python
"%PYTHON313_ARM64%" -c "import sys, sysconfig; raise SystemExit(0 if sys.version_info[:2] == (3, 13) and sysconfig.get_platform() == 'win-arm64' and not sysconfig.get_config_var('Py_GIL_DISABLED') else 1)" || goto wrong_python
"%PYTHON313T_ARM64%" -c "import sys, sysconfig; raise SystemExit(0 if sys.version_info[:2] == (3, 13) and sysconfig.get_platform() == 'win-arm64' and sysconfig.get_config_var('Py_GIL_DISABLED') else 1)" || goto wrong_python
"%PYTHON314T_ARM64%" -c "import sys, sysconfig; raise SystemExit(0 if sys.version_info[:2] == (3, 14) and sysconfig.get_platform() == 'win-arm64' and sysconfig.get_config_var('Py_GIL_DISABLED') else 1)" || goto wrong_python

"%PYTHON313_ARM64%" continuous-delivery\update-version.py || goto error

:: The 3.11 stable ABI wheel also supports Python 3.12.
"%PYTHON311_ARM64%" -m build || goto error

:: Use the 3.13 stable ABI from 3.13 onwards because of deprecated functions.
"%PYTHON313_ARM64%" -m build || goto error

:: Free-threaded builds do not support the Limited C API or stable ABI.
"%PYTHON313T_ARM64%" -m build || goto error
"%PYTHON314T_ARM64%" -m build || goto error

goto :EOF

:missing_python
echo PYTHON311_ARM64, PYTHON313_ARM64, PYTHON313T_ARM64, and PYTHON314T_ARM64 must point to native ARM64 Python executables.
exit /b 1

:wrong_python
echo Configured Python executables must have the expected version, win-arm64 platform, and free-threaded status.
exit /b 1

:error
echo Failed with error #%errorlevel%.
exit /b %errorlevel%
28 changes: 28 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ def is_32bit():
return is_64bit() == False


def is_windows_arm64():
return sys.platform == 'win32' and sysconfig.get_platform() == 'win-arm64'


# TODO: Fix this. Since adding pyproject.toml, it always returns False
def is_development_mode():
"""Return whether we're building in Development Mode (a.k.a. “Editable Installs”).
Expand Down Expand Up @@ -196,6 +200,20 @@ def determine_generator_args(cmake_version=None, windows_sdk_version=None):

print('Using Visual Studio', vs_version, vs_year)

if is_windows_arm64():
if not shutil.which('clang-cl'):
raise RuntimeError('clang-cl is required to build for Windows ARM64')
print('Using Ninja and clang-cl for Windows ARM64')
return [
'-G', 'Ninja',
f'-DCMAKE_SYSTEM_VERSION={windows_sdk_version}',
'-DCMAKE_C_COMPILER=clang-cl',
'-DCMAKE_CXX_COMPILER=clang-cl',
'-DCMAKE_ASM_COMPILER=clang-cl',
# The optimized ARM checksum sources do not compile with clang-cl.
'-DUSE_CPU_EXTENSIONS=OFF',
]

if vs_year <= 2017:
# For VS2017 and earlier, architecture goes at end of generator string
if is_64bit():
Expand Down Expand Up @@ -325,6 +343,16 @@ def __init__(self, name, extra_cmake_args=[], libname=None):


class awscrt_build_ext(setuptools.command.build_ext.build_ext):
def build_extensions(self):
if is_windows_arm64():
if not self.compiler.initialized:
self.compiler.initialize()
clang_cl = shutil.which('clang-cl')
if not clang_cl:
raise RuntimeError('clang-cl is required to build for Windows ARM64')
self.compiler.cc = clang_cl
super().build_extensions()

def _build_dependencies_impl(self, build_dir, install_path, osx_arch=None):
cmake = get_cmake_path()

Expand Down