|
29 | 29 | mkdir $env:RUNNER_TEMP/opencl |
30 | 30 | tar.exe -xf $env:RUNNER_TEMP/opencl.zip --strip-components=1 -C $env:RUNNER_TEMP/opencl |
31 | 31 |
|
| 32 | + - name: Set up MSYS2 UCRT64 for Aevum |
| 33 | + uses: msys2/setup-msys2@v2 |
| 34 | + with: |
| 35 | + msystem: UCRT64 |
| 36 | + update: true |
| 37 | + install: >- |
| 38 | + make |
| 39 | + mingw-w64-ucrt-x86_64-gcc |
| 40 | + mingw-w64-ucrt-x86_64-opencl-headers |
| 41 | + mingw-w64-ucrt-x86_64-opencl-icd |
| 42 | +
|
32 | 43 | - name: Clone and bootstrap vcpkg |
33 | 44 | run: | |
34 | 45 | git clone https://github.com/microsoft/vcpkg.git |
@@ -62,9 +73,135 @@ jobs: |
62 | 73 | -DOpenCL_INCLUDE_DIR="$env:RUNNER_TEMP\opencl\include" ` |
63 | 74 | -DOpenCL_LIBRARY="$env:RUNNER_TEMP\opencl\lib\OpenCL.lib" |
64 | 75 |
|
65 | | - - name: Build |
| 76 | + - name: Build PrMers |
66 | 77 | run: cmake --build build --config Release |
67 | 78 |
|
| 79 | + - name: Build and validate Aevum engine DLL |
| 80 | + shell: msys2 {0} |
| 81 | + run: | |
| 82 | + set -euo pipefail |
| 83 | +
|
| 84 | + make -C third_party/aevum clean |
| 85 | +
|
| 86 | + make -C third_party/aevum engine-lib -j"$(nproc)" \ |
| 87 | + CXX=g++ \ |
| 88 | + DL_LIBS= \ |
| 89 | + ENGINE_LINK_FLAGS="-shared -static-libstdc++ -static-libgcc" |
| 90 | +
|
| 91 | + DLL="third_party/aevum/build-engine/aevum_engine.dll" |
| 92 | +
|
| 93 | + cp third_party/aevum/build-engine/libaevum_engine.so "$DLL" |
| 94 | + test -s "$DLL" |
| 95 | +
|
| 96 | + DEPS="$(objdump -p "$DLL" | sed -n 's/^[[:space:]]*DLL Name: //p')" |
| 97 | +
|
| 98 | + echo "Aevum DLL dependencies:" |
| 99 | + printf '%s\n' "$DEPS" |
| 100 | +
|
| 101 | + if grep -Eqi '^libstdc\+\+-6\.dll$|^libgcc_s_.*\.dll$' <<<"$DEPS"; then |
| 102 | + echo "::error::Aevum DLL still depends on dynamic GCC C++ runtimes" |
| 103 | + exit 1 |
| 104 | + fi |
| 105 | +
|
| 106 | + if grep -qi '^libwinpthread-1\.dll$' <<<"$DEPS"; then |
| 107 | + cp /ucrt64/bin/libwinpthread-1.dll \ |
| 108 | + third_party/aevum/build-engine/ |
| 109 | + fi |
| 110 | +
|
| 111 | + cat > aevum-dll-smoke.cpp <<'CPP' |
| 112 | + #ifndef NOMINMAX |
| 113 | + #define NOMINMAX |
| 114 | + #endif |
| 115 | +
|
| 116 | + #include <windows.h> |
| 117 | +
|
| 118 | + #include <cstddef> |
| 119 | + #include <cstdint> |
| 120 | + #include <iostream> |
| 121 | + #include <stdexcept> |
| 122 | + #include <string> |
| 123 | +
|
| 124 | + int main(int argc, char** argv) { |
| 125 | + if (argc != 2) { |
| 126 | + std::cerr << "Usage: aevum-dll-smoke <dll>\n"; |
| 127 | + return 2; |
| 128 | + } |
| 129 | +
|
| 130 | + HMODULE library = LoadLibraryA(argv[1]); |
| 131 | + if (!library) { |
| 132 | + std::cerr << "LoadLibrary failed: " << GetLastError() << '\n'; |
| 133 | + return 3; |
| 134 | + } |
| 135 | +
|
| 136 | + const char* symbols[] = { |
| 137 | + "aevum_engine_version", |
| 138 | + "aevum_engine_last_error", |
| 139 | + "aevum_engine_resolve_fft", |
| 140 | + "aevum_engine_create", |
| 141 | + "aevum_engine_destroy", |
| 142 | + "aevum_engine_transform_size", |
| 143 | + "aevum_engine_word_count", |
| 144 | + "aevum_engine_sync", |
| 145 | + "aevum_engine_set_u32", |
| 146 | + "aevum_engine_set_words", |
| 147 | + "aevum_engine_get_words", |
| 148 | + "aevum_engine_copy", |
| 149 | + "aevum_engine_prepare", |
| 150 | + "aevum_engine_square_mul", |
| 151 | + "aevum_engine_mul", |
| 152 | + "aevum_engine_add", |
| 153 | + "aevum_engine_sub_reg", |
| 154 | + "aevum_engine_sub_u32", |
| 155 | + "aevum_engine_equal" |
| 156 | + }; |
| 157 | +
|
| 158 | + for (const char* symbol : symbols) { |
| 159 | + if (!GetProcAddress(library, symbol)) { |
| 160 | + std::cerr << "Missing export: " << symbol << '\n'; |
| 161 | + FreeLibrary(library); |
| 162 | + return 4; |
| 163 | + } |
| 164 | + } |
| 165 | +
|
| 166 | + using version_fn = const char* (*)(); |
| 167 | + using error_fn = const char* (*)(); |
| 168 | + using resolve_fn = |
| 169 | + int (*)(std::uint32_t, const char*, char*, std::size_t); |
| 170 | +
|
| 171 | + const auto version = reinterpret_cast<version_fn>( |
| 172 | + GetProcAddress(library, "aevum_engine_version")); |
| 173 | + const auto error = reinterpret_cast<error_fn>( |
| 174 | + GetProcAddress(library, "aevum_engine_last_error")); |
| 175 | + const auto resolve = reinterpret_cast<resolve_fn>( |
| 176 | + GetProcAddress(library, "aevum_engine_resolve_fft")); |
| 177 | +
|
| 178 | + char spec[64]{}; |
| 179 | +
|
| 180 | + if (!resolve(136279841u, nullptr, spec, sizeof(spec))) { |
| 181 | + std::cerr << "FFT resolution failed: " << error() << '\n'; |
| 182 | + FreeLibrary(library); |
| 183 | + return 5; |
| 184 | + } |
| 185 | +
|
| 186 | + std::cout << "Aevum DLL loaded, version=" << version() |
| 187 | + << ", FFT=" << spec << '\n'; |
| 188 | +
|
| 189 | + FreeLibrary(library); |
| 190 | + return 0; |
| 191 | + } |
| 192 | + CPP |
| 193 | +
|
| 194 | + g++ -std=c++20 -O2 \ |
| 195 | + -static-libstdc++ -static-libgcc \ |
| 196 | + aevum-dll-smoke.cpp \ |
| 197 | + -o aevum-dll-smoke.exe |
| 198 | +
|
| 199 | + ./aevum-dll-smoke.exe "$DLL" |
| 200 | +
|
| 201 | + file "$DLL" |
| 202 | + objdump -p "$DLL" | sed -n '/Export Table/,$p' | \ |
| 203 | + grep -q 'aevum_engine_version' |
| 204 | +
|
68 | 205 | - name: Generate code signing certificate |
69 | 206 | shell: powershell |
70 | 207 | run: | |
@@ -97,20 +234,70 @@ jobs: |
97 | 234 | - name: Package |
98 | 235 | shell: powershell |
99 | 236 | run: | |
100 | | - mkdir prmers_package; mkdir prmers_package\kernels |
| 237 | + New-Item -ItemType Directory -Force ` |
| 238 | + -Path prmers_package, prmers_package\kernels | Out-Null |
| 239 | +
|
101 | 240 | Copy-Item build\Release\prmers.exe prmers_package\ |
102 | 241 | Copy-Item kernels\prmers.cl prmers_package\kernels\ |
103 | 242 | Copy-Item vcpkg\installed\x64-windows\bin\*.dll prmers_package\ |
| 243 | +
|
| 244 | + Copy-Item ` |
| 245 | + third_party\aevum\build-engine\aevum_engine.dll ` |
| 246 | + prmers_package\ |
| 247 | +
|
| 248 | + Copy-Item third_party\aevum\tune.txt prmers_package\ |
| 249 | +
|
| 250 | + if (Test-Path ` |
| 251 | + third_party\aevum\build-engine\libwinpthread-1.dll) { |
| 252 | + Copy-Item ` |
| 253 | + third_party\aevum\build-engine\libwinpthread-1.dll ` |
| 254 | + prmers_package\ |
| 255 | + } |
| 256 | +
|
| 257 | + $required = @( |
| 258 | + "prmers_package\prmers.exe", |
| 259 | + "prmers_package\aevum_engine.dll", |
| 260 | + "prmers_package\tune.txt", |
| 261 | + "prmers_package\kernels\prmers.cl" |
| 262 | + ) |
| 263 | +
|
| 264 | + foreach ($file in $required) { |
| 265 | + if (-not (Test-Path $file)) { |
| 266 | + throw "Missing Windows release file: $file" |
| 267 | + } |
| 268 | + } |
| 269 | +
|
104 | 270 | Compress-Archive -Path prmers_package\* ` |
105 | 271 | -DestinationPath prmers-windows.zip |
106 | 272 |
|
| 273 | + $entries = tar.exe -tf prmers-windows.zip |
| 274 | + $entries | Write-Host |
| 275 | +
|
| 276 | + if (-not ($entries -match "aevum_engine.dll")) { |
| 277 | + throw "aevum_engine.dll is absent from prmers-windows.zip" |
| 278 | + } |
| 279 | +
|
| 280 | + if (-not ($entries -match "tune.txt")) { |
| 281 | + throw "tune.txt is absent from prmers-windows.zip" |
| 282 | + } |
| 283 | +
|
107 | 284 | - name: Calculate SHA256 checksum |
108 | 285 | shell: powershell |
109 | 286 | run: | |
110 | 287 | $h = Get-FileHash -Algorithm SHA256 -Path prmers-windows.zip |
111 | 288 | $h.Hash | Out-File -Encoding ASCII -NoNewline prmers-windows.zip.sha256 |
112 | 289 |
|
| 290 | + - name: Upload Windows package artifact |
| 291 | + uses: actions/upload-artifact@v4 |
| 292 | + with: |
| 293 | + name: prmers-windows |
| 294 | + path: | |
| 295 | + prmers-windows.zip |
| 296 | + prmers-windows.zip.sha256 |
| 297 | + if-no-files-found: error |
| 298 | + |
113 | 299 | - name: Upload release to GitHub |
| 300 | + if: startsWith(github.ref, 'refs/tags/') |
114 | 301 | uses: softprops/action-gh-release@v2 |
115 | 302 | with: |
116 | 303 | files: | |
|
0 commit comments