mirror of
https://github.com/gufo-org/gufo.git
synced 2026-11-07 09:35:59 -10:00
fix(windows): bundle the LLVM OpenMP runtime (#802)
This commit is contained in:
1 parent
2765d65e19
commit
5eedd09903
6 files changed
+632
-15
No files matched your search
+112
-14
@@ -53,6 +53,7 @@ jobs:
|
||||
SDK_SHA256: 1293927b06b3b8d4bd7e0265823fb998bc9e0d83c68f33dcfa5d32663b30ce38
|
||||
# Forward slashes: CMake reads backslashes in -D values as escapes.
|
||||
SDK_ROOT: C:/TheRock/build
|
||||
GUFO_PACKAGING_ROOT: ${{ github.workspace }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
@@ -62,6 +63,25 @@ jobs:
|
||||
repository: ${{ inputs.release-tag && 'gufo-org/gufo' || github.repository }}
|
||||
ref: ${{ inputs.release-tag && format('refs/tags/{0}', inputs.release-tag) || github.ref }}
|
||||
|
||||
# The executable stays at the release tag. Packaging tools may be newer
|
||||
# (for example, repairing a missing runtime in an already released ZIP).
|
||||
- name: Checkout current release packaging tools
|
||||
if: inputs.release-tag
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
repository: gufo-org/gufo
|
||||
ref: main
|
||||
path: build/gufo-packaging
|
||||
sparse-checkout: |
|
||||
tools/windows
|
||||
tests/tools
|
||||
licenses
|
||||
persist-credentials: false
|
||||
|
||||
- name: Select release packaging tools
|
||||
if: inputs.release-tag
|
||||
run: '"GUFO_PACKAGING_ROOT=$env:GITHUB_WORKSPACE/build/gufo-packaging" >> $env:GITHUB_ENV'
|
||||
|
||||
- name: Identify release source
|
||||
if: inputs.release-tag
|
||||
env:
|
||||
@@ -170,6 +190,39 @@ jobs:
|
||||
"VCPKG_ROOT=C:\vcpkg-gufo" >> $env:GITHUB_ENV
|
||||
"VCPKG_DEFAULT_BINARY_CACHE=$env:RUNNER_TEMP\vcpkg-archives" >> $env:GITHUB_ENV
|
||||
|
||||
# Visual Studio's LLVM OpenMP DLL is under debug_nonredist and cannot
|
||||
# be shipped. Build the upstream runtime with the ABI filename imported
|
||||
# by TheRock (including rocalution), rather than renaming another DLL.
|
||||
- name: Checkout LLVM OpenMP 18.1.8
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
repository: llvm/llvm-project
|
||||
ref: 3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff # llvmorg-18.1.8
|
||||
path: build/llvm-project
|
||||
sparse-checkout: |
|
||||
cmake
|
||||
llvm/cmake
|
||||
openmp
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build redistributable LLVM OpenMP
|
||||
id: openmp
|
||||
run: |
|
||||
$clang = Get-ChildItem "$env:SDK_ROOT/lib/llvm/bin" -Filter '*clang-cl.exe' | Select-Object -First 1
|
||||
if (-not $clang) { throw 'SDK clang-cl not found' }
|
||||
cmake -S build/llvm-project/openmp -B build/openmp -G Ninja `
|
||||
"-DCMAKE_C_COMPILER=$($clang.FullName)" "-DCMAKE_CXX_COMPILER=$($clang.FullName)" `
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache `
|
||||
-DCMAKE_BUILD_TYPE=Release -DOPENMP_MSVC_NAME_SCHEME=ON `
|
||||
-DOPENMP_ENABLE_LIBOMPTARGET=OFF -DLIBOMP_OMPT_SUPPORT=OFF
|
||||
if ($LASTEXITCODE -ne 0) { throw 'OpenMP configure failed' }
|
||||
cmake --build build/openmp --parallel $env:NUMBER_OF_PROCESSORS --target omp ompimp
|
||||
if ($LASTEXITCODE -ne 0) { throw 'OpenMP build failed' }
|
||||
$runtime = 'build/openmp/runtime/src/libomp140.x86_64.dll'
|
||||
if (-not (Test-Path $runtime)) { throw "OpenMP runtime missing: $runtime" }
|
||||
New-Item -ItemType Directory -Force build/windows-release | Out-Null
|
||||
Copy-Item $runtime build/windows-release
|
||||
|
||||
- name: Configure
|
||||
id: configure
|
||||
run: |
|
||||
@@ -180,7 +233,9 @@ jobs:
|
||||
# ccache cannot cache objects that write a shared /Zi PDB: embed
|
||||
# the debug info in each object instead (/Z7).
|
||||
cmake --preset windows-release -DBUILD_TESTING=ON "-DCMAKE_HIP_COMPILER_ROCM_ROOT=$env:SDK_ROOT" `
|
||||
-DCMAKE_POLICY_DEFAULT_CMP0141=NEW -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded @identity
|
||||
-DCMAKE_POLICY_DEFAULT_CMP0141=NEW -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded `
|
||||
-DOpenMP_CXX_LIB_NAMES=libomp "-DOpenMP_libomp_LIBRARY=$PWD/build/openmp/runtime/src/libomp.lib" `
|
||||
"-DOpenMP_CXX_INCLUDE_DIR=$PWD/build/openmp/runtime/src" @identity
|
||||
if ($LASTEXITCODE -ne 0) { throw 'configure failed' }
|
||||
"$PWD\build\windows-release\vcpkg_installed\x64-windows-release\bin" >> $env:GITHUB_PATH
|
||||
"$PWD\build\windows-release" >> $env:GITHUB_PATH
|
||||
@@ -221,8 +276,11 @@ jobs:
|
||||
if (Test-Path "$build\$dir") { Copy-Item "$build\$dir" $dist -Recurse }
|
||||
}
|
||||
Copy-Item "$build\vcpkg_installed\x64-windows-release\bin\*.dll" $dist -Force
|
||||
Copy-Item "$env:GUFO_PACKAGING_ROOT/licenses/llvm-openmp.txt" "$dist/llvm-openmp-LICENSE.txt"
|
||||
'LLVM OpenMP 18.1.8, source: https://github.com/llvm/llvm-project/tree/3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff/openmp; Apache-2.0 WITH LLVM-exception; built with OPENMP_MSVC_NAME_SCHEME=ON.' |
|
||||
Set-Content "$dist/llvm-openmp-version.txt" -Encoding ascii
|
||||
$redist = Get-ChildItem "$env:VCToolsRedistDir\x64" -Directory |
|
||||
Where-Object { $_.Name -like 'Microsoft.VC*.CRT' -or $_.Name -like 'Microsoft.VC*.OpenMP.LLVM' }
|
||||
Where-Object { $_.Name -like 'Microsoft.VC*.CRT' }
|
||||
foreach ($dir in $redist) { Copy-Item "$($dir.FullName)\*.dll" $dist -Force }
|
||||
foreach ($test in 'gpu_queues_test', 'bandwidth_test', 'allocation_benchmark_test') {
|
||||
$exe = Get-ChildItem $build -Recurse -Filter "$test.exe" | Select-Object -First 1
|
||||
@@ -240,6 +298,34 @@ jobs:
|
||||
"Bundle: {0} files, {1:N0} MiB" -f $files.Count, (($files | Measure-Object Length -Sum).Sum / 1MB) |
|
||||
Tee-Object -Append $env:GITHUB_STEP_SUMMARY
|
||||
|
||||
# Inspect imports rather than trusting PATH: the hosted builder may
|
||||
# already have a dependency in System32. Run this on PR bundles too.
|
||||
- name: Check extracted Windows bundle
|
||||
run: |
|
||||
python -m pip install pefile==2024.8.26
|
||||
if ($LASTEXITCODE -ne 0) { throw 'cannot install PE inspection tool' }
|
||||
python -m unittest discover -s "$env:GUFO_PACKAGING_ROOT/tests/tools" -p windows_bundle_test.py
|
||||
if ($LASTEXITCODE -ne 0) { throw 'bundle checker tests failed' }
|
||||
$archive = "$env:RUNNER_TEMP/windows-bundle-test.zip"
|
||||
$extracted = "$env:RUNNER_TEMP/windows-bundle-test"
|
||||
tar -a -cf $archive -C "$env:RUNNER_TEMP/windows-gufo" .
|
||||
if ($LASTEXITCODE -ne 0) { throw 'cannot archive test bundle' }
|
||||
New-Item -ItemType Directory -Force $extracted | Out-Null
|
||||
tar -xf $archive -C $extracted
|
||||
if ($LASTEXITCODE -ne 0) { throw 'cannot extract test bundle' }
|
||||
python "$env:GUFO_PACKAGING_ROOT/tools/windows/check_bundle.py" $extracted
|
||||
if ($LASTEXITCODE -ne 0) { throw 'bundle has unshipped DLL dependencies' }
|
||||
$env:PATH = "$extracted;$env:SystemRoot/System32;$env:SystemRoot"
|
||||
Push-Location $extracted
|
||||
try {
|
||||
foreach ($argument in '--version', '--help') {
|
||||
$output = & ./gufo.exe $argument
|
||||
if ($LASTEXITCODE -ne 0 -or -not $output) { throw "bundled gufo $argument failed" }
|
||||
}
|
||||
& ./gufo.exe diagnose --section platform
|
||||
if ($LASTEXITCODE -ne 0) { throw 'extracted bundle platform diagnosis failed' }
|
||||
} finally { Pop-Location }
|
||||
|
||||
- name: Upload gufo for the Devlab runner
|
||||
if: ${{ !inputs.release-tag }}
|
||||
id: bundle
|
||||
@@ -260,24 +346,36 @@ jobs:
|
||||
$bundle = "$env:RUNNER_TEMP\windows-gufo"
|
||||
New-Item -ItemType Directory -Force -Path $dist | Out-Null
|
||||
Copy-Item "$bundle\gufo.exe", "$bundle\*.dll", LICENSE, NOTICE, THIRD_PARTY_NOTICES.md $dist
|
||||
Copy-Item "$bundle/llvm-openmp-LICENSE.txt", "$bundle/llvm-openmp-version.txt" $dist
|
||||
Copy-Item licenses "$dist\third-party" -Recurse
|
||||
Copy-Item src\models\deepseek_v4_flash\LICENSE.ds4 "$dist\third-party"
|
||||
foreach ($dir in 'rocblas', 'hipblaslt') {
|
||||
if (Test-Path "$bundle\$dir") { Copy-Item "$bundle\$dir" $dist -Recurse }
|
||||
}
|
||||
# Exercise the distribution with only its bundled DLLs on PATH.
|
||||
$env:PATH = "$dist;$env:SystemRoot\System32;$env:SystemRoot"
|
||||
$expected = "gufo version $env:GUFO_RELEASE_VERSION ($env:GUFO_REVISION)"
|
||||
$actual = & "$dist\gufo.exe" --version
|
||||
if ($LASTEXITCODE -ne 0 -or ($actual -join "`n") -cne $expected) {
|
||||
throw "release reports '$actual', expected '$expected'"
|
||||
}
|
||||
& "$dist\gufo.exe" diagnose --section platform
|
||||
if ($LASTEXITCODE -ne 0) { throw 'bundled platform diagnosis failed' }
|
||||
$archive = "$env:RUNNER_TEMP\gufo-$env:RELEASE_TAG-windows-x86_64.zip"
|
||||
# Windows' libarchive tar supports ZIP64 for the HIP runtime.
|
||||
tar -a -cf $archive -C $dist .
|
||||
if ($LASTEXITCODE -ne 0) { throw 'cannot pack Windows release' }
|
||||
# Validate the exact release ZIP, not only its staging directory.
|
||||
$extracted = "$env:RUNNER_TEMP/gufo-release-verify"
|
||||
New-Item -ItemType Directory -Force $extracted | Out-Null
|
||||
tar -xf $archive -C $extracted
|
||||
if ($LASTEXITCODE -ne 0) { throw 'cannot extract Windows release' }
|
||||
python "$env:GUFO_PACKAGING_ROOT/tools/windows/check_bundle.py" $extracted
|
||||
if ($LASTEXITCODE -ne 0) { throw 'release ZIP has unshipped DLL dependencies' }
|
||||
$env:PATH = "$extracted;$env:SystemRoot/System32;$env:SystemRoot"
|
||||
Push-Location $extracted
|
||||
try {
|
||||
$expected = "gufo version $env:GUFO_RELEASE_VERSION ($env:GUFO_REVISION)"
|
||||
$actual = & ./gufo.exe --version
|
||||
if ($LASTEXITCODE -ne 0 -or ($actual -join "`n") -cne $expected) {
|
||||
throw "release reports '$actual', expected '$expected'"
|
||||
}
|
||||
$help = & ./gufo.exe --help
|
||||
if ($LASTEXITCODE -ne 0 -or -not $help) { throw 'release help failed' }
|
||||
& ./gufo.exe diagnose --section platform
|
||||
if ($LASTEXITCODE -ne 0) { throw 'release platform diagnosis failed' }
|
||||
} finally { Pop-Location }
|
||||
$sha = (Get-FileHash -Algorithm SHA256 $archive).Hash.ToLowerInvariant()
|
||||
"$sha $(Split-Path $archive -Leaf)" | Set-Content "$archive.sha256" -Encoding ascii
|
||||
"artifact-name=windows-release-$env:RELEASE_TAG-$env:GITHUB_RUN_ATTEMPT" >> $env:GITHUB_OUTPUT
|
||||
@@ -313,10 +411,10 @@ jobs:
|
||||
path: ${{ runner.temp }}\therock-archive
|
||||
key: gufo-therock-v2-${{ env.SDK_TARBALL }}
|
||||
|
||||
# Under a fresh key per run, as soon as configure ran: a restored set
|
||||
# plus this run's new entries is saved whole.
|
||||
# Save both OpenMP and Gufo objects, even if a later stage fails. A fresh
|
||||
# key preserves this run's new entries alongside the restored set.
|
||||
- name: Save compiler cache
|
||||
if: always() && steps.configure.outcome == 'success'
|
||||
if: always() && (steps.openmp.outcome == 'success' || steps.configure.outcome == 'success')
|
||||
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ${{ runner.temp }}\ccache
|
||||
|
||||
+27
-1
@@ -6,6 +6,27 @@ from the Linux build. The device toolchain differs: `clang-cl` and the HIP
|
||||
runtime come from a TheRock SDK, MSVC supplies the C++ standard library and
|
||||
the linker, and vcpkg supplies the libraries.
|
||||
|
||||
## Downloaded Windows releases
|
||||
|
||||
Extract the entire release ZIP before running `gufo.exe`, keeping its DLLs and
|
||||
kernel directories beside it. Bundles include an LLVM OpenMP runtime built
|
||||
from upstream LLVM 18.1.8 source under Apache-2.0 with LLVM exceptions, using
|
||||
`libomp140.x86_64.dll` as required by the SDK. The license is included under
|
||||
`llvm-openmp-LICENSE.txt`, with source provenance in `llvm-openmp-version.txt`.
|
||||
|
||||
The v0.24.0 ZIP omitted this DLL ([#801](https://github.com/gufo-org/gufo/issues/801)).
|
||||
If it exits silently, including for `--help`, with status `0xC0000135`, the
|
||||
Windows loader could not find a DLL. Use a subsequent fixed Gufo release when
|
||||
available. For a local development workaround, install Microsoft's Visual
|
||||
Studio Build Tools with the C++ workload and run Gufo from its x64 Native
|
||||
Tools command prompt. Microsoft documents the LLVM OpenMP DLL under
|
||||
`VC\Redist\MSVC\<version>\debug_nonredist\x64\Microsoft.VC*.OpenMP.LLVM`;
|
||||
if necessary, copy that installed x64 DLL beside `gufo.exe` for local use.
|
||||
Do not obtain DLLs from third-party download sites or replace system DLLs.
|
||||
The ordinary VC++ Redistributable does not supply this LLVM runtime.
|
||||
Microsoft's DLL is [not redistributable](https://learn.microsoft.com/en-us/cpp/build/reference/openmp-enable-openmp-2-0-support?view=msvc-170);
|
||||
release packaging builds the upstream runtime instead.
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
- **Hardware/driver:** AMD Strix Halo (gfx1151) with a current AMD graphics
|
||||
@@ -107,7 +128,12 @@ Then `curl http://127.0.0.1:8080/ready` and POST to `/v1/chat/completions`.
|
||||
[`.github/workflows/windows.yml`](.github/workflows/windows.yml) builds this
|
||||
recipe on a hosted `windows-latest` runner, with the SDK archive, the vcpkg
|
||||
packages and the compiler cache restored from the Actions cache, and runs
|
||||
`check-pr`. On a manual dispatch, the Windows Strix Halo Devlab runner then
|
||||
`check-pr`. It also builds the upstream OpenMP runtime, extracts the packaged
|
||||
bundle, checks every EXE/DLL's normal and delay imports against the bundle and
|
||||
an explicit Windows system DLL list, and runs `--help`, `--version` and platform
|
||||
diagnosis with a restricted `PATH`. The import check does not use the builder's
|
||||
installed DLLs, so developer tools cannot conceal an omitted dependency.
|
||||
On a manual dispatch, the Windows Strix Halo Devlab runner then
|
||||
downloads the resulting bundle and runs `gufo diagnose`, the weight-free GPU
|
||||
tests, and one small model per family through
|
||||
[`tests/functional/family_smoke.py`](tests/functional/family_smoke.py):
|
||||
|
||||
@@ -27,6 +27,7 @@ Non-Nix builds must retain the notices of the versions they actually distribute.
|
||||
| libjpeg-turbo | Linked; JPEG decoding | `IJG AND BSD-3-Clause AND Zlib` | 3.1.4.1; flake.lock | [libjpeg-turbo](https://github.com/libjpeg-turbo/libjpeg-turbo) |
|
||||
| libwebp | Linked; WebP decoding | `BSD-3-Clause` | 1.6.0; flake.lock | [webmproject/libwebp](https://chromium.googlesource.com/webm/libwebp) |
|
||||
| FFmpeg | Separate ffmpeg/ffprobe executables for media | `GPL-3.0-or-later` (Nix build with GPL/version3 components) | 8.1.2; flake.lock | [FFmpeg](https://github.com/FFmpeg/FFmpeg) |
|
||||
| LLVM OpenMP | Windows runtime built from upstream source; Microsoft-compatible DLL naming | `Apache-2.0 WITH LLVM-exception` | 18.1.8 (`3b5b5c1ec4a3095ab096dd780e84d7ab81f3d7ff`) | [LLVM](https://github.com/llvm/llvm-project/tree/llvmorg-18.1.8/openmp); [license](licenses/llvm-openmp.txt) |
|
||||
| GNU C/C++/OpenMP runtimes | System runtime libraries; no Gufo source import | `LGPL-2.1-or-later AND (GPL-3.0-or-later WITH GCC-exception-3.1)` | glibc/GCC packages in flake.lock | [GNU](https://www.gnu.org/software/) |
|
||||
| llama.cpp / ggml | Adapted quantization, attention and model-private HIP kernels | `MIT` | `5c0e9468378eba6bf3cc1989ff5d62fbbe4d9e3a`; attention `e9fa0781f1c25fc4fe8c86be1edc6970661ad6f0` | [llama.cpp](https://github.com/ggml-org/llama.cpp) |
|
||||
| mikealanni/gufo | Adapted Flash-Next GDN row reuse and SSM stride optimization | `MIT` | `f450218743bcaf77e3e1f8fab78f4cd4e4aafae3` | [gufo fork](https://github.com/mikealanni/gufo/tree/f450218743bcaf77e3e1f8fab78f4cd4e4aafae3) |
|
||||
|
||||
@@ -0,0 +1,361 @@
|
||||
==============================================================================
|
||||
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
|
||||
==============================================================================
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
---- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
||||
==============================================================================
|
||||
Software from third parties included in the LLVM Project:
|
||||
==============================================================================
|
||||
The LLVM Project contains third party software which is under different license
|
||||
terms. All such code will be identified clearly using at least one of two
|
||||
mechanisms:
|
||||
1) It will be in a separate directory tree with its own `LICENSE.txt` or
|
||||
`LICENSE` file at the top containing the specific license and restrictions
|
||||
which apply to that software, or
|
||||
2) It will contain specific license and restriction terms at the top of every
|
||||
file.
|
||||
|
||||
==============================================================================
|
||||
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
|
||||
==============================================================================
|
||||
|
||||
The software contained in this directory tree is dual licensed under both the
|
||||
University of Illinois "BSD-Like" license and the MIT license. As a user of
|
||||
this code you may choose to use it under either license. As a contributor,
|
||||
you agree to allow your code to be used under both. The full text of the
|
||||
relevant licenses is included below.
|
||||
|
||||
In addition, a license agreement from the copyright/patent holders of the
|
||||
software contained in this directory tree is included below.
|
||||
|
||||
==============================================================================
|
||||
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 1997-2019 Intel Corporation
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
OpenMP Runtime Team
|
||||
Intel Corporation
|
||||
http://www.openmprtl.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of Intel Corporation OpenMP Runtime Team nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this Software without specific prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
Copyright (c) 1997-2019 Intel Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
==============================================================================
|
||||
|
||||
Intel Corporation
|
||||
|
||||
Software Grant License Agreement ("Agreement")
|
||||
|
||||
Except for the license granted herein to you, Intel Corporation ("Intel") reserves
|
||||
all right, title, and interest in and to the Software (defined below).
|
||||
|
||||
Definition
|
||||
|
||||
"Software" means the code and documentation as well as any original work of
|
||||
authorship, including any modifications or additions to an existing work, that
|
||||
is intentionally submitted by Intel to llvm.org (http://llvm.org) ("LLVM") for
|
||||
inclusion in, or documentation of, any of the products owned or managed by LLVM
|
||||
(the "Work"). For the purposes of this definition, "submitted" means any form of
|
||||
electronic, verbal, or written communication sent to LLVM or its
|
||||
representatives, including but not limited to communication on electronic
|
||||
mailing lists, source code control systems, and issue tracking systems that are
|
||||
managed by, or on behalf of, LLVM for the purpose of discussing and improving
|
||||
the Work, but excluding communication that is conspicuously marked otherwise.
|
||||
|
||||
1. Grant of Copyright License. Subject to the terms and conditions of this
|
||||
Agreement, Intel hereby grants to you and to recipients of the Software
|
||||
distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge,
|
||||
royalty-free, irrevocable copyright license to reproduce, prepare derivative
|
||||
works of, publicly display, publicly perform, sublicense, and distribute the
|
||||
Software and such derivative works.
|
||||
|
||||
2. Grant of Patent License. Subject to the terms and conditions of this
|
||||
Agreement, Intel hereby grants you and to recipients of the Software
|
||||
distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge,
|
||||
royalty-free, irrevocable (except as stated in this section) patent license
|
||||
to make, have made, use, offer to sell, sell, import, and otherwise transfer
|
||||
the Work, where such license applies only to those patent claims licensable
|
||||
by Intel that are necessarily infringed by Intel's Software alone or by
|
||||
combination of the Software with the Work to which such Software was
|
||||
submitted. If any entity institutes patent litigation against Intel or any
|
||||
other entity (including a cross-claim or counterclaim in a lawsuit) alleging
|
||||
that Intel's Software, or the Work to which Intel has contributed constitutes
|
||||
direct or contributory patent infringement, then any patent licenses granted
|
||||
to that entity under this Agreement for the Software or Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, the software is
|
||||
provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
|
||||
either express or implied, including, without limitation, any warranties or
|
||||
conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE.
|
||||
|
||||
==============================================================================
|
||||
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Windows packaging regressions; runs on Linux and Windows with pefile."""
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"check_bundle", Path(__file__).resolve().parents[2] / "tools/windows/check_bundle.py"
|
||||
)
|
||||
bundle = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(bundle)
|
||||
|
||||
|
||||
class WindowsBundleTest(unittest.TestCase):
|
||||
def test_missing_transitive_openmp_fails_even_if_installed_on_host(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
(root / "gufo.exe").touch()
|
||||
(root / "rocalution.dll").touch()
|
||||
imports = {
|
||||
"gufo.exe": {"rocalution.dll", "kernel32.dll"},
|
||||
"rocalution.dll": {"libomp140.x86_64.dll"},
|
||||
"LIBOMP140.x86_64.DLL": {"api-ms-win-crt-runtime-l1-1-0.dll"},
|
||||
}
|
||||
with patch.object(bundle, "imported_dlls", side_effect=lambda p: imports[p.name]):
|
||||
self.assertEqual(
|
||||
bundle.check_bundle(root),
|
||||
["rocalution.dll requires unbundled libomp140.x86_64.dll"],
|
||||
)
|
||||
(root / "LIBOMP140.x86_64.DLL").touch()
|
||||
self.assertEqual(bundle.check_bundle(root), [])
|
||||
|
||||
def test_developer_and_crt_libraries_are_not_system_dependencies(self):
|
||||
for name in ("libomp140.x86_64.dll", "libomp.dll", "msvcp140.dll", "vcruntime140.dll"):
|
||||
with self.subTest(name=name):
|
||||
self.assertFalse(bundle.is_system_dll(name))
|
||||
self.assertTrue(bundle.is_system_dll("KERNEL32.DLL"))
|
||||
|
||||
def test_normal_and_delay_imports_are_checked(self):
|
||||
from types import SimpleNamespace as Object
|
||||
|
||||
pe = Object(
|
||||
FILE_HEADER=Object(Machine=0x8664),
|
||||
DIRECTORY_ENTRY_IMPORT=[Object(dll=b"KERNEL32.dll")],
|
||||
DIRECTORY_ENTRY_DELAY_IMPORT=[Object(dll=b"missing.dll")],
|
||||
)
|
||||
with patch.object(bundle.pefile, "PE") as reader:
|
||||
reader.return_value.__enter__.return_value = pe
|
||||
with patch.object(pe, "parse_data_directories", create=True):
|
||||
self.assertEqual(bundle.imported_dlls(Path("gufo.exe")), {"kernel32.dll", "missing.dll"})
|
||||
|
||||
def test_missing_executable_fails(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
with self.assertRaisesRegex(ValueError, "missing gufo.exe"):
|
||||
bundle.check_bundle(Path(tmp))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Reject Windows bundles that rely on non-system DLLs outside the bundle.
|
||||
|
||||
Requires pefile==2024.8.26. Checks normal and delay imports in every top-level
|
||||
EXE/DLL, including SDK libraries that Gufo loads indirectly. Never resolves DLLs
|
||||
against the inspection host's PATH or System32.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
import pefile
|
||||
|
||||
# Windows 11 inbox libraries, not development tools, CRT or GPU SDK runtimes.
|
||||
SYSTEM_DLLS = frozenset(
|
||||
"""advapi32.dll bcrypt.dll cfgmgr32.dll crypt32.dll gdi32.dll iphlpapi.dll
|
||||
kernel32.dll ntdll.dll ole32.dll oleaut32.dll psapi.dll secur32.dll setupapi.dll
|
||||
shell32.dll shlwapi.dll user32.dll version.dll ws2_32.dll""".split()
|
||||
)
|
||||
|
||||
|
||||
def is_system_dll(name):
|
||||
name = name.lower()
|
||||
return name in SYSTEM_DLLS or name.startswith(("api-ms-win-", "ext-ms-win-"))
|
||||
|
||||
|
||||
def imported_dlls(path):
|
||||
with pefile.PE(str(path), fast_load=True) as pe:
|
||||
if pe.FILE_HEADER.Machine != 0x8664:
|
||||
raise ValueError(f"{path.name}: expected an x86-64 PE image")
|
||||
pe.parse_data_directories(directories=[1, 13]) # import, delay import
|
||||
return {
|
||||
entry.dll.decode("ascii").lower()
|
||||
for directory in ("DIRECTORY_ENTRY_IMPORT", "DIRECTORY_ENTRY_DELAY_IMPORT")
|
||||
for entry in getattr(pe, directory, [])
|
||||
}
|
||||
|
||||
|
||||
def check_bundle(directory):
|
||||
images = {
|
||||
path.name.lower(): path
|
||||
for path in directory.iterdir()
|
||||
if path.is_file() and path.suffix.lower() in (".exe", ".dll")
|
||||
}
|
||||
if "gufo.exe" not in images:
|
||||
raise ValueError("bundle is missing gufo.exe")
|
||||
missing = []
|
||||
for name, path in sorted(images.items()):
|
||||
for dependency in sorted(imported_dlls(path)):
|
||||
if dependency not in images and not is_system_dll(dependency):
|
||||
missing.append(f"{name} requires unbundled {dependency}")
|
||||
return missing
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("directory", type=Path)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
missing = check_bundle(args.directory)
|
||||
except (OSError, ValueError, pefile.PEFormatError) as error:
|
||||
parser.exit(1, f"{error}\n")
|
||||
if missing:
|
||||
parser.exit(1, "\n".join(missing) + "\n")
|
||||
print("All imported non-system DLLs are bundled (including delay imports).")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user