Skip to content

Library API Overview ​

msvc-kit can be used as a Rust library for programmatic access to MSVC toolchain management.

Installation ​

Add to your Cargo.toml:

toml
[dependencies]
msvc-kit = "0.2"
tokio = { version = "1", features = ["full"] }

Quick Example ​

rust
use msvc_kit::{
    download_msvc, download_sdk, extract_and_finalize_msvc, extract_and_finalize_sdk,
    setup_environment, DownloadOptions,
};

#[tokio::main]
async fn main() -> msvc_kit::Result<()> {
    // Download with default options
    let options = DownloadOptions::default();
    
    let mut msvc_info = download_msvc(&options).await?;
    let sdk_info = download_sdk(&options).await?;
    extract_and_finalize_msvc(&mut msvc_info).await?;
    extract_and_finalize_sdk(&sdk_info).await?;
    
    // Setup environment
    let env = setup_environment(&msvc_info, Some(&sdk_info))?;
    
    // Access paths
    println!("cl.exe: {:?}", env.cl_exe_path());
    println!("INCLUDE: {}", env.include_path_string());
    println!("LIB: {}", env.lib_path_string());
    
    Ok(())
}

Main Types ​

Version Discovery Functions ​

rust
/// Fetch available versions from Microsoft servers
pub async fn list_available_versions() -> Result<AvailableVersions>;

/// Available version information
pub struct AvailableVersions {
    pub msvc_versions: Vec<String>,  // e.g., ["14.44", "14.43", "14.42"]
    pub sdk_versions: Vec<String>,   // e.g., ["10.0.26100.0", "10.0.22621.0"]
    pub latest_msvc: Option<String>, // e.g., Some("14.44")
    pub latest_sdk: Option<String>,  // e.g., Some("10.0.26100.0")
    /// Visual Studio channel that served the versions, e.g.
    /// Some("Visual Studio 2026 (v18)"). `None` for callers that build the
    /// value themselves; with automatic selection the channel depends on what
    /// upstream has published.
    pub channel: Option<String>,
}

Example:

rust
use msvc_kit::list_available_versions;

#[tokio::main]
async fn main() -> msvc_kit::Result<()> {
    let versions = list_available_versions().await?;
    
    println!("Latest MSVC: {:?}", versions.latest_msvc);
    println!("Latest SDK: {:?}", versions.latest_sdk);
    
    println!("\nAvailable MSVC versions:");
    for v in &versions.msvc_versions {
        println!("  {}", v);
    }
    Ok(())
}

Download Functions ​

rust
/// Download MSVC compiler components
pub async fn download_msvc(options: &DownloadOptions) -> Result<InstallInfo>;

/// Download Windows SDK components
pub async fn download_sdk(options: &DownloadOptions) -> Result<InstallInfo>;

download_msvc and download_sdk only fetch payloads. Call extract_and_finalize_msvc / extract_and_finalize_sdk before passing the returned InstallInfo to setup_environment.

rust
/// Extract downloaded MSVC payloads and update the full MSVC version
pub async fn extract_and_finalize_msvc(info: &mut InstallInfo) -> Result<()>;

/// Extract downloaded Windows SDK payloads
pub async fn extract_and_finalize_sdk(info: &InstallInfo) -> Result<()>;

Environment Functions ​

rust
/// Setup environment from install info
pub fn setup_environment(
    msvc_info: &InstallInfo,
    sdk_info: Option<&InstallInfo>,
) -> Result<MsvcEnvironment>;

/// Get environment variables as HashMap
pub fn get_env_vars(env: &MsvcEnvironment) -> HashMap<String, String>;

Script Generation Functions ​

rust
/// Generate portable scripts (relative paths, for bundles)
pub fn generate_portable_scripts(ctx: &ScriptContext) -> Result<GeneratedScripts>;

/// Generate absolute path scripts (for installed environments)
pub fn generate_absolute_scripts(ctx: &ScriptContext) -> Result<GeneratedScripts>;

/// Generate a single script for specified shell
pub fn generate_script(ctx: &ScriptContext, shell: ShellType) -> Result<String>;

/// Save scripts to a directory
pub async fn save_scripts(
    scripts: &GeneratedScripts,
    output_dir: &Path,
    base_name: &str,
) -> Result<()>;

Script Context ​

