]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-113464: Get LLVM from cpython-bin-deps on Windows (GH-133278)
authorBrandt Bucher <brandtbucher@microsoft.com>
Fri, 2 May 2025 18:17:15 +0000 (11:17 -0700)
committerGitHub <noreply@github.com>
Fri, 2 May 2025 18:17:15 +0000 (11:17 -0700)
.github/workflows/jit.yml
Misc/NEWS.d/next/Build/2025-05-01-17-27-06.gh-issue-113464.vjE5X4.rst [new file with mode: 0644]
PCbuild/build.bat
PCbuild/get_externals.bat
PCbuild/regen.targets
Tools/jit/README.md
Tools/jit/_llvm.py
Tools/jit/_targets.py
Tools/jit/build.py

index 6ea238d294ca89ddaad9f0b6daebc6a5e555be78..116e0c1e945e380d2ddb7f8da6d1cba515ba19e3 100644 (file)
@@ -95,10 +95,10 @@ jobs:
         with:
           python-version: '3.11'
 
+      # PCbuild downloads LLVM automatically:
       - name: Windows
         if: runner.os == 'Windows'
         run: |
-          choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
           ./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
           ./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
 
diff --git a/Misc/NEWS.d/next/Build/2025-05-01-17-27-06.gh-issue-113464.vjE5X4.rst b/Misc/NEWS.d/next/Build/2025-05-01-17-27-06.gh-issue-113464.vjE5X4.rst
new file mode 100644 (file)
index 0000000..d150b19
--- /dev/null
@@ -0,0 +1,3 @@
+Use the cpython-bin-deps "externals" repository for Windows LLVM dependency
+management. Installing LLVM manually is no longer necessary for Windows JIT
+builds.
index 88d6b99d651cf37c6372f758a5c66bc0b953333b..2f358991e484ce4a284e1a8d1dfc96ea08aea230 100644 (file)
@@ -111,6 +111,7 @@ if "%IncludeExternals%"=="" set IncludeExternals=true
 if "%IncludeCTypes%"=="" set IncludeCTypes=true
 if "%IncludeSSL%"=="" set IncludeSSL=true
 if "%IncludeTkinter%"=="" set IncludeTkinter=true
+if "%UseJIT%" NEQ "true" set IncludeLLVM=false
 
 if "%IncludeExternals%"=="true" call "%dir%get_externals.bat"
 
index b28ce9caeb3f135b0ce0a27d59cc0419e343d459..49ace616793d8eac0236c26e1fa8f5731655d03c 100644 (file)
@@ -15,6 +15,7 @@ set IncludeSSLSrc=false
 if "%~1"=="--no-tkinter" (set IncludeTkinter=false) & shift & goto CheckOpts
 if "%~1"=="--no-openssl" (set IncludeSSL=false) & shift & goto CheckOpts
 if "%~1"=="--no-libffi" (set IncludeLibffi=false) & shift & goto CheckOpts
+if "%~1"=="--no-llvm" (set IncludeLLVM=false) & shift & goto CheckOpts
 if "%~1"=="--tkinter-src" (set IncludeTkinterSrc=true) & shift & goto CheckOpts
 if "%~1"=="--openssl-src" (set IncludeSSLSrc=true) & shift & goto CheckOpts
 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
 if NOT "%IncludeSSL%"=="false"     set binaries=%binaries% openssl-bin-3.0.16.2
 if NOT "%IncludeTkinter%"=="false" set binaries=%binaries% tcltk-8.6.15.0
 if NOT "%IncludeSSLSrc%"=="false"  set binaries=%binaries% nasm-2.11.06
