Skip to content

Commit bfcbb28

Browse files
authored
GH-113464: Get LLVM from cpython-bin-deps on Windows (GH-133278)
1 parent a0bc0c4 commit bfcbb28

File tree

9 files changed

+44
-13
lines changed

9 files changed

+44
-13
lines changed

.github/workflows/jit.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ jobs:
9595
with:
9696
python-version: '3.11'
9797

98+
# PCbuild downloads LLVM automatically:
9899
- name: Windows
99100
if: runner.os == 'Windows'
100101
run: |
101-
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
102102
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
103103
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
104104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Use the cpython-bin-deps "externals" repository for Windows LLVM dependency
2+
management. Installing LLVM manually is no longer necessary for Windows JIT
3+
builds.

PCbuild/build.bat

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ if "%IncludeExternals%"=="" set IncludeExternals=true
111111
if "%IncludeCTypes%"=="" set IncludeCTypes=true
112112
if "%IncludeSSL%"=="" set IncludeSSL=true
113113
if "%IncludeTkinter%"=="" set IncludeTkinter=true
114+
if "%UseJIT%" NEQ "true" set IncludeLLVM=false
114115

115116
if "%IncludeExternals%"=="true" call "%dir%get_externals.bat"
116117

PCbuild/get_externals.bat

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ set IncludeSSLSrc=false
1515
if "%~1"=="--no-tkinter" (set IncludeTkinter=false) & shift & goto CheckOpts
1616
if "%~1"=="--no-openssl" (set IncludeSSL=false) & shift & goto CheckOpts
1717
if "%~1"=="--no-libffi" (set IncludeLibffi=false) & shift & goto CheckOpts
18+
if "%~1"=="--no-llvm" (set IncludeLLVM=false) & shift & goto CheckOpts
1819
if "%~1"=="--tkinter-src" (set IncludeTkinterSrc=true) & shift & goto CheckOpts
1920
if "%~1"=="--openssl-src" (set IncludeSSLSrc=true) & shift & goto CheckOpts
2021
if "%~1"=="--libffi-src" (set IncludeLibffiSrc=true) & shift & goto CheckOpts
@@ -80,6 +81,7 @@ if NOT "%IncludeLibffi%"=="false" set binaries=%binaries% libffi-3.4.4
8081
if NOT "%IncludeSSL%"=="false" set binaries=%binaries% openssl-bin-3.0.16.2
8182
if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.15.0
8283
if NOT "%IncludeSSLSrc%"=="false" set binaries=%binaries% nasm-2.11.06
84+
if NOT "%IncludeLLVM%"=="false" set binaries=%binaries% llvm-19.1.7.0
8385