rust
/// Create portable script context (uses relative paths like %~dp0)
let ctx = ScriptContext::portable(
    "14.44.34823",      // MSVC version
    "10.0.26100.0",     // SDK version
    Architecture::X64,   // Target arch
    Architecture::X64,   // Host arch
);

/// Create absolute script context (uses actual paths)
let ctx = ScriptContext::absolute(
    PathBuf::from("C:/msvc-kit"),
    "14.44.34823",
    "10.0.26100.0",
    Architecture::X64,
    Architecture::X64,
);

Configuration Functions ​

rust
/// Load configuration from disk
pub fn load_config() -> Result<MsvcKitConfig>;

/// Load stored settings without transient environment overrides
pub fn load_persisted_config() -> Result<MsvcKitConfig>;

/// Save configuration to disk
pub fn save_config(config: &MsvcKitConfig) -> Result<()>;

Configuration Location ​

rust
/// File name of the CLI configuration file
pub const CONFIG_FILE_NAME: &str = "config.toml";

/// Marker file that switches an installation into portable mode
pub const PORTABLE_MARKER_FILE: &str = "msvc-kit.portable";

/// Environment variable pointing at a specific configuration file or directory
pub const CONFIG_ENV_VAR: &str = "MSVC_KIT_CONFIG";

/// Environment variable that enables portable mode
pub const PORTABLE_ENV_VAR: &str = "MSVC_KIT_PORTABLE";

/// Resolved configuration file location
///
/// Precedence: `--config` / `set_config_path_override` > `MSVC_KIT_CONFIG`
/// > portable mode (`config.toml` next to the executable)
/// > per-user configuration directory.
pub fn get_config_path() -> PathBuf;

/// Directory holding the running executable, if it can be determined
pub fn exe_dir() -> Option<PathBuf>;

/// Whether the installation stores its configuration next to the executable
pub fn is_portable_mode() -> bool;

/// Pin the configuration file for the rest of the process (CLI `--config`)
pub fn set_config_path_override(path: impl Into<PathBuf>);

/// Explicit configuration path set with `set_config_path_override`
pub fn config_path_override() -> Option<PathBuf>;

/// Drop an explicit configuration path
pub fn clear_config_path_override();

/// Create the portable marker file next to the executable
pub fn enable_portable_mode() -> Result<()>;

/// Remove the portable marker file
pub fn disable_portable_mode() -> Result<()>;

Re-exported Types ​

rust
pub use config::MsvcKitConfig;
pub use downloader::{DownloadOptions, AvailableVersions, list_available_versions};
pub use env::{MsvcEnvironment, ToolPaths};
pub use error::{MsvcKitError, Result};
pub use installer::InstallInfo;
pub use scripts::{GeneratedScripts, ScriptContext, ShellType};
pub use version::{Architecture, MsvcVersion, SdkVersion};

Error Handling ​

All functions return msvc_kit::Result<T>:

rust
use msvc_kit::{download_msvc, DownloadOptions, MsvcKitError};

async fn example() {
    let options = DownloadOptions::default();
    
    match download_msvc(&options).await {
        Ok(info) => println!("Installed to {:?}", info.install_path),
        Err(MsvcKitError::Network(e)) => eprintln!("Network error: {}", e),
        Err(MsvcKitError::VersionNotFound(v)) => eprintln!("Version not found: {}", v),
        Err(e) => eprintln!("Error: {}", e),
    }
}

Feature Flags ​

msvc-kit provides optional features to reduce dependency conflicts:

FeatureDefaultPulls in
self-updateyesaxoupdater
native-tlsyesreqwest/native-tls (SChannel on Windows)
rustls-tlsnoreqwest/rustls

self-update (default) ​

Enables the msvc-kit update command, which queries GitHub Releases through axoupdater. The binary itself is only built when the feature is enabled, so library users can drop it.

toml
# Include self-update (default)
[dependencies]
msvc-kit = "0.2"

# Or explicitly enable
[dependencies]
msvc-kit = { version = "0.2", features = ["self-update"] }

Library-only Usage (No Self-update) ​

toml
[dependencies]
msvc-kit = { version = "0.2", default-features = false }

Thread Safety ​

  • DownloadOptions, InstallInfo, MsvcEnvironment are Send + Sync
  • Download functions are async and can be called from any runtime
  • Configuration lives in a single TOML file with no locking, so concurrent msvc-kit config writes from separate processes can race

Next Steps ​

Released under the MIT License.