Git Product home page Git Product logo

Comments (5)

bjorn3 avatar bjorn3 commented on August 23, 2024 2

The Discord GameSDK uses Rust too internally and exports rust_eh_personality for whatever reason. This rust_eh_personality conflicts with the one from the libstd copy used by your own program. Discord will have to fix their SDK to stop exporting rust_eh_personality. A normal cdylib build doesn't export rust_eh_personality. Without help from someone working at Discord it would be very hard to figure out why rust_eh_personality gets exported by their SDK.

from rust.

BenCheung0422 avatar BenCheung0422 commented on August 23, 2024

I may head to use discord-sdk crate instead, although the official SDK should still be usable. By the way, this is my simplified version of discord_game_sdk_sys/build.rs:

use std::{env, fs, path::*};
use std::fs::{create_dir_all, File};
use std::io::Write;
use zip::ZipArchive;

const SDK_VERSION: &str = "2.5.6";

fn main() {
    // DO NOT RELY ON THIS
    if cfg!(feature = "private-docs-rs") {
        return generate_ffi_bindings(bindgen::builder().header("discord_game_sdk.h"));
    }

    let sdk_path = fetch_discord_game_sdk();
    // println!("cargo:rustc-env=LD_LIBRARY_PATH={}", fs::canonicalize(sdk_path.join("lib/x86_64")).unwrap().display());
    // println!("cargo:rustc-env=DYLD_LIBRARY_PATH={}", fs::canonicalize(sdk_path.join("lib/x86_64")).unwrap().display());
    println!("cargo:rustc-link-search={}", fs::canonicalize(sdk_path.join("lib/x86_64")).unwrap().to_str().unwrap());
    println!("cargo:rerun-if-changed={}", sdk_path.display());

    generate_ffi_bindings(
        bindgen::builder().header(sdk_path.join("c/discord_game_sdk.h").to_str().unwrap()),
    );

    if cfg!(feature = "link") {
        let target = env::var("TARGET").unwrap();

        verify_installation(&target, &sdk_path);
        configure_linkage(&target, &sdk_path);
    }
}

fn fetch_discord_game_sdk() -> PathBuf {
    let mut sdk_version = SDK_VERSION.to_string();
    println!("Target Discord GameSDK: {sdk_version}");
    let main_dir = PathBuf::from("libraries");
    let extract_dir = main_dir.join("discord_game_sdk");
    create_dir_all(&extract_dir).unwrap();
    println!("Checking local cache...");

    // Check cached version
    let version_file_path = extract_dir.join("VERSION");
    if version_file_path.exists() {
        match fs::read_to_string(&version_file_path) {
            Ok(ver) => {
                if ver == sdk_version {
                    println!("Version matched, no upgrade required.");
                    return extract_dir;
                } else {
                    println!("Version not matched, an upgrade is required.");
                }
            }
            Err(err) => eprintln!("Error opening VERSION: {err}"),
        }
    }

    println!("Clearing cache directory...");
    if extract_dir.exists() {
        fs::remove_dir_all(&extract_dir).expect("remove directory");
        fs::create_dir(&extract_dir).expect("create directory");
    }

    println!("Fetching {sdk_version} SDK...");
    let download_path = main_dir.join("fetch.zip");
    reqwest::blocking::get(format!(
        "https://dl-game-sdk.discordapp.net/{sdk_version}/discord_game_sdk.zip"))
        .expect("request Discord Game SDK")
        .copy_to(&mut File::create(&download_path).expect("Discord Game SDK local cache"))
        .expect("download Discord Game SDK");
    ZipArchive::new(File::open(&download_path).expect("read download cache"))
        .expect("valid zip")
        .extract(&extract_dir)
        .expect("extract cached zip");
    fs::remove_file(download_path).expect("remove cached zip");
    File::create(version_file_path).expect("create VERSION")
        .write_all(unsafe { sdk_version.as_bytes_mut() }).expect("write VERSION");
    println!("SDK fetched.");

    // Prepare for library

    fs::rename(extract_dir.join("lib/x86_64/discord_game_sdk.so"),
               extract_dir.join("lib/x86_64/libdiscord_game_sdk.so")).unwrap();
    fs::rename(extract_dir.join("lib/x86_64/discord_game_sdk.dylib"),
               extract_dir.join("lib/x86_64/libdiscord_game_sdk.dylib")).unwrap();
    fs::rename(extract_dir.join("lib/x86_64/discord_game_sdk.dll.lib"),
               extract_dir.join("lib/x86_64/discord_game_sdk.lib")).unwrap();
    fs::rename(extract_dir.join("lib/x86/discord_game_sdk.dll.lib"),
               extract_dir.join("lib/x86/discord_game_sdk.lib")).unwrap();

    extract_dir
}

fn verify_installation(target: &str, sdk_path: &Path) {
    match target {
        "x86_64-unknown-linux-gnu" => {
            assert!(
                sdk_path.join("lib/x86_64/libdiscord_game_sdk.so").exists(),
                "{}",
                MISSING_SETUP
            );
        }

        "x86_64-apple-darwin" => {
            assert!(
                sdk_path
                    .join("lib/x86_64/libdiscord_game_sdk.dylib")
                    .exists(),
                "{}",
                MISSING_SETUP
            );
        }

        "x86_64-pc-windows-gnu" | "x86_64-pc-windows-msvc" => {
            assert!(
                sdk_path.join("lib/x86_64/discord_game_sdk.lib").exists(),
                "{}",
                MISSING_SETUP
            );
        }

        "i686-pc-windows-gnu" | "i686-pc-windows-msvc" => {
            assert!(
                sdk_path.join("lib/x86/discord_game_sdk.lib").exists(),
                "{}",
                MISSING_SETUP
            );
        }

        _ => panic!("{}", INCOMPATIBLE_PLATFORM),
    }
}

fn configure_linkage(target: &str, sdk_path: &Path) {
    match target {
        "x86_64-unknown-linux-gnu"
        | "x86_64-apple-darwin"
        | "x86_64-pc-windows-gnu"
        | "x86_64-pc-windows-msvc" => {
            println!("cargo:rustc-link-lib=discord_game_sdk");
            println!(
                "cargo:rustc-link-search={}",
                sdk_path.join("lib/x86_64").display()
            );
        }

        "i686-pc-windows-gnu" | "i686-pc-windows-msvc" => {
            println!("cargo:rustc-link-lib=discord_game_sdk");
            println!(
                "cargo:rustc-link-search={}",
                sdk_path.join("lib/x86").display()
            );
        }

        _ => {}
    }
}

fn generate_ffi_bindings(builder: bindgen::Builder) {
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());

    builder
        .ctypes_prefix("ctypes")
        .derive_copy(true)
        .derive_debug(true)
        .derive_default(true)
        .derive_eq(true)
        .derive_hash(true)
        .derive_partialeq(true)
        .generate_comments(false)
        .impl_debug(true)
        .impl_partialeq(true)
        .parse_callbacks(Box::new(Callbacks))
        .prepend_enum_name(false)
        .allowlist_function("Discord.+")
        .allowlist_type("[EI]?Discord.+")
        .allowlist_var("DISCORD_.+")
        .generate()
        .expect("discord_game_sdk_sys: bindgen could not generate bindings")
        .write_to_file(out_path.join("bindings.rs"))
        .expect("discord_game_sdk_sys: could not write bindings to file");
}

#[derive(Debug)]
struct Callbacks;

impl bindgen::callbacks::ParseCallbacks for Callbacks {
    fn int_macro(&self, name: &str, _value: i64) -> Option<bindgen::callbacks::IntKind> {
        // Must match sys::DiscordVersion
        if name.ends_with("_VERSION") {
            Some(bindgen::callbacks::IntKind::I32)
        } else {
            None
        }
    }
}

const MISSING_SETUP: &str = r#"

discord_game_sdk_sys: Hello,

You are trying to link to the Discord Game SDK.
Some additional set-up is required, namely some files need to be copied for the linker:

# Linux: prepend with `lib` and add to library search path
$ cp $DISCORD_GAME_SDK_PATH/lib/x86_64/{,lib}discord_game_sdk.so
$ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+${LD_LIBRARY_PATH}:}$DISCORD_GAME_SDK_PATH/lib/x86_64

# Mac OS: prepend with `lib` and add to library search path
$ cp $DISCORD_GAME_SDK_PATH/lib/x86_64/{,lib}discord_game_sdk.dylib
$ export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH:+${DYLD_LIBRARY_PATH}:}$DISCORD_GAME_SDK_PATH/lib/x86_64

# Windows: copy `*.dll.lib` to `*.lib` (won't affect library search)
$ cp $DISCORD_GAME_SDK_PATH/lib/x86_64/discord_game_sdk.{dll.lib,lib}
$ cp $DISCORD_GAME_SDK_PATH/lib/x86/discord_game_sdk.{dll.lib,lib}

After all this, `cargo build` and `cargo run` should function as expected.

Please report any issues you have at:
https://github.com/ldesgoui/discord_game_sdk

Thanks, and apologies for the inconvenience

"#;

const INCOMPATIBLE_PLATFORM: &str = r#"

discord_game_sdk_sys: Hello,

You are trying to link to the Discord Game SDK.
Unfortunately, the platform you are trying to target is not supported.

Please report any issues you have at:
https://github.com/ldesgoui/discord_game_sdk

Thanks, and apologies for the inconvenience

"#;

And discord_game_sdk_sys/Cargo.toml:

[build-dependencies]
bindgen = { version = "0.69.4", default-features = false, features = ["runtime"] }
reqwest = { version = "0.12.5", features = ["blocking"] }
zip = "2.1.3"

from rust.

BenCheung0422 avatar BenCheung0422 commented on August 23, 2024

Oh I see, so their SDK cannot be used in Rust as library at the moment. Perhaps this issue can be filed to Discord then?

from rust.

bjorn3 avatar bjorn3 commented on August 23, 2024

Yeah, that would be your best bet. Until they have fixed it, maybe you could try somehow patching the import library to remove the rust_eh_personality export?

from rust.

BenCheung0422 avatar BenCheung0422 commented on August 23, 2024

It can compile when I used

lib /MACHINE:X86 /def:discord_game_sdk.def /out:discord_game_sdk.lib

with

LIBRARY DISCORD_GAME_SDK
EXPORTS
    DiscordCreate  @1
    DiscordVersion @2

Reference: https://stackoverflow.com/a/280567

from rust.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.