8486
for %%b in (%binaries%) do (
8587
if exist "%EXTERNALS_DIR%\%%b" (
@@ -98,7 +100,7 @@ goto end
98100

99101
:usage
100102
echo.Valid options: -c, --clean, --clean-only, --organization, --python,
101-
echo.--no-tkinter, --no-openssl
103+
echo.--no-tkinter, --no-openssl, --no-llvm
102104
echo.
103105
echo.Pull all sources and binaries necessary for compiling optional extension
104106
echo.modules that rely on external libraries.

PCbuild/regen.targets

+7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,11 @@
3030
<_KeywordOutputs Include="$(PySourcePath)Lib\keyword.py" />
3131
<!-- Taken from _Target._compute_digest in Tools\jit\_targets.py: -->
3232
<_JITSources Include="$(PySourcePath)Python\executor_cases.c.h;$(GeneratedPyConfigDir)pyconfig.h;$(PySourcePath)Tools\jit\**"/>
33+
<!-- Need to explicitly enumerate these, since globbing doesn't work for missing outputs: -->
3334
<_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils.h"/>
35+
<_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils-aarch64-pc-windows-msvc.h" Condition="$(Platform) == 'ARM64'"/>
36+
<_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils-i686-pc-windows-msvc.h" Condition="$(Platform) == 'Win32'"/>
37+
<_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils-x86_64-pc-windows-msvc.h" Condition="$(Platform) == 'x64'"/>
3438
<_CasesSources Include="$(PySourcePath)Python\bytecodes.c;$(PySourcePath)Python\optimizer_bytecodes.c;"/>
3539
<_CasesOutputs Include="$(PySourcePath)Python\generated_cases.c.h;$(PySourcePath)Include\opcode_ids.h;$(PySourcePath)Include\internal\pycore_uop_ids.h;$(PySourcePath)Python\opcode_targets.h;$(PySourcePath)Include\internal\pycore_opcode_metadata.h;$(PySourcePath)Include\internal\pycore_uop_metadata.h;$(PySourcePath)Python\optimizer_cases.c.h;$(PySourcePath)Lib\_opcode_metadata.py"/>
3640
<_SbomSources Include="$(PySourcePath)PCbuild\get_externals.bat" />
@@ -124,6 +128,9 @@
124128
<Exec Command='$(PythonForBuild) "$(PySourcePath)Tools\jit\build.py" $(JITArgs)'
125129
WorkingDirectory="$(GeneratedPyConfigDir)"/>
126130
</Target>
131+
<Target Name="_CleanJIT" AfterTargets="Clean">
132+
<Delete Files="@(_JITOutputs)"/>
133+
</Target>
127134

128135
<Target Name="_RegenNoPGUpdate"
129136
Condition="$(Configuration) != 'PGUpdate'"

Tools/jit/README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ Homebrew won't add any of the tools to your `$PATH`. That's okay; the build scri
4141

4242
### Windows
4343

44-
Install LLVM 19 [by searching for it on LLVM's GitHub releases page](https://github.com/llvm/llvm-project/releases?q=19), clicking on "Assets", downloading the appropriate Windows installer for your platform (likely the file ending with `-win64.exe`), and running it. **When installing, be sure to select the option labeled "Add LLVM to the system PATH".**
44+
LLVM is downloaded automatically (along with other external binary dependencies) by `PCbuild\build.bat`.
45+
46+
Otherwise, you can install LLVM 19 [by searching for it on LLVM's GitHub releases page](https://github.com/llvm/llvm-project/releases?q=19), clicking on "Assets", downloading the appropriate Windows installer for your platform (likely the file ending with `-win64.exe`), and running it. **When installing, be sure to select the option labeled "Add LLVM to the system PATH".**
4547

4648
Alternatively, you can use [chocolatey](https://chocolatey.org):
4749

Tools/jit/_llvm.py

+8
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
import subprocess
99
import typing
1010

11+
import _targets
12+
1113
_LLVM_VERSION = 19
1214
_LLVM_VERSION_PATTERN = re.compile(rf"version\s+{_LLVM_VERSION}\.\d+\.\d+\S*\s+")
15+
_EXTERNALS_LLVM_TAG = "llvm-19.1.7.0"
1316

1417
_P = typing.ParamSpec("_P")
1518
_R = typing.TypeVar("_R")
@@ -72,6 +75,11 @@ async def _find_tool(tool: str, *, echo: bool = False) -> str | None:
7275
return path
7376
# Versioned executables:
7477
path = f"{tool}-{_LLVM_VERSION}"
78+
if await _check_tool_version(path, echo=echo):
79+
return path
80+
# PCbuild externals:
81+
externals = os.environ.get("EXTERNALS_DIR", _targets.EXTERNALS)
82+
path = os.path.join(externals, _EXTERNALS_LLVM_TAG, "bin", tool)
7583
if await _check_tool_version(path, echo=echo):
7684
return path
7785
# Homebrew-installed executables:

Tools/jit/_targets.py

+2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@
2323
TOOLS_JIT = TOOLS_JIT_BUILD.parent
2424
TOOLS = TOOLS_JIT.parent
2525
CPYTHON = TOOLS.parent
26+
EXTERNALS = CPYTHON / "externals"
2627
PYTHON_EXECUTOR_CASES_C_H = CPYTHON / "Python" / "executor_cases.c.h"
2728
TOOLS_JIT_TEMPLATE_C = TOOLS_JIT / "template.c"
29+
2830
ASYNCIO_RUNNER = asyncio.Runner()
2931

3032
_S = typing.TypeVar("_S", _schema.COFFSection, _schema.ELFSection, _schema.MachOSection)

Tools/jit/build.py

+16-10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import _targets
99

1010
if __name__ == "__main__":
11+
out = pathlib.Path.cwd().resolve()
1112
comment = f"$ {shlex.join([pathlib.Path(sys.executable).name] + sys.argv)}"
1213
parser = argparse.ArgumentParser(description=__doc__)
1314
parser.add_argument(
@@ -31,17 +32,22 @@
3132
target.force = args.force
3233
target.verbose = args.verbose
3334
target.build(
34-
pathlib.Path.cwd(),
35+
out,
3536
comment=comment,
3637
stencils_h=f"jit_stencils-{target.triple}.h",
3738
force=args.force,
3839
)
39-
40-
with open("jit_stencils.h", "w") as fp:
41-
for idx, target in enumerate(args.target):
42-
fp.write(f"#{'if' if idx == 0 else 'elif'} {target.condition}\n")
43-
fp.write(f'#include "jit_stencils-{target.triple}.h"\n')
44-
45-
fp.write("#else\n")
46-
fp.write('#error "unexpected target"\n')
47-
fp.write("#endif\n")
40+
jit_stencils_h = out / "jit_stencils.h"
41+
lines = [f"// {comment}\n"]
42+
guard = "#if"
43+
for target in args.target:
44+
lines.append(f"{guard} {target.condition}\n")
45+
lines.append(f'#include "jit_stencils-{target.triple}.h"\n')
46+
guard = "#elif"
47+
lines.append("#else\n")
48+
lines.append('#error "unexpected target"\n')
49+
lines.append("#endif\n")
50+
body = "".join(lines)
51+
# Don't touch the file if it hasn't changed (so we don't trigger a rebuild):
52+
if not jit_stencils_h.is_file() or jit_stencils_h.read_text() != body:
53+
jit_stencils_h.write_text(body)

0 commit comments

Comments
 (0)