diff --git a/.gitea/workflows/prebuilt.yml b/.gitea/workflows/prebuilt.yml new file mode 100644 index 0000000..347ffa1 --- /dev/null +++ b/.gitea/workflows/prebuilt.yml @@ -0,0 +1,99 @@ +name: Prebuilt release + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + releases: write + +jobs: + prebuilt: + runs-on: ubuntu-latest + env: + CARGO_TERM_COLOR: always + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Install nightly Rust + uses: dtolnay/rust-toolchain@nightly + with: + targets: x86_64-pc-windows-gnu + + - name: Install MinGW and packaging tools + run: | + sudo apt-get update + sudo apt-get install -y mingw-w64 zip unzip jq + + - name: Build release binaries + env: + CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: x86_64-w64-mingw32-gcc + run: cargo build --release --target x86_64-pc-windows-gnu -p ext -p launcher + + - name: Package prebuilt release + run: | + set -euo pipefail + + rm -rf dist + mkdir -p dist + cp target/x86_64-pc-windows-gnu/release/hkrpg.dll dist/ + cp target/x86_64-pc-windows-gnu/release/launcher.exe dist/ + + test -f dist/hkrpg.dll + test -f dist/launcher.exe + + ( + cd dist + zip -9 -q ../hkrpg.zip hkrpg.dll launcher.exe + ) + unzip -l hkrpg.zip + + - name: Publish prebuilt release + env: + GITEA_API_URL: ${{ gitea.server_url }}/api/v1 + GITEA_REPOSITORY: ${{ gitea.repository }} + GITEA_SHA: ${{ gitea.sha }} + GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + run: | + set -euo pipefail + + api="${GITEA_API_URL}" + repo="${GITEA_REPOSITORY}" + tag="prebuilt" + auth=(-H "Authorization: token ${GITEA_TOKEN}" -H "Accept: application/json") + + release_status="$(curl -sS "${auth[@]}" -o release.json -w '%{http_code}' \ + "${api}/repos/${repo}/releases/tags/${tag}" || true)" + + case "${release_status}" in + 200) + ;; + 404) + curl -fsS -X POST "${auth[@]}" \ + -H "Content-Type: application/json" \ + -d "{\"tag_name\":\"${tag}\",\"target_commitish\":\"${GITEA_SHA}\",\"name\":\"${tag}\",\"body\":\"Automated prebuilt binaries for ${GITEA_SHA}\",\"draft\":false,\"prerelease\":false}" \ + "${api}/repos/${repo}/releases" > release.json + ;; + *) + cat release.json + exit 1 + ;; + esac + + release_id="$(jq -er '.id' release.json)" + assets="$(curl -fsS "${auth[@]}" \ + "${api}/repos/${repo}/releases/${release_id}/assets")" + + while read -r asset_id; do + test -z "${asset_id}" || curl -fsS -X DELETE "${auth[@]}" \ + "${api}/repos/${repo}/releases/${release_id}/assets/${asset_id}" + done < <(printf '%s' "${assets}" | jq -r '.[] | select(.name == "hkrpg.zip") | .id') + + curl -fsS -X POST "${auth[@]}" \ + -F "attachment=@hkrpg.zip;type=application/zip" \ + "${api}/repos/${repo}/releases/${release_id}/assets?name=hkrpg.zip" diff --git a/Cargo.toml b/Cargo.toml index 27f0ad0..d569974 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,12 @@ resolver = "2" [workspace.package] version = "0.1.0" +[profile.release] +opt-level = "z" +lto = true +codegen-units = 1 +strip = true + [workspace.dependencies] windows = { version = "0.54.0", features = [ "Win32_Foundation", diff --git a/hkrpg/src/lib.rs b/hkrpg/src/lib.rs index 9554897..72a3063 100644 --- a/hkrpg/src/lib.rs +++ b/hkrpg/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(str_from_utf16_endian, once_cell_get_mut)] +#![feature(once_cell_get_mut)] use std::{thread, time::Duration}; diff --git a/launcher/build.rs b/launcher/build.rs index ce39353..2706be1 100644 --- a/launcher/build.rs +++ b/launcher/build.rs @@ -1,4 +1,54 @@ +use std::{env, fs, path::PathBuf, process::Command}; + fn main() { - println!("cargo:rustc-link-arg-bin=launcher=/MANIFEST:EMBED"); - println!("cargo:rustc-link-arg-bin=launcher=/MANIFESTUAC:level=\'requireAdministrator\'"); + match env::var("CARGO_CFG_TARGET_ENV").as_deref() { + Ok("msvc") => { + println!("cargo:rustc-link-arg-bin=launcher=/MANIFEST:EMBED"); + println!("cargo:rustc-link-arg-bin=launcher=/MANIFESTUAC:level='requireAdministrator'"); + } + Ok("gnu") => { + let Some(out_dir) = env::var_os("OUT_DIR") else { + return; + }; + + let out_dir = PathBuf::from(out_dir); + let manifest = out_dir.join("launcher.manifest"); + let resource = out_dir.join("launcher.rc"); + let object = out_dir.join("launcher-manifest.o"); + + if fs::write(&manifest, MANIFEST).is_err() || fs::write(&resource, RESOURCE).is_err() { + return; + } + + let Ok(status) = Command::new("x86_64-w64-mingw32-windres") + .current_dir(&out_dir) + .args(["launcher.rc", "-O", "coff", "-o"]) + .arg(&object) + .status() + else { + return; + }; + + if !status.success() { + return; + } + + println!("cargo:rustc-link-arg-bin=launcher={}", object.display()); + } + _ => {} + } } + +const RESOURCE: &str = "1 24 \"launcher.manifest\"\n"; + +const MANIFEST: &str = r#" + + + + + + + + + +"#;