Skip to content

Commit

Permalink
Merge pull request #1 from colesbury/quansight
Browse files Browse the repository at this point in the history
Support building free-threaded CPython
  • Loading branch information
andfoy authored Nov 5, 2024
2 parents 7069021 + 7bbe2dd commit d84df7e
Show file tree
Hide file tree
Showing 17 changed files with 405 additions and 39 deletions.
68 changes: 43 additions & 25 deletions .github/workflows/build-python-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@ on:
inputs:
VERSION:
description: 'Python version to build and upload'
default: '3.12.3'
default: '3.13.0'
required: true
PUBLISH_RELEASES:
description: 'Whether to publish releases'
required: true
type: boolean
default: false
THREADING_BUILD_MODES:
description: 'CPython threading build modes'
required: true
type: str
default: 'freethreaded'
PLATFORMS:
description: 'Platforms for execution in "os" or "os_arch" format (arch is "x64" by default)'
required: true
default: 'ubuntu-20.04,ubuntu-22.04,ubuntu-22.04_arm64,ubuntu-24.04,ubuntu-24.04_arm64,macos-13_x64,macos-14_arm64,windows-2019_x64,windows-2019_x86,windows-2019_arm64'
default: 'ubuntu-20.04,ubuntu-22.04,ubuntu-24.04,macos-13_x64,macos-14_arm64,windows-2019_x64,windows-2019_x86'
pull_request:
paths-ignore:
- 'versions-manifest.json'
Expand All @@ -40,32 +45,42 @@ jobs:
id: generate-matrix
run: |
[String[]]$configurations = "${{ inputs.platforms || 'ubuntu-20.04,ubuntu-22.04,ubuntu-22.04_arm64,ubuntu-24.04,ubuntu-24.04_arm64,macos-13,macos-14_arm64,windows-2019_x64,windows-2019_x86,windows-2019_arm64' }}".Split(",").Trim()
[String[]]$buildModes = "${{ inputs.threading_build_modes || 'default' }}".Split(",").Trim()
$matrix = @()
foreach ($configuration in $configurations) {
$parts = $configuration.Split("_")
$os = $parts[0]
$arch = if ($parts[1]) {$parts[1]} else {"x64"}
switch -wildcard ($os) {
"*ubuntu*" { $platform = $os.Replace("ubuntu","linux")}
"*macos*" { $platform = 'darwin' }
"*windows*" { $platform = 'win32' }
}
if ($configuration -eq "ubuntu-22.04_arm64") {
$os = "setup-actions-ubuntu-arm64-2-core"
}
elseif ($configuration -eq "ubuntu-24.04_arm64") {
$os = "setup-actions-ubuntu24-arm64-2-core"
}
elseif ($configuration -eq "windows-2019_arm64") {
$os = "setup-actions-windows-arm64-4-core"
}
$matrix += @{
'platform' = $platform
'os' = $os
'arch' = $arch
foreach ($buildMode in $buildModes) {
$parts = $configuration.Split("_")
$os = $parts[0]
$arch = if ($parts[1]) {$parts[1]} else {"x64"}
switch -wildcard ($os) {
"*ubuntu*" { $platform = $os.Replace("ubuntu","linux")}
"*macos*" { $platform = 'darwin' }
"*windows*" { $platform = 'win32' }
}
if ($configuration -eq "ubuntu-22.04_arm64") {
$os = "setup-actions-ubuntu-arm64-2-core"
}
elseif ($configuration -eq "ubuntu-24.04_arm64") {
$os = "setup-actions-ubuntu24-arm64-2-core"
}
elseif ($configuration -eq "windows-2019_arm64") {
$os = "setup-actions-windows-arm64-4-core"
}
if ($buildMode -eq "freethreaded") {
if ([semver]"${{ inputs.VERSION }}" -lt [semver]"3.13.0") {
continue;
}
$arch += "-freethreaded"
}
$matrix += @{
'platform' = $platform
'os' = $os
'arch' = $arch
}
}
}
echo "matrix=$($matrix | ConvertTo-Json -Compress -AsArray)" >> $env:GITHUB_OUTPUT
Expand Down Expand Up @@ -201,6 +216,9 @@ jobs:
python-version: ${{ env.VERSION }}
architecture: ${{ matrix.arch }}

- name: Python version
run: python -VVV

- name: Verbose sysconfig dump
if: runner.os == 'Linux' || runner.os == 'macOS'
run: python ./sources/python-config-output.py
Expand Down
43 changes: 43 additions & 0 deletions .github/workflows/create-pr-to-update-manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# This reusable workflow is used by actions/*-versions repositories
# It is designed to create a PR with update of versions-manifest.json when a new release is published
# The GITHUB_TOKEN secret is used to create versions-manifest.json and publish related PR

name: Create Pull Request (called indirectly)
on:
workflow_call:
inputs:
tool-name:
description: 'Name of the tool for which PR is created'
required: true
type: string

defaults:
run:
shell: pwsh

jobs:
create_pr:
name: Create Pull Request
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: true

- name: Create versions-manifest.json
run: |
./nogil-helpers/manifest-generator.ps1 -RepositoryFullName "$env:GITHUB_REPOSITORY" `
-GitHubAccessToken "${{ secrets.GITHUB_TOKEN }}" `
-OutputFile "./versions-manifest.json" `
-ConfigurationFile "./config/${{ inputs.tool-name }}-manifest-config.json"
- name: Create GitHub PR
run: |
$formattedDate = Get-Date -Format "MM/dd/yyyy"
./helpers/github/create-pull-request.ps1 `
-RepositoryFullName "$env:GITHUB_REPOSITORY" `
-AccessToken "${{ secrets.GITHUB_TOKEN }}" `
-BranchName "update-versions-manifest-file" `
-CommitMessage "Update versions-manifest" `
-PullRequestTitle "[versions-manifest] Update for release from ${formattedDate}" `
-PullRequestBody "Update versions-manifest.json for release from ${formattedDate}"
2 changes: 1 addition & 1 deletion .github/workflows/create-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:

jobs:
create-pr:
uses: actions/versions-package-tools/.github/workflows/create-pr-to-update-manifest.yml@main
uses: ./.github/workflows/create-pr-to-update-manifest.yml
with:
tool-name: "python"
secrets: inherit
33 changes: 33 additions & 0 deletions builders/macos-python-builder.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,37 @@ class macOSPythonBuilder : NixPythonBuilder {
return $pkgLocation
}

[string] GetFrameworkName() {
<#
.SYNOPSIS
Get the Python installation Package name.
#>

if ($this.IsFreeThreaded()) {
return "PythonT.framework"
} else {
return "Python.framework"
}
}

[string] GetPkgChoices() {
<#
.SYNOPSIS
Reads the configuration XML file for the Python installer
#>

$config = if ($this.IsFreeThreaded()) { "freethreaded" } else { "default" }
$choicesFile = Join-Path $PSScriptRoot "../config/macos-pkg-choices-$($config).xml"
$choicesTemplate = Get-Content -Path $choicesFile -Raw

$variablesToReplace = @{
"{{__VERSION_MAJOR_MINOR__}}" = "$($this.Version.Major).$($this.Version.Minor)";
}

$variablesToReplace.keys | ForEach-Object { $choicesTemplate = $choicesTemplate.Replace($_, $variablesToReplace[$_]) }
return $choicesTemplate
}

[void] CreateInstallationScriptPkg() {
<#
.SYNOPSIS
Expand All @@ -165,6 +196,8 @@ class macOSPythonBuilder : NixPythonBuilder {
"{{__VERSION_FULL__}}" = $this.Version;
"{{__PKG_NAME__}}" = $this.GetPkgName();
"{{__ARCH__}}" = $this.Architecture;
"{{__FRAMEWORK_NAME__}}" = $this.GetFrameworkName();
"{{__PKG_CHOICES__}}" = $this.GetPkgChoices();
}

$variablesToReplace.keys | ForEach-Object { $installationTemplateContent = $installationTemplateContent.Replace($_, $variablesToReplace[$_]) }
Expand Down
2 changes: 1 addition & 1 deletion builders/nix-python-builder.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class NixPythonBuilder : PythonBuilder {
Write-Debug "make Python $($this.Version)-$($this.Architecture) $($this.Platform)"
$buildOutputLocation = New-Item -Path $this.WorkFolderLocation -Name "build_output.txt" -ItemType File

Execute-Command -Command "make 2>&1 | tee $buildOutputLocation" -ErrorAction Continue
Execute-Command -Command "make 2>&1 | tee $buildOutputLocation" -ErrorAction Continue
Execute-Command -Command "make install" -ErrorAction Continue

Write-Debug "Done; Make log location: $buildOutputLocation"
Expand Down
18 changes: 18 additions & 0 deletions builders/python-builder.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,24 @@ class PythonBuilder {
return "$($this.Version.Major).$($this.Version.Minor).$($this.Version.Patch)"
}

[string] GetHardwareArchitecture() {
<#
.SYNOPSIS
The hardware architecture (x64, arm64) without any Python free threading suffix.
#>

return $this.Architecture.Replace("-freethreaded", "")
}

[bool] IsFreeThreaded() {
<#
.SYNOPSIS
Check if Python version is free threaded.
#>

return $this.Architecture.EndsWith("-freethreaded")
}

[void] PreparePythonToolcacheLocation() {
<#
.SYNOPSIS
Expand Down
8 changes: 8 additions & 0 deletions builders/ubuntu-python-builder.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ class UbuntuPythonBuilder : NixPythonBuilder {
$configureString += " --enable-shared"
$configureString += " --enable-optimizations"

if ($this.IsFreeThreaded()) {
if ($this.Version -lt "3.13.0") {
Write-Host "Python versions lower than 3.13.0 do not support free threading"
exit 1
}
$configureString += " --disable-gil"
}

### Compile with support of loadable sqlite extensions.
### Link to documentation (https://docs.python.org/3/library/sqlite3.html#sqlite3.Connection.enable_load_extension)
$configureString += " --enable-loadable-sqlite-extensions"
Expand Down
5 changes: 3 additions & 2 deletions builders/win-python-builder.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ class WinPythonBuilder : PythonBuilder {
#>

$ArchitectureExtension = ""
if ($this.Architecture -eq "x64") {
if ($this.GetHardwareArchitecture() -eq "x64") {
if ($this.Version -ge "3.5") {
$ArchitectureExtension = "-amd64"
} else {
$ArchitectureExtension = ".amd64"
}
}elseif ($this.Architecture -eq "arm64") {
} elseif ($this.GetHardwareArchitecture() -eq "arm64") {
$ArchitectureExtension = "-arm64"
}

Expand Down Expand Up @@ -113,6 +113,7 @@ class WinPythonBuilder : PythonBuilder {

$variablesToReplace = @{
"{{__ARCHITECTURE__}}" = $this.Architecture;
"{{__HARDWARE_ARCHITECTURE__}}" = $this.GetHardwareArchitecture();
"{{__VERSION__}}" = $this.Version;
"{{__PYTHON_EXEC_NAME__}}" = $pythonExecName
}
Expand Down
8 changes: 8 additions & 0 deletions config/macos-pkg-choices-default.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
</dict>
</array>
</plist>
14 changes: 14 additions & 0 deletions config/macos-pkg-choices-freethreaded.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<array>
<dict>
<key>attributeSetting</key>
<integer>1</integer>
<key>choiceAttribute</key>
<string>selected</string>
<key>choiceIdentifier</key>
<string>org.python.Python.PythonTFramework-{{__VERSION_MAJOR_MINOR__}}</string>
</dict>
</array>
</plist>
2 changes: 1 addition & 1 deletion config/python-manifest-config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"regex": "python-\\d+\\.\\d+\\.\\d+-(\\w+\\.\\d+)?-?(\\w+)-(\\d+\\.\\d+)?-?((x|arm)\\d+)",
"regex": "python-\\d+\\.\\d+\\.\\d+-(\\w+\\.\\d+)?-?(\\w+)-(\\d+\\.\\d+)?-?((x|arm)\\d+(-freethreaded)?)",
"groups": {
"arch": 4,
"platform": 2,
Expand Down
20 changes: 17 additions & 3 deletions installers/macos-pkg-setup-template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ set -e

PYTHON_FULL_VERSION="{{__VERSION_FULL__}}"
PYTHON_PKG_NAME="{{__PKG_NAME__}}"
PYTHON_FRAMEWORK_NAME="{{__FRAMEWORK_NAME__}}"
PYTHON_PKG_CHOICES=$(cat << 'EOF'
{{__PKG_CHOICES__}}
EOF
)
ARCH="{{__ARCH__}}"
MAJOR_VERSION=$(echo $PYTHON_FULL_VERSION | cut -d '.' -f 1)
MINOR_VERSION=$(echo $PYTHON_FULL_VERSION | cut -d '.' -f 2)
Expand All @@ -20,7 +25,7 @@ fi
PYTHON_TOOLCACHE_PATH=$TOOLCACHE_ROOT/Python
PYTHON_TOOLCACHE_VERSION_PATH=$PYTHON_TOOLCACHE_PATH/$PYTHON_FULL_VERSION
PYTHON_TOOLCACHE_VERSION_ARCH_PATH=$PYTHON_TOOLCACHE_VERSION_PATH/$ARCH
PYTHON_FRAMEWORK_PATH="/Library/Frameworks/Python.framework/Versions/${MAJOR_VERSION}.${MINOR_VERSION}"
PYTHON_FRAMEWORK_PATH="/Library/Frameworks/${PYTHON_FRAMEWORK_NAME}/Versions/${MAJOR_VERSION}.${MINOR_VERSION}"
PYTHON_APPLICATION_PATH="/Applications/Python ${MAJOR_VERSION}.${MINOR_VERSION}"

echo "Check if Python hostedtoolcache folder exist..."
Expand All @@ -38,8 +43,11 @@ else
done
fi

PYTHON_PKG_CHOICES_FILES=$(mktemp)
echo "$PYTHON_PKG_CHOICES" > $PYTHON_PKG_CHOICES_FILES

echo "Install Python binaries from prebuilt package"
sudo installer -pkg $PYTHON_PKG_NAME -target /
sudo installer -pkg $PYTHON_PKG_NAME -applyChoiceChangesXML $PYTHON_PKG_CHOICES_FILES -target /

echo "Create hostedtoolcach symlinks (Required for the backward compatibility)"
echo "Create Python $PYTHON_FULL_VERSION folder"
Expand All @@ -53,7 +61,9 @@ ln -s "${PYTHON_FRAMEWORK_PATH}/lib" lib

echo "Create additional symlinks (Required for the UsePythonVersion Azure Pipelines task and the setup-python GitHub Action)"
ln -s ./bin/$PYTHON_MAJOR_DOT_MINOR python
chmod +x python

# Note that bin is a symlink so referencing .. from bin will not work as expected
cd bin/

# This symlink already exists if Python version with the same major.minor version is installed,
Expand All @@ -62,11 +72,15 @@ if [ ! -f $PYTHON_MAJOR_MINOR ]; then
ln -s $PYTHON_MAJOR_DOT_MINOR $PYTHON_MAJOR_MINOR
fi

if [ ! -f $PYTHON_MAJOR ]; then
ln -s $PYTHON_MAJOR_DOT_MINOR $PYTHON_MAJOR
fi

if [ ! -f python ]; then
ln -s $PYTHON_MAJOR_DOT_MINOR python
fi

chmod +x ../python $PYTHON_MAJOR $PYTHON_MAJOR_DOT_MINOR $PYTHON_MAJOR_MINOR python
chmod +x $PYTHON_MAJOR $PYTHON_MAJOR_DOT_MINOR $PYTHON_MAJOR_MINOR python

echo "Upgrading pip..."
export PIP_ROOT_USER_ACTION=ignore
Expand Down
Loading

0 comments on commit d84df7e

Please sign in to comment.