Compare commits
1 commit
master
...
wip/buildi
Author | SHA1 | Date | |
---|---|---|---|
5bd6ae7df0 |
8 changed files with 300 additions and 4 deletions
108
.ci/image/Dockerfile
Normal file
108
.ci/image/Dockerfile
Normal file
|
@ -0,0 +1,108 @@
|
|||
FROM rust:slim-bullseye
|
||||
|
||||
RUN set -eux; \
|
||||
apt-get update; \
|
||||
apt-get install --no-install-recommends -y \
|
||||
build-essential \
|
||||
curl \
|
||||
gpg \
|
||||
jq \
|
||||
libatk1.0-dev \
|
||||
libclang-13-dev \
|
||||
libglib2.0-dev \
|
||||
libgtk-3-dev \
|
||||
libpango1.0-dev \
|
||||
libssl-dev \
|
||||
libzstd-dev \
|
||||
pkg-config; \
|
||||
apt-get remove -y --auto-remove; \
|
||||
rm -rf /var/lib/apt/lists/*; \
|
||||
rustup default nightly
|
||||
|
||||
# https://jake-shadle.github.io/xwin/
|
||||
|
||||
ENV KEYRINGS /usr/local/share/keyrings
|
||||
ARG XWIN_VERSION=0.2.11
|
||||
ARG XWIN_PREFIX="xwin-$XWIN_VERSION-x86_64-unknown-linux-musl"
|
||||
ARG LLVM_VERSION=16
|
||||
|
||||
ADD https://apt.llvm.org/llvm-snapshot.gpg.key /root/llvm-snapshot.gpg.key
|
||||
ADD https://dl.winehq.org/wine-builds/winehq.key /root/winehq.key
|
||||
ADD https://github.com/Jake-Shadle/xwin/releases/download/$XWIN_VERSION/$XWIN_PREFIX.tar.gz /root/$XWIN_PREFIX.tar.gz
|
||||
|
||||
RUN set -eux; \
|
||||
mkdir -p $KEYRINGS; \
|
||||
# clang/lld/llvm
|
||||
gpg --dearmor > $KEYRINGS/llvm.gpg < /root/llvm-snapshot.gpg.key; \
|
||||
# wine
|
||||
gpg --dearmor > $KEYRINGS/winehq.gpg < /root/winehq.key; \
|
||||
echo "deb [signed-by=$KEYRINGS/llvm.gpg] http://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-${LLVM_VERSION} main" > /etc/apt/sources.list.d/llvm.list; \
|
||||
echo "deb [signed-by=$KEYRINGS/winehq.gpg] https://dl.winehq.org/wine-builds/debian/ bullseye main" > /etc/apt/sources.list.d/winehq.list; \
|
||||
dpkg --add-architecture i386; \
|
||||
apt-get update; \
|
||||
apt-get install --no-install-recommends -y \
|
||||
libclang-${LLVM_VERSION}-dev \
|
||||
gcc-mingw-w64-x86-64 \
|
||||
clang-${LLVM_VERSION} \
|
||||
llvm-${LLVM_VERSION} \
|
||||
lld-${LLVM_VERSION} \
|
||||
winehq-staging \
|
||||
tar; \
|
||||
# ensure that clang/clang++ are callable directly
|
||||
ln -s clang-${LLVM_VERSION} /usr/bin/clang && ln -s clang /usr/bin/clang++ && ln -s lld-${LLVM_VERSION} /usr/bin/ld.lld; \
|
||||
# We also need to setup symlinks ourselves for the MSVC shims because they aren't in the debian packages
|
||||
ln -s clang-${LLVM_VERSION} /usr/bin/clang-cl && ln -s llvm-ar-${LLVM_VERSION} /usr/bin/llvm-lib && ln -s lld-link-${LLVM_VERSION} /usr/bin/lld-link; \
|
||||
# Verify the symlinks are correct
|
||||
clang++ -v; \
|
||||
ld.lld -v; \
|
||||
# Doesn't have an actual -v/--version flag, but it still exits with 0
|
||||
llvm-lib -v; \
|
||||
clang-cl -v; \
|
||||
lld-link --version; \
|
||||
# Use clang instead of gcc when compiling and linking binaries targeting the host (eg proc macros, build files)
|
||||
update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100; \
|
||||
update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 100; \
|
||||
update-alternatives --install /usr/bin/ld ld /usr/bin/ld.lld 100; \
|
||||
rustup target add x86_64-pc-windows-msvc; \
|
||||
rustup component add rust-src; \
|
||||
# Install xwin to cargo/bin via github release. Note you could also just use `cargo install xwin`.
|
||||
tar -xzv -f /root/$XWIN_PREFIX.tar.gz -C /usr/local/cargo/bin --strip-components=1 $XWIN_PREFIX/xwin; \
|
||||
# Splat the CRT and SDK files to /xwin/crt and /xwin/sdk respectively
|
||||
xwin --accept-license splat --include-debug-libs --output /xwin; \
|
||||
# Remove unneeded files to reduce image size
|
||||
apt-get remove -y --auto-remove; \
|
||||
rm -rf \
|
||||
.xwin-cache \
|
||||
/usr/local/cargo/bin/xwin \
|
||||
/root/$XWIN_PREFIX.tar.gz \
|
||||
/var/lib/apt/lists/* \
|
||||
/root/*.key;
|
||||
|
||||
# Note that we're using the full target triple for each variable instead of the
|
||||
# simple CC/CXX/AR shorthands to avoid issues when compiling any C/C++ code for
|
||||
# build dependencies that need to compile and execute in the host environment
|
||||
ENV CC_x86_64_pc_windows_msvc="clang-cl" \
|
||||
CXX_x86_64_pc_windows_msvc="clang-cl" \
|
||||
AR_x86_64_pc_windows_msvc="llvm-lib" \
|
||||
# wine can be quite spammy with log messages and they're generally uninteresting
|
||||
WINEDEBUG="-all" \
|
||||
# Use wine to run test executables
|
||||
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUNNER="wine" \
|
||||
# Note that we only disable unused-command-line-argument here since clang-cl
|
||||
# doesn't implement all of the options supported by cl, but the ones it doesn't
|
||||
# are _generally_ not interesting.
|
||||
CL_FLAGS="-Wno-unused-command-line-argument -fuse-ld=lld-link /imsvc/xwin/crt/include /imsvc/xwin/sdk/include/ucrt /imsvc/xwin/sdk/include/um /imsvc/xwin/sdk/include/shared" \
|
||||
# Let cargo know what linker to invoke if you haven't already specified it
|
||||
# in a .cargo/config.toml file
|
||||
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER="lld-link" \
|
||||
CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_RUSTFLAGS="-Lnative=/xwin/crt/lib/x86_64 -Lnative=/xwin/sdk/lib/um/x86_64 -Lnative=/xwin/sdk/lib/ucrt/x86_64"
|
||||
|
||||
# These are separate since docker/podman won't transform environment variables defined in the same ENV block
|
||||
ENV CFLAGS_x86_64_pc_windows_msvc="$CL_FLAGS" \
|
||||
CXXFLAGS_x86_64_pc_windows_msvc="$CL_FLAGS"
|
||||
|
||||
# Run wineboot just to setup the default WINEPREFIX so we don't do it every
|
||||
# container run
|
||||
RUN wine wineboot --init
|
||||
|
||||
WORKDIR /src/dt_p2p
|
10
Cargo.toml
10
Cargo.toml
|
@ -7,3 +7,13 @@ members = [
|
|||
|
||||
# [profile.dev.package.backtrace]
|
||||
# opt-level = 3
|
||||
|
||||
[profile.release]
|
||||
strip = "debuginfo"
|
||||
|
||||
# The MSVC toolchain cannot handle LTO properly. Some symbol related to
|
||||
# panic unwind would always be missing.
|
||||
# So we use a separate profile for when we can compile with LTO.
|
||||
[profile.release-lto]
|
||||
inherits = "release"
|
||||
lto = true
|
||||
|
|
35
Dockerfile
Normal file
35
Dockerfile
Normal file
|
@ -0,0 +1,35 @@
|
|||
FROM dtmt-ci-base-msvc
|
||||
|
||||
# Create dummy crates and copy their Cargo.toml, so that dependencies can be cached
|
||||
RUN set -e; \
|
||||
cargo new --bin crates/dtmt; \
|
||||
cargo new --bin crates/dtmm; \
|
||||
cargo new --lib lib/dtmt-shared; \
|
||||
cargo new --lib lib/nexusmods; \
|
||||
cargo new --lib lib/sdk; \
|
||||
cargo new --lib lib/serde_sjson; \
|
||||
cargo new --lib lib/steamlocate-rs
|
||||
|
||||
COPY Cargo.toml Cargo.lock /src/dtmt/
|
||||
COPY crates/dtmt/Cargo.toml /src/dtmt/crates/dtmt/
|
||||
COPY crates/dtmm/Cargo.toml /src/dtmt/crates/dtmm/
|
||||
COPY lib/dtmt-shared/Cargo.toml /src/dtmt/lib/dtmt-shared/
|
||||
COPY lib/nexusmods/Cargo.toml /src/dtmt/lib/nexusmods/
|
||||
COPY lib/sdk/Cargo.toml /src/dtmt/lib/sdk/
|
||||
COPY lib/serde_sjson/Cargo.toml /src/dtmt/lib/serde_sjson/
|
||||
COPY lib/steamlocate-rs/Cargo.toml /src/dtmt/lib/steamlocate-rs/
|
||||
|
||||
# Crates with build scripts cannot be split that way, but they shouldn't change too often
|
||||
COPY lib/luajit2-sys /src/dtmt/lib/luajit2-sys
|
||||
COPY lib/oodle /src/dtmt/lib/oodle
|
||||
# color-eyre needs to be copied, too, then, as it's used by `oodle`
|
||||
COPY lib/color-eyre /src/dtmt/lib/color-eyre
|
||||
COPY --from=dtmt-ci-base-msvc /src/*.lib /src/dtmt/lib/oodle/
|
||||
|
||||
RUN cargo build --release --target x86_64-pc-windows-msvc --locked -Zbuild-std
|
||||
RUN rm -r crates lib
|
||||
|
||||
COPY . /src/dtmt
|
||||
COPY --from=dtmt-ci-base-msvc /src/*.lib /src/dtmt/lib/oodle/
|
||||
|
||||
RUN cargo build --release --target x86_64-pc-windows-msvc --frozen -Zbuild-std
|
12
Justfile
Normal file
12
Justfile
Normal file
|
@ -0,0 +1,12 @@
|
|||
image_name := 'dt_p2p-ci-base'
|
||||
|
||||
ci-build:
|
||||
docker run --rm -ti --user $(id -u) -v ./:/src/dt_p2p {{ image_name }} cargo --color always build --target x86_64-pc-windows --locked -Zbuild-std
|
||||
|
||||
build-image:
|
||||
docker build -f .ci/Dockerfile .
|
||||
|
||||
ci-image:
|
||||
docker build -t {{ image_name }} .ci/image
|
||||
docker tag {{ image_name }} registry.sclu1034.dev/{{ image_name }}
|
||||
docker push registry.sclu1034.dev/{{ image_name }}
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.144"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib", "lib"]
|
||||
|
|
|
@ -10,6 +10,7 @@ fn main() {
|
|||
|
||||
let bindings = bindgen::Builder::default()
|
||||
.header(HEADER_NAME)
|
||||
.rustified_enum("PluginApiID")
|
||||
.clang_arg("-Istingray_sdk/")
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
|
||||
.generate()
|
||||
|
@ -19,4 +20,10 @@ fn main() {
|
|||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
bindings
|
||||
.write_to_file(out_path.join("../../../bindings.rs"))
|
||||
.expect("Couldn't write bindings to debug path");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,53 @@
|
|||
mod stingray_sdk;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::ffi::c_char;
|
||||
use std::ffi::CString;
|
||||
|
||||
use stingray_sdk::GetApiFunction;
|
||||
use stingray_sdk::PluginApi;
|
||||
use stingray_sdk::PluginApiID;
|
||||
|
||||
use crate::stingray_sdk::LoggingApi;
|
||||
|
||||
const PLUGIN_NAME: &str = "dt_p2p";
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_name() -> *const c_char {
|
||||
let s = CString::new(PLUGIN_NAME).expect("Failed to create CString from plugin name");
|
||||
s.as_ptr()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn setup_game(get_engine_api: GetApiFunction) {
|
||||
println!("setup_game");
|
||||
|
||||
let log = LoggingApi::get(get_engine_api);
|
||||
|
||||
log.info(
|
||||
PLUGIN_NAME,
|
||||
format!("Hello, world! This is {}!", PLUGIN_NAME),
|
||||
);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn shutdown_game() {
|
||||
println!("shutdown_game");
|
||||
|
||||
// log.info(PLUGIN_NAME, format!("Goodbye, world!", PLUGIN_NAME));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_plugin_api(id: PluginApiID) -> *mut PluginApi {
|
||||
if id == PluginApiID::PLUGIN_API_ID {
|
||||
let api = PluginApi {
|
||||
get_name: Some(get_name),
|
||||
setup_game: Some(setup_game),
|
||||
shutdown_game: Some(shutdown_game),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Box::into_raw(Box::new(api))
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,4 +4,80 @@
|
|||
#![allow(clippy::type_complexity)]
|
||||
#![allow(unused)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
mod bindings {
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
}
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::c_char;
|
||||
use std::os::raw::c_void;
|
||||
|
||||
pub use bindings::GetApiFunction;
|
||||
pub use bindings::PluginApi;
|
||||
pub use bindings::PluginApiID;
|
||||
|
||||
impl std::default::Default for PluginApi {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: 65,
|
||||
flags: 3,
|
||||
fn_0: std::ptr::null_mut(),
|
||||
fn_1: std::ptr::null_mut(),
|
||||
fn_2: std::ptr::null_mut(),
|
||||
fn_3: std::ptr::null_mut(),
|
||||
fn_4: std::ptr::null_mut(),
|
||||
fn_5: std::ptr::null_mut(),
|
||||
setup_game: None,
|
||||
update_game: None,
|
||||
shutdown_game: None,
|
||||
fn_9: std::ptr::null_mut(),
|
||||
fn_10: std::ptr::null_mut(),
|
||||
fn_11: std::ptr::null_mut(),
|
||||
get_name: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_engine_api(f: GetApiFunction, id: PluginApiID) -> *mut c_void {
|
||||
let f = if cfg!(debug_assertions) {
|
||||
f.expect("'GetApiFunction' is always passed by the engine")
|
||||
} else {
|
||||
// `Option::unwrap` still generates several instructions in
|
||||
// optimized code.
|
||||
unsafe { f.unwrap_unchecked() }
|
||||
};
|
||||
|
||||
unsafe { f(id as u32) }
|
||||
}
|
||||
|
||||
pub struct LoggingApi {
|
||||
info: unsafe extern "C" fn(*const c_char, *const c_char),
|
||||
warning: unsafe extern "C" fn(*const c_char, *const c_char),
|
||||
error: unsafe extern "C" fn(*const c_char, *const c_char),
|
||||
}
|
||||
|
||||
impl LoggingApi {
|
||||
pub fn get(f: GetApiFunction) -> Self {
|
||||
let api = unsafe {
|
||||
let api = get_engine_api(f, PluginApiID::LOGGING_API_ID);
|
||||
api as *mut bindings::LoggingApi
|
||||
};
|
||||
|
||||
unsafe {
|
||||
Self {
|
||||
info: (*api).info.unwrap_unchecked(),
|
||||
warning: (*api).warning.unwrap_unchecked(),
|
||||
error: (*api).error.unwrap_unchecked(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn info(&self, system: impl Into<Vec<u8>>, message: impl Into<Vec<u8>>) {
|
||||
let f = self.info;
|
||||
let system = CString::new(system).expect("Invalid CString");
|
||||
let message = CString::new(message).expect("Invalid CString");
|
||||
unsafe {
|
||||
f(system.as_ptr(), message.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue