turso_sdk_kit 0.7.2

Low-level C ABI for building Turso language bindings. For Rust applications, use the `turso` crate instead.
Documentation
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    println!("cargo::rerun-if-changed=build.rs");

    if env::var("CARGO_CFG_WINDOWS").is_err() {
        return;
    }

    let out_dir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR is set by Cargo"));
    let rc_path = out_dir.join("turso_sdk_kit_version.rc");
    let res_path = out_dir.join("turso_sdk_kit_version.res");
    let version = env::var("CARGO_PKG_VERSION").expect("CARGO_PKG_VERSION is set by Cargo");
    let file_version = file_version(&version);
    let file_version_commas = file_version.replace('.', ",");
    let rc = format!(
        r#"#define VS_FFI_FILEFLAGSMASK 0x0000003FL
#define VOS_NT_WINDOWS32 0x00040004L
#define VFT_DLL 0x00000002L
#define VFT2_UNKNOWN 0x00000000L

1 VERSIONINFO
FILEVERSION {file_version_commas}
PRODUCTVERSION {file_version_commas}
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
FILEFLAGS 0
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_DLL
FILESUBTYPE VFT2_UNKNOWN
BEGIN
  BLOCK "StringFileInfo"
  BEGIN
    BLOCK "040904b0"
    BEGIN
      VALUE "CompanyName", "Turso\0"
      VALUE "FileDescription", "Turso SDK Kit\0"
      VALUE "FileVersion", "{file_version}\0"
      VALUE "InternalName", "turso_sdk_kit\0"
      VALUE "LegalCopyright", "Copyright (c) 2026 Turso\0"
      VALUE "OriginalFilename", "turso_sdk_kit.dll\0"
      VALUE "ProductName", "Turso\0"
      VALUE "ProductVersion", "{version}\0"
    END
  END
  BLOCK "VarFileInfo"
  BEGIN
    VALUE "Translation", 0x0409, 1200
  END
END
"#
    );
    fs::write(&rc_path, rc).expect("write Windows version resource script");

    let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
    let status = if target_env == "msvc" {
        Command::new(find_windows_resource_compiler())
            .arg("/nologo")
            .arg(format!("/fo{}", res_path.display()))
            .arg(&rc_path)
            .status()
    } else {
        Command::new("windres")
            .arg(&rc_path)
            .arg("-O")
            .arg("coff")
            .arg("-o")
            .arg(&res_path)
            .status()
    }
    .expect("compile Windows version resource");

    assert!(
        status.success(),
        "Windows version resource compiler failed with status {status}"
    );

    println!("cargo::rustc-link-arg-cdylib={}", res_path.display());
}

fn find_windows_resource_compiler() -> PathBuf {
    if let Some(path) = find_in_path("rc.exe") {
        return path;
    }

    let Some(program_files_x86) = env::var_os("ProgramFiles(x86)") else {
        panic!("rc.exe was not found in PATH and ProgramFiles(x86) is not set");
    };
    let sdk_bin = PathBuf::from(program_files_x86)
        .join("Windows Kits")
        .join("10")
        .join("bin");
    let mut candidates = fs::read_dir(&sdk_bin)
        .unwrap_or_else(|error| {
            panic!(
                "rc.exe was not found in PATH and Windows SDK bin directory {} could not be read: {error}",
                sdk_bin.display()
            )
        })
        .filter_map(Result::ok)
        .map(|entry| entry.path().join("x64").join("rc.exe"))
        .filter(|path| path.exists())
        .collect::<Vec<_>>();
    candidates.sort();
    candidates
        .pop()
        .unwrap_or_else(|| panic!("rc.exe was not found under {}", sdk_bin.display()))
}

fn find_in_path(program: &str) -> Option<PathBuf> {
    let paths = env::var_os("PATH")?;
    env::split_paths(&paths)
        .map(|path| path.join(program))
        .find(|candidate| candidate.exists())
}

fn file_version(version: &str) -> String {
    let core = version.split_once('-').map_or(version, |(core, _)| core);
    let mut parts = core.split('.').map(|part| {
        part.parse::<u16>()
            .expect("Cargo package version components fit Windows VERSIONINFO")
    });
    let major = parts.next().unwrap_or(0);
    let minor = parts.next().unwrap_or(0);
    let patch = parts.next().unwrap_or(0);
    format!("{major}.{minor}.{patch}.0")
}