+if NOT "%IncludeLLVM%"=="false"    set binaries=%binaries% llvm-19.1.7.0
 
 for %%b in (%binaries%) do (
     if exist "%EXTERNALS_DIR%\%%b" (
@@ -98,7 +100,7 @@ goto end
 
 :usage
 echo.Valid options: -c, --clean, --clean-only, --organization, --python,
-echo.--no-tkinter, --no-openssl
+echo.--no-tkinter, --no-openssl, --no-llvm
 echo.
 echo.Pull all sources and binaries necessary for compiling optional extension
 echo.modules that rely on external libraries.
index 416241d9d0df102a1ff0d73a92204f748336a7a7..e7822a126c6304195cc92e38d31c64e98b6d379b 100644 (file)
     <_KeywordOutputs Include="$(PySourcePath)Lib\keyword.py" />
     <!-- Taken from _Target._compute_digest in Tools\jit\_targets.py: -->
     <_JITSources Include="$(PySourcePath)Python\executor_cases.c.h;$(GeneratedPyConfigDir)pyconfig.h;$(PySourcePath)Tools\jit\**"/>
+    <!-- Need to explicitly enumerate these, since globbing doesn't work for missing outputs: -->
     <_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils.h"/>
+    <_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils-aarch64-pc-windows-msvc.h" Condition="$(Platform) == 'ARM64'"/>
+    <_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils-i686-pc-windows-msvc.h" Condition="$(Platform) == 'Win32'"/>
+    <_JITOutputs Include="$(GeneratedPyConfigDir)jit_stencils-x86_64-pc-windows-msvc.h" Condition="$(Platform) == 'x64'"/>
     <_CasesSources Include="$(PySourcePath)Python\bytecodes.c;$(PySourcePath)Python\optimizer_bytecodes.c;"/>
     <_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"/>
     <_SbomSources Include="$(PySourcePath)PCbuild\get_externals.bat" />
     <Exec Command='$(PythonForBuild) "$(PySourcePath)Tools\jit\build.py" $(JITArgs)'
           WorkingDirectory="$(GeneratedPyConfigDir)"/>
   </Target>
+  <Target Name="_CleanJIT" AfterTargets="Clean">
+    <Delete Files="@(_JITOutputs)"/>
+  </Target>
 
   <Target Name="_RegenNoPGUpdate"
           Condition="$(Configuration) != 'PGUpdate'"
index 4107265754f6ec9102008499c463dfe5d32c67ff..ff4b3964e65bad69dd6ed548f6092b8424550a2d 100644 (file)
@@ -41,7 +41,9 @@ Homebrew won't add any of the tools to your `$PATH`. That's okay; the build scri
 
 ### Windows
 
-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".**
+LLVM is downloaded automatically (along with other external binary dependencies) by `PCbuild\build.bat`.
+
+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".**
 
 Alternatively, you can use [chocolatey](https://chocolatey.org):
 
index 925b56ac669aa0f54cae7487ff97b22aa37f8ebd..f09a8404871b24b92f836324cc35a6bc10bc5408 100644 (file)
@@ -8,8 +8,11 @@ import shlex
 import subprocess
 import typing
 
+import _targets
+
 _LLVM_VERSION = 19
 _LLVM_VERSION_PATTERN = re.compile(rf"version\s+{_LLVM_VERSION}\.\d+\.\d+\S*\s+")
+_EXTERNALS_LLVM_TAG = "llvm-19.1.7.0"
 
 _P = typing.ParamSpec("_P")
 _R = typing.TypeVar("_R")
@@ -72,6 +75,11 @@ async def _find_tool(tool: str, *, echo: bool = False) -> str | None:
         return path
     # Versioned executables:
     path = f"{tool}-{_LLVM_VERSION}"
+    if await _check_tool_version(path, echo=echo):
+        return path
+    # PCbuild externals:
+    externals = os.environ.get("EXTERNALS_DIR", _targets.EXTERNALS)
+    path = os.path.join(externals, _EXTERNALS_LLVM_TAG, "bin", tool)
     if await _check_tool_version(path, echo=echo):
         return path
     # Homebrew-installed executables:
index e0ac735a20f6914983c2b5b6162ca6c3ba6a1b21..6ceb4404e74ce7e84d9574fef3f3b831b8cb8d26 100644 (file)
@@ -23,8 +23,10 @@ TOOLS_JIT_BUILD = pathlib.Path(__file__).resolve()
 TOOLS_JIT = TOOLS_JIT_BUILD.parent
 TOOLS = TOOLS_JIT.parent
 CPYTHON = TOOLS.parent
+EXTERNALS = CPYTHON / "externals"
 PYTHON_EXECUTOR_CASES_C_H = CPYTHON / "Python" / "executor_cases.c.h"
 TOOLS_JIT_TEMPLATE_C = TOOLS_JIT / "template.c"
+
 ASYNCIO_RUNNER = asyncio.Runner()
 
 _S = typing.TypeVar("_S", _schema.COFFSection, _schema.ELFSection, _schema.MachOSection)
index 4d1e484b6838eb708629e9d71e927646f29eaf4f..49b08f477dbed7bf10239535342f1477a949f93c 100644 (file)
@@ -8,6 +8,7 @@ import sys
 import _targets
 
 if __name__ == "__main__":
+    out = pathlib.Path.cwd().resolve()
     comment = f"$ {shlex.join([pathlib.Path(sys.executable).name] + sys.argv)}"
     parser = argparse.ArgumentParser(description=__doc__)
     parser.add_argument(
@@ -31,17 +32,22 @@ if __name__ == "__main__":
         target.force = args.force
         target.verbose = args.verbose
         target.build(
-            pathlib.Path.cwd(),
+            out,
             comment=comment,
             stencils_h=f"jit_stencils-{target.triple}.h",
             force=args.force,
         )
-
-    with open("jit_stencils.h", "w") as fp:
-        for idx, target in enumerate(args.target):
-            fp.write(f"#{'if' if idx == 0 else 'elif'} {target.condition}\n")
-            fp.write(f'#include "jit_stencils-{target.triple}.h"\n')
-
-        fp.write("#else\n")
-        fp.write('#error "unexpected target"\n')
-        fp.write("#endif\n")
+    jit_stencils_h = out / "jit_stencils.h"
+    lines = [f"// {comment}\n"]
+    guard = "#if"
+    for target in args.target:
+        lines.append(f"{guard} {target.condition}\n")
+        lines.append(f'#include "jit_stencils-{target.triple}.h"\n')
+        guard = "#elif"
+    lines.append("#else\n")
+    lines.append('#error "unexpected target"\n')
+    lines.append("#endif\n")
+    body = "".join(lines)
+    # Don't touch the file if it hasn't changed (so we don't trigger a rebuild):
+    if not jit_stencils_h.is_file() or jit_stencils_h.read_text() != body:
+        jit_stencils_h.write_text(body)