Windows exes carry the coin icon and a version block (the project lead's rule, 4 Oct 2026)
Every Windows executable now ships with the coin icon Explorer shows and the version block Properties shows
(CompanyName Igneum, ProductName Igneum Miner, FileDescription per exe, 0.3.0, LegalCopyright Igneum contributors),
like the Mac app and DMG already do.
- igneumd.exe, igneum-miner.exe: packaging/windows/embed-resources.sh now takes the worktree and target dir
(defaults vendor/igneum-node-v4 and vendor/igneum-node/target-integration) and relinks with a linker shim first in
PATH instead of `cargo rustc -- -C link-arg`: cargo rustc takes one package and unifies features differently from
the two-package cross-build (300 crates differ), and a configured linker is fingerprinted and rebuilds everything;
the PATH shim changes neither. .rc files moved to 0.3.0.
- igneum-worker-cuda.exe, igneum-worker-opencl.exe: proto-cuda/nvrtc/build-windows.sh compiles the two new .rc
files with windres and links the objects; the icon is made with make-icons.py if missing.
- igneum-app.exe: app/igneum-app/build.rs runs windres on resources/igneum-app.rc for Windows targets and links it
(cargo:rustc-link-arg-bins, no crate dependency); it fails the build if the .rc version drifts from Cargo.toml.
- packaging/windows/resources/verify-exe.py: small PE parser that checks the .rsrc section, icon group and version
strings on the Mac; both build scripts call it, and it checks every exe inside the packages.
- proto-opencl/cl_dynamic.h: clGetEventInfo added to the run-time loader table (4714b51 added the call in host.c
without it, so the one-click OpenCL worker no longer linked under IGNEUM_CL_DYNAMIC).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
4714b510f2
commit
d69d70c3fc
11 changed files with 498 additions and 100 deletions
|
|
@ -5,6 +5,7 @@ edition = "2021"
|
|||
description = "Igneum Miner engine: supervises the node, the miner and the GPU workers, and serves the dashboard on 127.0.0.1"
|
||||
license = "MIT"
|
||||
publish = false
|
||||
build = "build.rs" # Windows targets: links resources/igneum-app.rc (coin icon, version block) into the exe
|
||||
|
||||
[[bin]]
|
||||
name = "igneum-app"
|
||||
|
|
|
|||
80
app/igneum-app/build.rs
Normal file
80
app/igneum-app/build.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Build script for igneum-app. On a Windows target it compiles resources/igneum-app.rc (the coin icon Explorer shows
|
||||
// and the version block under Properties > Details) with windres and links the object into igneum-app.exe. Other
|
||||
// targets: nothing. the project lead's rule (4 October 2026): every shipped exe carries the coin icon and a version block, like the
|
||||
// Mac app and DMG. No crate dependency: windres is called directly (x86_64-w64-mingw32-windres from Homebrew mingw-w64
|
||||
// on the Mac, windres from MSYS2 on a PC; IGNEUM_WINDRES names another one).
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let manifest = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
|
||||
let rc = manifest.join("resources").join("igneum-app.rc");
|
||||
let icons = manifest.join("..").join("..").join("brand").join("icons");
|
||||
let ico = icons.join("igneum.ico");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed={}", rc.display());
|
||||
println!("cargo:rerun-if-changed={}", ico.display());
|
||||
println!("cargo:rerun-if-env-changed=IGNEUM_WINDRES");
|
||||
if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") {
|
||||
return;
|
||||
}
|
||||
// The .rc carries the version by hand; it must agree with Cargo.toml so Properties shows the number the app reports.
|
||||
let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION");
|
||||
let text = fs::read_to_string(&rc).unwrap_or_else(|e| panic!("cannot read {}: {e}", rc.display()));
|
||||
let numeric = format!("{},0", version.replace('.', ","));
|
||||
if !text.contains(&format!("\"{version}\"")) || !text.contains(&numeric) {
|
||||
panic!(
|
||||
"{} must carry version {version} (FILEVERSION/PRODUCTVERSION {numeric}, FileVersion/ProductVersion \"{version}\")",
|
||||
rc.display()
|
||||
);
|
||||
}
|
||||
if !ico.is_file() {
|
||||
panic!("no {}; run python3 brand/icons/make-icons.py first", ico.display());
|
||||
}
|
||||
let windres = match find_windres() {
|
||||
Some(w) => w,
|
||||
None => {
|
||||
if env::var("CARGO_CFG_TARGET_ENV").as_deref() == Ok("msvc") {
|
||||
println!("cargo:warning=no windres found: igneum-app.exe is built without the coin icon and version block (set IGNEUM_WINDRES)");
|
||||
return;
|
||||
}
|
||||
panic!("no windres found (brew install mingw-w64, or set IGNEUM_WINDRES): igneum-app.exe must carry the coin icon and version block");
|
||||
}
|
||||
};
|
||||
let out = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR")).join("igneum-app.res.o");
|
||||
let status = Command::new(&windres)
|
||||
.arg("-I").arg(&icons)
|
||||
.arg("-i").arg(&rc)
|
||||
.arg("-O").arg("coff")
|
||||
.arg("-o").arg(&out)
|
||||
.status()
|
||||
.unwrap_or_else(|e| panic!("cannot run {windres}: {e}"));
|
||||
if !status.success() {
|
||||
panic!("{windres} failed on {} ({status})", rc.display());
|
||||
}
|
||||
println!("cargo:rustc-link-arg-bins={}", out.display());
|
||||
}
|
||||
|
||||
fn find_windres() -> Option<String> {
|
||||
let mut candidates = Vec::new();
|
||||
if let Ok(w) = env::var("IGNEUM_WINDRES") {
|
||||
if !w.is_empty() {
|
||||
candidates.push(w);
|
||||
}
|
||||
}
|
||||
let prefix = match env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default().as_str() {
|
||||
"x86_64" => Some("x86_64-w64-mingw32"),
|
||||
"x86" => Some("i686-w64-mingw32"),
|
||||
"aarch64" => Some("aarch64-w64-mingw32"),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(p) = prefix {
|
||||
candidates.push(format!("{p}-windres"));
|
||||
}
|
||||
candidates.push("windres".to_string());
|
||||
candidates
|
||||
.into_iter()
|
||||
.find(|c| Command::new(c).arg("--version").output().map(|o| o.status.success()).unwrap_or(false))
|
||||
}
|
||||
35
app/igneum-app/resources/igneum-app.rc
Normal file
35
app/igneum-app/resources/igneum-app.rc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Windows resources for igneum-app.exe: the coin icon Explorer shows and the version block under Properties > Details.
|
||||
// Compiled with x86_64-w64-mingw32-windres (the icon path is relative to brand/icons, passed with -I).
|
||||
// the project lead's rule (4 October 2026): every shipped exe carries the coin icon and a version block, like the Mac app and DMG.
|
||||
#include <winver.h>
|
||||
|
||||
1 ICON "igneum.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,3,0,0
|
||||
PRODUCTVERSION 0,3,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Igneum"
|
||||
VALUE "FileDescription", "Igneum Miner engine"
|
||||
VALUE "FileVersion", "0.3.0"
|
||||
VALUE "InternalName", "igneum-app"
|
||||
VALUE "LegalCopyright", "Igneum contributors"
|
||||
VALUE "OriginalFilename", "igneum-app.exe"
|
||||
VALUE "ProductName", "Igneum Miner"
|
||||
VALUE "ProductVersion", "0.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
|
@ -1,61 +1,107 @@
|
|||
#!/usr/bin/env bash
|
||||
# Gives igneumd.exe and igneum-miner.exe the coin icon and a version block (CompanyName Igneum, ProductName
|
||||
# Igneum Miner, 0.1.0). Two steps, both on the Mac:
|
||||
# Gives igneumd.exe and igneum-miner.exe the coin icon and the version block Explorer shows under Properties > Details
|
||||
# (CompanyName Igneum, ProductName Igneum Miner, 0.3.0). the project lead's rule (4 October 2026): every shipped exe carries the
|
||||
# coin icon and a version block, like the Mac app and DMG. Two steps, both on the Mac:
|
||||
# 1. windres compiles resources/igneumd.rc and resources/igneum-miner.rc into COFF objects (cheap, always done).
|
||||
# 2. --relink runs `cargo rustc` for each binary with `-C link-arg=<object>`: only the final crate is recompiled and
|
||||
# relinked, every dependency comes from the cache, so it costs a few minutes after a normal cross-build. The
|
||||
# objects are linked in as extra inputs, nothing in vendor/ changes. Without --relink the exact commands are
|
||||
# printed, and build-installer.ps1 stamps the resources with rcedit on the PC instead.
|
||||
# The resulting exes land where proto-cuda/windows-app/make-package.sh already picks them up
|
||||
# (vendor/igneum-node-win/target/x86_64-pc-windows-gnu/release/).
|
||||
# 2. --relink runs the same cargo build as proto-cuda/windows-node/cross-build.sh (same packages, features and
|
||||
# environment, so every cached dependency is reused) with a linker shim first in PATH: a script named
|
||||
# x86_64-w64-mingw32-gcc (the linker rustc picks for x86_64-pc-windows-gnu) that runs the real one and appends
|
||||
# the matching object whenever the output being linked is igneumd-<hash>.exe or igneum-miner-<hash>.exe. The two
|
||||
# exes are removed from deps/ first so cargo relinks them even when nothing changed. Nothing in vendor/ changes.
|
||||
# Why not `cargo rustc -- -C link-arg=<obj>`: it takes one package, and a one-package selection unifies features
|
||||
# differently from the two-package cross-build (300 crates differ, checked 4 Oct 2026), so it would rebuild half
|
||||
# the tree and ship a differently-featured miner. Why PATH and not CARGO_TARGET_..._LINKER: cargo puts the
|
||||
# configured linker in its fingerprints, so that rebuilds every crate (checked on app/igneum-app the same day).
|
||||
# The exes land in <target dir>/x86_64-pc-windows-gnu/release/, where proto-cuda/windows-app/make-package.sh and
|
||||
# packaging/windows/make-payload.sh pick them up. Without --relink only the objects are compiled and the command is
|
||||
# printed (build-installer.ps1 can stamp the resources with rcedit on the PC instead).
|
||||
#
|
||||
# packaging/windows/embed-resources.sh compile the objects, print the relink commands
|
||||
# packaging/windows/embed-resources.sh --relink also relink both exes (needs a completed cross-build in the cache)
|
||||
# Usage: packaging/windows/embed-resources.sh [--relink] [worktree] [target dir]
|
||||
# worktree the node checkout to build, default vendor/igneum-node-v4 (or NODE_WORKTREE)
|
||||
# target dir CARGO_TARGET_DIR, default vendor/igneum-node/target-integration (or CARGO_TARGET_DIR); relative paths
|
||||
# are taken from the repository root
|
||||
# JOBS=n cargo jobs, default 4
|
||||
set -euo pipefail
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT="$(cd "$HERE/../.." && pwd)"
|
||||
ICONS="$ROOT/brand/icons"
|
||||
OUT="$HERE/build/res"
|
||||
NODE="${NODE_WORKTREE:-$ROOT/vendor/igneum-node-win}"
|
||||
VERIFY="$HERE/resources/verify-exe.py"
|
||||
MINGW="/opt/homebrew/opt/mingw-w64/toolchain-x86_64/x86_64-w64-mingw32"
|
||||
RELINK=0
|
||||
if [ "${1:-}" = "--relink" ]; then RELINK=1; shift; fi
|
||||
NODE="${1:-${NODE_WORKTREE:-$ROOT/vendor/igneum-node-v4}}"
|
||||
TD="${2:-${CARGO_TARGET_DIR:-$ROOT/vendor/igneum-node/target-integration}}"
|
||||
case "$NODE" in /*) ;; *) NODE="$ROOT/$NODE" ;; esac
|
||||
case "$TD" in /*) ;; *) TD="$ROOT/$TD" ;; esac
|
||||
JOBS="${JOBS:-4}"
|
||||
command -v x86_64-w64-mingw32-windres >/dev/null || { echo "x86_64-w64-mingw32-windres not found (brew install mingw-w64)" >&2; exit 1; }
|
||||
[ -f "$ICONS/igneum.ico" ] || { echo "no $ICONS/igneum.ico; run python3 brand/icons/make-icons.py first" >&2; exit 1; }
|
||||
[ -f "$ICONS/igneum.ico" ] || { echo "no $ICONS/igneum.ico, making the icons"; python3 "$ICONS/make-icons.py"; }
|
||||
[ -d "$NODE" ] || { echo "no worktree at $NODE" >&2; exit 1; }
|
||||
mkdir -p "$OUT"
|
||||
for name in igneumd igneum-miner; do
|
||||
x86_64-w64-mingw32-windres -I "$ICONS" -i "$HERE/resources/$name.rc" -O coff -o "$OUT/$name.res.o"
|
||||
echo "compiled $OUT/$name.res.o ($(stat -f %z "$OUT/$name.res.o") bytes)"
|
||||
done
|
||||
|
||||
# The linker shim: the real x86_64-w64-mingw32-gcc plus the resource object for the exe being linked
|
||||
REAL_GCC="$(command -v x86_64-w64-mingw32-gcc)" || { echo "x86_64-w64-mingw32-gcc not found" >&2; exit 1; }
|
||||
SHIM="$HERE/build/linker-shim"
|
||||
rm -rf "$SHIM" && mkdir -p "$SHIM"
|
||||
cat > "$SHIM/x86_64-w64-mingw32-gcc" <<SHIM_SH
|
||||
#!/bin/bash
|
||||
# Written by packaging/windows/embed-resources.sh: runs the real linker and appends the resource object for the exe
|
||||
# being linked (igneumd-<hash>.exe or igneum-miner-<hash>.exe, found after -o, also inside a @response file).
|
||||
REAL="$REAL_GCC"
|
||||
RES="$OUT"
|
||||
out=""
|
||||
prev=""
|
||||
for a in "\$@"; do
|
||||
case "\$a" in @*) if [ -f "\${a#@}" ]; then
|
||||
p2=""; for w in \$(cat "\${a#@}"); do if [ "\$p2" = "-o" ]; then out="\$w"; fi; p2="\$w"; done
|
||||
fi ;; esac
|
||||
if [ "\$prev" = "-o" ]; then out="\$a"; fi
|
||||
prev="\$a"
|
||||
done
|
||||
case "\$(basename "\$out")" in
|
||||
igneumd-*.exe|igneumd.exe) exec "\$REAL" "\$@" "\$RES/igneumd.res.o" ;;
|
||||
igneum-miner-*.exe|igneum_miner-*.exe|igneum-miner.exe) exec "\$REAL" "\$@" "\$RES/igneum-miner.res.o" ;;
|
||||
esac
|
||||
exec "\$REAL" "\$@"
|
||||
SHIM_SH
|
||||
chmod +x "$SHIM/x86_64-w64-mingw32-gcc"
|
||||
|
||||
# The same environment as proto-cuda/windows-node/cross-build.sh, so the cached dependencies are reused.
|
||||
export PATH="$HOME/.cargo/bin:/opt/homebrew/bin:$PATH"
|
||||
export CARGO_TARGET_DIR="${CARGO_TARGET_DIR:-target}"
|
||||
export CARGO_TARGET_DIR="$TD"
|
||||
export CC_x86_64_pc_windows_gnu=x86_64-w64-mingw32-gcc
|
||||
export CXX_x86_64_pc_windows_gnu=x86_64-w64-mingw32-g++
|
||||
export AR_x86_64_pc_windows_gnu=x86_64-w64-mingw32-ar
|
||||
export LIBCLANG_PATH=/opt/homebrew/opt/llvm/lib
|
||||
export BINDGEN_EXTRA_CLANG_ARGS_x86_64_pc_windows_gnu="--target=x86_64-w64-mingw32 --sysroot=$MINGW -I$MINGW/include"
|
||||
export CARGO_TARGET_X86_64_PC_WINDOWS_GNU_RUSTFLAGS="-C link-arg=-static -C link-arg=-static-libgcc"
|
||||
REL="$TD/x86_64-pc-windows-gnu/release"
|
||||
BUILD="nice -n 19 cargo build --release -j $JOBS -p kaspad -p igneum-miner --features igneum-pow --target x86_64-pc-windows-gnu"
|
||||
|
||||
relink_cmd() { # $1 package, $2 bin, $3 object
|
||||
printf 'nice -n 19 cargo rustc --release -j 2 -p %s --bin %s --features igneum-pow --target x86_64-pc-windows-gnu -- -C link-arg=%q\n' "$1" "$2" "$3"
|
||||
}
|
||||
if [ "${1:-}" = "--relink" ]; then
|
||||
if [ "$RELINK" = 1 ]; then
|
||||
cd "$NODE"
|
||||
for spec in "kaspad igneumd" "igneum-miner igneum-miner"; do
|
||||
set -- $spec
|
||||
echo "relinking $2.exe"
|
||||
eval "$(relink_cmd "$1" "$2" "$OUT/$2.res.o")"
|
||||
exe="$CARGO_TARGET_DIR/x86_64-pc-windows-gnu/release/$2.exe"
|
||||
x86_64-w64-mingw32-objdump -h "$exe" | grep -q '\.rsrc' && echo "$exe: .rsrc section present ($(stat -f %z "$exe") bytes)" || { echo "$exe has no .rsrc section" >&2; exit 1; }
|
||||
echo "worktree $NODE at $(git rev-parse --short HEAD) ($(git status --porcelain | grep -v '^??' | wc -l | tr -d ' ') modified files), target dir $TD"
|
||||
rm -f "$REL"/deps/igneumd-*.exe "$REL"/deps/igneum-miner-*.exe "$REL"/deps/igneum_miner-*.exe
|
||||
PATH="$SHIM:$PATH" $BUILD
|
||||
for exe in igneumd igneum-miner; do
|
||||
f="$REL/$exe.exe"
|
||||
x86_64-w64-mingw32-objdump -h "$f" | grep -q '\.rsrc' || { echo "$f has no .rsrc section" >&2; exit 1; }
|
||||
echo "$f: $(stat -f %z "$f") bytes; DLLs: $(x86_64-w64-mingw32-objdump -p "$f" | grep 'DLL Name' | awk '{print $3}' | sort -u | tr '\n' ' ')"
|
||||
done
|
||||
python3 "$VERIFY" --version 0.3.0 "$REL/igneumd.exe" "$REL/igneum-miner.exe"
|
||||
else
|
||||
cat <<TXT
|
||||
|
||||
Not relinked (no --relink). After the next cross-build (proto-cuda/windows-node/cross-build.sh), from $NODE
|
||||
with the same environment variables as that script, run:
|
||||
$(relink_cmd kaspad igneumd "$OUT/igneumd.res.o")
|
||||
$(relink_cmd igneum-miner igneum-miner "$OUT/igneum-miner.res.o")
|
||||
Then proto-cuda/windows-app/make-package.sh ships the branded exes. Check with:
|
||||
x86_64-w64-mingw32-objdump -h vendor/igneum-node-win/target/x86_64-pc-windows-gnu/release/igneum-miner.exe | grep rsrc
|
||||
Not relinked (no --relink). To relink from $NODE into $TD, run with the same environment as
|
||||
proto-cuda/windows-node/cross-build.sh, the shim first in PATH, and the old exes removed from $REL/deps/:
|
||||
PATH=$SHIM:\$PATH $BUILD
|
||||
Or simply: $0 --relink${1:+ $1}${2:+ $2}
|
||||
Then proto-cuda/windows-app/make-package.sh and packaging/windows/make-payload.sh ship the branded exes. Check with:
|
||||
python3 $VERIFY --version 0.3.0 $REL/igneumd.exe $REL/igneum-miner.exe
|
||||
TXT
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,34 +1,35 @@
|
|||
// Windows resources for igneum-miner.exe: the coin icon and the version block Explorer shows under Properties > Details.
|
||||
// Compiled by embed-resources.sh with x86_64-w64-mingw32-windres (icon path relative to brand/icons, passed with -I).
|
||||
#include <winver.h>
|
||||
|
||||
1 ICON "igneum.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,1,0,0
|
||||
PRODUCTVERSION 0,1,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Igneum"
|
||||
VALUE "FileDescription", "Igneum Miner"
|
||||
VALUE "FileVersion", "0.1.0"
|
||||
VALUE "InternalName", "igneum-miner"
|
||||
VALUE "LegalCopyright", "Igneum. Nothing is bought or sold."
|
||||
VALUE "OriginalFilename", "igneum-miner.exe"
|
||||
VALUE "ProductName", "Igneum Miner"
|
||||
VALUE "ProductVersion", "0.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
// Windows resources for igneum-miner.exe: the coin icon Explorer shows and the version block under Properties > Details.
|
||||
// Compiled with x86_64-w64-mingw32-windres (the icon path is relative to brand/icons, passed with -I).
|
||||
// the project lead's rule (4 October 2026): every shipped exe carries the coin icon and a version block, like the Mac app and DMG.
|
||||
#include <winver.h>
|
||||
|
||||
1 ICON "igneum.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,3,0,0
|
||||
PRODUCTVERSION 0,3,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Igneum"
|
||||
VALUE "FileDescription", "Igneum Miner lottery miner"
|
||||
VALUE "FileVersion", "0.3.0"
|
||||
VALUE "InternalName", "igneum-miner"
|
||||
VALUE "LegalCopyright", "Igneum contributors"
|
||||
VALUE "OriginalFilename", "igneum-miner.exe"
|
||||
VALUE "ProductName", "Igneum Miner"
|
||||
VALUE "ProductVersion", "0.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
|
|
|||
|
|
@ -1,34 +1,35 @@
|
|||
// Windows resources for igneumd.exe: the coin icon and the version block Explorer shows under Properties > Details.
|
||||
// Compiled by embed-resources.sh with x86_64-w64-mingw32-windres (icon path relative to brand/icons, passed with -I).
|
||||
#include <winver.h>
|
||||
|
||||
1 ICON "igneum.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,1,0,0
|
||||
PRODUCTVERSION 0,1,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Igneum"
|
||||
VALUE "FileDescription", "Igneum Miner node"
|
||||
VALUE "FileVersion", "0.1.0"
|
||||
VALUE "InternalName", "igneumd"
|
||||
VALUE "LegalCopyright", "Igneum. Nothing is bought or sold."
|
||||
VALUE "OriginalFilename", "igneumd.exe"
|
||||
VALUE "ProductName", "Igneum Miner"
|
||||
VALUE "ProductVersion", "0.1.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
// Windows resources for igneumd.exe: the coin icon Explorer shows and the version block under Properties > Details.
|
||||
// Compiled with x86_64-w64-mingw32-windres (the icon path is relative to brand/icons, passed with -I).
|
||||
// the project lead's rule (4 October 2026): every shipped exe carries the coin icon and a version block, like the Mac app and DMG.
|
||||
#include <winver.h>
|
||||
|
||||
1 ICON "igneum.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,3,0,0
|
||||
PRODUCTVERSION 0,3,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Igneum"
|
||||
VALUE "FileDescription", "Igneum Miner node"
|
||||
VALUE "FileVersion", "0.3.0"
|
||||
VALUE "InternalName", "igneumd"
|
||||
VALUE "LegalCopyright", "Igneum contributors"
|
||||
VALUE "OriginalFilename", "igneumd.exe"
|
||||
VALUE "ProductName", "Igneum Miner"
|
||||
VALUE "ProductVersion", "0.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
|
|
|||
147
packaging/windows/resources/verify-exe.py
Executable file
147
packaging/windows/resources/verify-exe.py
Executable file
|
|
@ -0,0 +1,147 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Checks that a Windows exe carries the Igneum resources: a .rsrc section with an icon group and a version block whose
|
||||
CompanyName is Igneum and ProductName is Igneum Miner. Prints what it finds. Small PE parser, no dependencies, runs on
|
||||
the Mac where rcedit and Explorer are not available.
|
||||
python3 verify-exe.py [--version 0.3.0] exe [exe ...] exit 1 if any exe fails"""
|
||||
import struct, sys
|
||||
|
||||
RT_ICON, RT_GROUP_ICON, RT_VERSION = 3, 14, 16
|
||||
REQUIRED = ("CompanyName", "ProductName", "FileDescription", "FileVersion", "ProductVersion", "LegalCopyright")
|
||||
|
||||
|
||||
def sections_of(data):
|
||||
pe = struct.unpack_from("<I", data, 0x3C)[0]
|
||||
if data[pe:pe + 4] != b"PE\0\0":
|
||||
raise ValueError("not a PE file")
|
||||
nsec, opt_size = struct.unpack_from("<H", data, pe + 6)[0], struct.unpack_from("<H", data, pe + 20)[0]
|
||||
opt = pe + 24
|
||||
magic = struct.unpack_from("<H", data, opt)[0]
|
||||
dd = opt + (112 if magic == 0x20B else 96)
|
||||
res_rva, res_size = struct.unpack_from("<II", data, dd + 2 * 8)
|
||||
secs = []
|
||||
for i in range(nsec):
|
||||
s = opt + opt_size + 40 * i
|
||||
name = data[s:s + 8].rstrip(b"\0").decode("latin1")
|
||||
vsize, vaddr, rsize, raw = struct.unpack_from("<IIII", data, s + 8)
|
||||
secs.append((name, vaddr, max(vsize, rsize), raw))
|
||||
return secs, res_rva, res_size
|
||||
|
||||
|
||||
def rva_to_off(secs, rva):
|
||||
for _, vaddr, size, raw in secs:
|
||||
if vaddr <= rva < vaddr + size:
|
||||
return raw + (rva - vaddr)
|
||||
raise ValueError("rva 0x%x outside every section" % rva)
|
||||
|
||||
|
||||
def walk(data, base, off, depth, found, path=()):
|
||||
named, ids = struct.unpack_from("<HH", data, base + off + 12)
|
||||
for i in range(named + ids):
|
||||
e = base + off + 16 + 8 * i
|
||||
ident, child = struct.unpack_from("<II", data, e)
|
||||
if child & 0x80000000:
|
||||
walk(data, base, child & 0x7FFFFFFF, depth + 1, found, path + (ident,))
|
||||
else:
|
||||
rva, size = struct.unpack_from("<II", data, base + child)
|
||||
found.append((path + (ident,), rva, size))
|
||||
|
||||
|
||||
def version_strings(data, off, size):
|
||||
"""Parses VS_VERSIONINFO into (fixed FileVersion tuple, {key: value})."""
|
||||
end = off + size
|
||||
|
||||
def block(pos):
|
||||
length, vlen, vtype = struct.unpack_from("<HHH", data, pos)
|
||||
key_end = pos + 6
|
||||
while data[key_end:key_end + 2] != b"\0\0":
|
||||
key_end += 2
|
||||
key = data[pos + 6:key_end].decode("utf-16-le")
|
||||
val = (key_end + 2 + 3) & ~3
|
||||
return length, vlen, vtype, key, val
|
||||
|
||||
strings, fixed = {}, None
|
||||
length, vlen, _, key, val = block(off)
|
||||
if vlen >= 52 and struct.unpack_from("<I", data, val)[0] == 0xFEEF04BD:
|
||||
ms, ls, pms, pls = struct.unpack_from("<IIII", data, val + 8)
|
||||
fixed = (ms >> 16, ms & 0xFFFF, ls >> 16, ls & 0xFFFF, pms >> 16, pms & 0xFFFF, pls >> 16, pls & 0xFFFF)
|
||||
pos = (val + vlen + 3) & ~3
|
||||
while pos < off + length:
|
||||
clen, _, _, ckey, cval = block(pos)
|
||||
if ckey == "StringFileInfo":
|
||||
tpos = cval
|
||||
while tpos < pos + clen:
|
||||
tlen, _, _, _, tval = block(tpos)
|
||||
spos = tval
|
||||
while spos < tpos + tlen:
|
||||
slen, svlen, _, skey, sval = block(spos)
|
||||
if slen == 0:
|
||||
break
|
||||
raw = data[sval:sval + 2 * svlen]
|
||||
strings[skey] = raw.decode("utf-16-le").rstrip("\0")
|
||||
spos = (spos + slen + 3) & ~3
|
||||
tpos = (tpos + tlen + 3) & ~3
|
||||
if clen == 0:
|
||||
break
|
||||
pos = (pos + clen + 3) & ~3
|
||||
return fixed, strings
|
||||
|
||||
|
||||
def check(path, want_version):
|
||||
data = open(path, "rb").read()
|
||||
secs, res_rva, res_size = sections_of(data)
|
||||
names = [s[0] for s in secs]
|
||||
problems = []
|
||||
if ".rsrc" not in names:
|
||||
problems.append("no .rsrc section")
|
||||
if not res_rva:
|
||||
problems.append("resource table empty in the PE data directory")
|
||||
icons = groups = 0
|
||||
fixed, strings = None, {}
|
||||
if res_rva:
|
||||
base = rva_to_off(secs, res_rva)
|
||||
found = []
|
||||
walk(data, base, 0, 0, found)
|
||||
for p, rva, size in found:
|
||||
if p[0] == RT_ICON:
|
||||
icons += 1
|
||||
elif p[0] == RT_GROUP_ICON:
|
||||
groups += 1
|
||||
elif p[0] == RT_VERSION and fixed is None:
|
||||
fixed, strings = version_strings(data, rva_to_off(secs, rva), size)
|
||||
if not groups:
|
||||
problems.append("no icon group (RT_GROUP_ICON)")
|
||||
if fixed is None:
|
||||
problems.append("no version block (RT_VERSION)")
|
||||
for k in REQUIRED:
|
||||
if not strings.get(k):
|
||||
problems.append("missing " + k)
|
||||
if strings.get("CompanyName") not in (None, "Igneum"):
|
||||
problems.append("CompanyName is %r, not Igneum" % strings["CompanyName"])
|
||||
if strings.get("ProductName") not in (None, "Igneum Miner"):
|
||||
problems.append("ProductName is %r, not Igneum Miner" % strings["ProductName"])
|
||||
if want_version:
|
||||
for k in ("FileVersion", "ProductVersion"):
|
||||
if strings.get(k) and strings[k] != want_version:
|
||||
problems.append("%s is %s, not %s" % (k, strings[k], want_version))
|
||||
if fixed and ".".join(map(str, fixed[:3])) != want_version:
|
||||
problems.append("FILEVERSION is %s, not %s" % (".".join(map(str, fixed[:4])), want_version))
|
||||
print("%s: %d bytes, sections %s" % (path, len(data), " ".join(names)))
|
||||
print(" icon images %d, icon groups %d, FILEVERSION %s" % (icons, groups, ".".join(map(str, fixed[:4])) if fixed else "none"))
|
||||
for k in REQUIRED + ("InternalName", "OriginalFilename"):
|
||||
if k in strings:
|
||||
print(" %-17s %s" % (k, strings[k]))
|
||||
for p in problems:
|
||||
print(" FAIL: " + p)
|
||||
return not problems
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = sys.argv[1:]
|
||||
want = None
|
||||
if args[:1] == ["--version"]:
|
||||
want, args = args[1], args[2:]
|
||||
if not args:
|
||||
sys.exit(__doc__)
|
||||
ok = all([check(p, want) for p in args])
|
||||
print("all %d exe(s) carry the Igneum resources" % len(args) if ok else "FAILED")
|
||||
sys.exit(0 if ok else 1)
|
||||
|
|
@ -5,27 +5,43 @@
|
|||
# proto-opencl/igneum-worker-opencl.exe host.c with IGNEUM_CL_DYNAMIC (OpenCL.dll loaded at run time) and the generic
|
||||
# --pack serve mode; the pack it is built against is only a placeholder
|
||||
# Static libgcc/libstdc++/winpthread, so each exe needs only KERNEL32 and the Universal CRT (Windows 10 and 11 have it).
|
||||
# Each exe carries the coin icon and a version block (igneum-worker-cuda.rc, igneum-worker-opencl.rc, compiled with windres
|
||||
# and linked in; the project lead's rule, 4 October 2026: every shipped exe shows the coin in Explorer and a publisher in Properties).
|
||||
# Usage: build-windows.sh (then windows-app/make-package.sh ships them with the NVRTC DLLs)
|
||||
set -euo pipefail
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT="$(cd "$HERE/../.." && pwd)"
|
||||
RED="$HERE/redist"
|
||||
ICONS="$ROOT/brand/icons"
|
||||
[ -f "$RED/include/cuda.h" ] && [ -f "$RED/include/nvrtc.h" ] && [ -f "$RED/include/CL/cl.h" ] || { echo "run $HERE/fetch-redist.sh first" >&2; exit 1; }
|
||||
CXX=x86_64-w64-mingw32-g++
|
||||
CC=x86_64-w64-mingw32-gcc
|
||||
STRIP=x86_64-w64-mingw32-strip
|
||||
WINDRES=x86_64-w64-mingw32-windres
|
||||
command -v "$WINDRES" >/dev/null || { echo "$WINDRES not found (brew install mingw-w64)" >&2; exit 1; }
|
||||
PLACEHOLDER="$ROOT/proto-cuda/packs/igneum-devnet-v4-epoch0"
|
||||
VERIFY="$ROOT/packaging/windows/resources/verify-exe.py"
|
||||
|
||||
# The coin icon and the version blocks, as COFF objects the linker takes like any other input
|
||||
[ -f "$ICONS/igneum.ico" ] || { echo "== no $ICONS/igneum.ico, making the icons"; python3 "$ICONS/make-icons.py"; }
|
||||
RES="$(mktemp -d)"
|
||||
for w in cuda opencl; do
|
||||
"$WINDRES" -I "$ICONS" -i "$HERE/igneum-worker-$w.rc" -O coff -o "$RES/igneum-worker-$w.res.o"
|
||||
done
|
||||
|
||||
echo "== igneum-worker-cuda.exe"
|
||||
"$CXX" -std=c++17 -O2 -Wall -Wextra -static -I "$HERE" -I "$RED/include" -o "$HERE/igneum-worker-cuda.exe" "$HERE/worker.cpp"
|
||||
"$CXX" -std=c++17 -O2 -Wall -Wextra -static -I "$HERE" -I "$RED/include" -o "$HERE/igneum-worker-cuda.exe" "$HERE/worker.cpp" "$RES/igneum-worker-cuda.res.o"
|
||||
"$STRIP" "$HERE/igneum-worker-cuda.exe"
|
||||
echo "== igneum-worker-opencl.exe"
|
||||
"$CC" -std=c99 -O2 -Wall -Wextra -Wno-stringop-truncation -Wno-format-truncation -static -DIGNEUM_CL_DYNAMIC -DCL_TARGET_OPENCL_VERSION=120 \
|
||||
-I "$RED/include" -I "$PLACEHOLDER" -DIGNEUM_KERNEL_PATH='"kernel_bound.cl"' \
|
||||
-o "$ROOT/proto-opencl/igneum-worker-opencl.exe" "$ROOT/proto-opencl/host.c"
|
||||
-o "$ROOT/proto-opencl/igneum-worker-opencl.exe" "$ROOT/proto-opencl/host.c" "$RES/igneum-worker-opencl.res.o"
|
||||
"$STRIP" "$ROOT/proto-opencl/igneum-worker-opencl.exe"
|
||||
rm -rf "$RES"
|
||||
for exe in "$HERE/igneum-worker-cuda.exe" "$ROOT/proto-opencl/igneum-worker-opencl.exe"; do
|
||||
printf '%s: %d bytes, imports:' "$(basename "$exe")" "$(stat -f %z "$exe")"
|
||||
x86_64-w64-mingw32-objdump -p "$exe" | sed -n 's/^[[:space:]]*DLL Name: //p' | tr '\n' ' '
|
||||
echo
|
||||
done
|
||||
# the icon and version block survived the strip (strip keeps .rsrc; this proves it)
|
||||
python3 "$VERIFY" --version 0.3.0 "$HERE/igneum-worker-cuda.exe" "$ROOT/proto-opencl/igneum-worker-opencl.exe"
|
||||
|
|
|
|||
35
proto-cuda/nvrtc/igneum-worker-cuda.rc
Normal file
35
proto-cuda/nvrtc/igneum-worker-cuda.rc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Windows resources for igneum-worker-cuda.exe: the coin icon Explorer shows and the version block under Properties > Details.
|
||||
// Compiled with x86_64-w64-mingw32-windres (the icon path is relative to brand/icons, passed with -I).
|
||||
// the project lead's rule (4 October 2026): every shipped exe carries the coin icon and a version block, like the Mac app and DMG.
|
||||
#include <winver.h>
|
||||
|
||||
1 ICON "igneum.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,3,0,0
|
||||
PRODUCTVERSION 0,3,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Igneum"
|
||||
VALUE "FileDescription", "Igneum Miner CUDA worker"
|
||||
VALUE "FileVersion", "0.3.0"
|
||||
VALUE "InternalName", "igneum-worker-cuda"
|
||||
VALUE "LegalCopyright", "Igneum contributors"
|
||||
VALUE "OriginalFilename", "igneum-worker-cuda.exe"
|
||||
VALUE "ProductName", "Igneum Miner"
|
||||
VALUE "ProductVersion", "0.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
35
proto-cuda/nvrtc/igneum-worker-opencl.rc
Normal file
35
proto-cuda/nvrtc/igneum-worker-opencl.rc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// Windows resources for igneum-worker-opencl.exe: the coin icon Explorer shows and the version block under Properties > Details.
|
||||
// Compiled with x86_64-w64-mingw32-windres (the icon path is relative to brand/icons, passed with -I).
|
||||
// the project lead's rule (4 October 2026): every shipped exe carries the coin icon and a version block, like the Mac app and DMG.
|
||||
#include <winver.h>
|
||||
|
||||
1 ICON "igneum.ico"
|
||||
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 0,3,0,0
|
||||
PRODUCTVERSION 0,3,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEFLAGS 0x0L
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904B0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Igneum"
|
||||
VALUE "FileDescription", "Igneum Miner OpenCL worker"
|
||||
VALUE "FileVersion", "0.3.0"
|
||||
VALUE "InternalName", "igneum-worker-opencl"
|
||||
VALUE "LegalCopyright", "Igneum contributors"
|
||||
VALUE "OriginalFilename", "igneum-worker-opencl.exe"
|
||||
VALUE "ProductName", "Igneum Miner"
|
||||
VALUE "ProductVersion", "0.3.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
X(clCreateCommandQueue) X(clCreateProgramWithSource) X(clBuildProgram) X(clGetProgramBuildInfo) X(clCreateKernel) \
|
||||
X(clSetKernelArg) X(clEnqueueNDRangeKernel) X(clEnqueueReadBuffer) X(clEnqueueWriteBuffer) X(clCreateBuffer) \
|
||||
X(clReleaseMemObject) X(clReleaseKernel) X(clReleaseProgram) X(clReleaseCommandQueue) X(clReleaseContext) \
|
||||
X(clFinish) X(clWaitForEvents) X(clReleaseEvent) X(clGetEventProfilingInfo) X(clGetKernelWorkGroupInfo) \
|
||||
X(clFinish) X(clWaitForEvents) X(clReleaseEvent) X(clGetEventInfo) X(clGetEventProfilingInfo) X(clGetKernelWorkGroupInfo) \
|
||||
X(clGetExtensionFunctionAddressForPlatform)
|
||||
|
||||
/* One pointer per entry point, typed from the header's declaration (so a signature drift is a compile error). */
|
||||
|
|
@ -72,6 +72,7 @@ static int ig_cl_load(void) {
|
|||
#define clFinish ig_clFinish
|
||||
#define clWaitForEvents ig_clWaitForEvents
|
||||
#define clReleaseEvent ig_clReleaseEvent
|
||||
#define clGetEventInfo ig_clGetEventInfo
|
||||
#define clGetEventProfilingInfo ig_clGetEventProfilingInfo
|
||||
#define clGetKernelWorkGroupInfo ig_clGetKernelWorkGroupInfo
|
||||
#define clGetExtensionFunctionAddressForPlatform ig_clGetExtensionFunctionAddressForPlatform
|
||||
|
|
|
|||
Loading…
Reference in a new issue