Installs Portable MSVC tools in user space
Project description
portablemsvc
PortableMSVC is a command-line utility for downloading, extracting, and managing a fully portable Microsoft C/C++ toolchain (MSVC + Windows SDK) on Windows, without requiring a full Visual Studio install.
Features
- Fetch the latest (or specified) MSVC toolset and Windows SDK from the official Visual Studio release channel
- Download and extract ZIPs, VSIX, MSI, and embedded CABs with pure-Python MSI extraction by default
- Preserve
msiexecextraction as an explicit fallback path - Prune unneeded files (debug symbols, telemetry, etc.) to minimize disk usage
- Generate
env.json,activate.cmd,activate.ps1, andactivate.xshfor easy environment setup - Support for xonsh, PowerShell, and Command Prompt activation
- Register/unregister toolchains in HKCU\Environment, with automatic PATH backup
- Maintain multiple portable installs side-by-side via a simple JSON database
- Plumbum-based CLI with subcommands for listing, installing, and managing toolchains
Requirements
- Windows 10+
- Python 3.10+
msiexec.exeon PATH only when usingPORTABLEMSVC_MSI_EXTRACTOR=msiexecorfallback
Installation
Using UV (https://github.com/astral-sh/uv) Recommended
uv tool install portablemsvc
The UV tool bin directory may need to be added to PATH.
Without installing
uvx portablemsvc --help
uvx portablemsvc search
Using pip
python -m pip install portablemsvc
Alternative: Clone and install locally
git clone https://github.com/tgbender/portablemsvc.git
cd portablemsvc
pip install .
This provides the portablemsvc console script on your PATH.
Usage
Run portablemsvc --help to view global options and subcommands.
Microsoft License Terms
PortableMSVC is not affiliated with Microsoft. It downloads MSVC and Windows SDK packages from Microsoft's official Visual Studio release channel, and those packages remain subject to Microsoft's license terms.
Before installing a toolchain, review the applicable Microsoft terms for your use case:
- Visual Studio license terms directory
- Visual Studio licensing guidance
- Visual Studio redistribution terms
Passing --accept-license means you have reviewed and accept the applicable
Microsoft terms for the packages PortableMSVC downloads and installs. Do not
redistribute downloaded packages, cache contents, or extracted toolchains unless
Microsoft's terms allow it.
Subcommands
search- Search available MSVC and SDK versionslist- List installed toolchainsinstall- Install a portable toolchainregister- Register toolchain into HKCU\Environmentunregister- Unregister toolchain from HKCU\Environmentinstall-from-lockfile- Reproducible install from a lockfileget-path- Get install path for build scripts
Search Available Versions
portablemsvc search [--channel release|preview] [--no-cache] [--full]
Search for available MSVC and Windows SDK versions before installing.
Install a Portable Toolchain
portablemsvc install
[--host x64|x86|arm|arm64]
[--target x64|x86|arm|arm64|all]
[--msvc-version <major.minor>]
[--sdk-version <build>]
[--channel release|preview]
[--accept-license]
[--no-cache]
[--output <custom_dir>]
By default, installs the latest x64 MSVC + SDK under:
%LOCALAPPDATA%\portable\msvc\msvc-<full_version>_sdk-<build>
If --output points at an existing directory, PortableMSVC will only replace it
when it is empty or already looks like a PortableMSVC install. It refuses to
replace arbitrary non-empty directories.
Environment Variable Overrides:
| Variable | Purpose |
|---|---|
PORTABLEMSVC_CACHE |
Override download cache directory |
PORTABLEMSVC_DATA |
Override install directory |
PORTABLEMSVC_CONFIG |
Override config directory |
PORTABLEMSVC_TEMP |
Override temp directory |
PORTABLEMSVC_MSI_EXTRACTOR |
Select MSI extractor: auto/pymsi (default), msiexec, or fallback |
Example:
set PORTABLEMSVC_CACHE=D:\cache\portablemsvc
portablemsvc install
Downloaded package payloads are cached by SHA256 so older toolchain versions can coexist for lockfile installs. Visual Studio manifests are also retained by downloaded content hash, with URL metadata pointing at the latest cached body.
List Installed Toolchains
portablemsvc list
Displays for each install:
- ID
- Path
- MSVC (manifest) version
- MSVC (internal) build folder version
- SDK version
- Host & Targets
- Installed at timestamp
Register / Unregister
-
Register the toolchain into your user environment:
portablemsvc register [--id <install_id>]
-
Unregister (restore original PATH):
portablemsvc unregister [--id <install_id>]
Example Workflow
-
Install the latest x64 toolchain (you will be prompted to review and accept the Microsoft license terms):
portablemsvc install
-
Register it into your environment:
portablemsvc register
-
Activate the environment (choose one):
Command Prompt:
activate.cmd
PowerShell:
.\activate.ps1
xonsh:
source activate.xsh
-
Verify:
where link.exe rustup show # should show x86_64-pc-windows-msvc cargo build # should invoke link.exe from your portable MSVC
-
List all installs:
portablemsvc list
-
Switch to another install later:
portablemsvc register --id <other_install_id> -
Cleanup:
portablemsvc unregister
Build Script Integration
The get-path command outputs the installation root for use in build scripts:
# Get path for latest install
$MSVC_ROOT = portablemsvc get-path
# Get path by lockfile (matches MSVC/SDK versions)
$MSVC_ROOT = portablemsvc get-path --lockfile .\portablemsvc.lock
# Get path by install ID
$MSVC_ROOT = portablemsvc get-path --id <install_id>
# Use in build
& "$MSVC_ROOT\activate.ps1"
nmake /f Makefile
The env.json file contains all environment variables needed for building:
CC,CXX,AR- Compiler pathsPATH,INCLUDE,LIB- Search pathsTOOL_VERSIONS- PE file versions of tools
CI/CD Usage
For reproducible builds in CI, use a lockfile:
# Install and generate lockfile (commit this to your repo)
portablemsvc install --accept-license --output .\msvc
# In CI, install from the lockfile for reproducible package selection
portablemsvc install-from-lockfile portablemsvc.lock --accept-license
Lockfiles are executable supply-chain input: they contain exact package URLs and hashes. Only use lockfiles from repositories and commits you trust.
GitHub Actions Example:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@v5
- run: uv tool install portablemsvc
- run: portablemsvc install-from-lockfile portablemsvc.lock --accept-license
env:
PORTABLEMSVC_CACHE: D:\cache\portablemsvc
# Get the path and use it
- run: |
$msvcPath = portablemsvc get-path --lockfile portablemsvc.lock
& "$msvcPath\activate.ps1"
cargo build --release
shell: pwsh
Contributing
Contributions and issues are welcome!
- Run
mise run lintto check code style and types - Run
mise run testto run the test suite - Run
mise run test-mostbefore changing installer behavior - Keep PRs focused on a single feature or bugfix
- Add tests for all new behavior
Publishing
Releases are published from the manual GitHub Actions release workflow on the main branch.
The publish job uses PyPI trusted publishing through the pypi environment, which requires reviewer approval and a 60 second wait timer before upload.
License
This project is MIT-licensed. See LICENSE for details.
Disclaimer
PortableMSVC is provided as-is. You are responsible for complying with the licenses for any Microsoft packages you download, install, use, or redistribute.
Acknowledgments
Huge thanks to @mmozeiko for foundational work on portable MSVC tooling inspiration.
Testing 🔍
Run the test suite:
# Fast tests (no downloads)
mise run test
# Most tests including slow_installs but not integration (~20GB downloads)
mise run test-most
# Full tests including integration (~20GB downloads)
mise run test-all
Test coverage includes:
- C/C++ compilation with Windows SDK headers
- Static library creation with
lib.exe - Tool version capture (PE file metadata)
- Environment variable verification
- Lockfile-based reproducible installs
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file portablemsvc-0.3.0.tar.gz.
File metadata
- Download URL: portablemsvc-0.3.0.tar.gz
- Upload date:
- Size: 40.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
36faca6b0c91c6751f9e0df2675d1f9ec8766ebd074f956e031df641669f70fe
|
|
| MD5 |
af2ca979e6f402194a14e0fc8ab477e2
|
|
| BLAKE2b-256 |
3a78e301cc13fb0c657d0d53e149f520a7363c36ef58a5e00c13948eafb55c3b
|
File details
Details for the file portablemsvc-0.3.0-py3-none-any.whl.
File metadata
- Download URL: portablemsvc-0.3.0-py3-none-any.whl
- Upload date:
- Size: 48.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.15 {"installer":{"name":"uv","version":"0.11.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e3b735fb763cf226ac2c405ab0e3031e4243f23b30b325e026c84013b8638bf1
|
|
| MD5 |
1265140d80a778315bbbe14af6b782bb
|
|
| BLAKE2b-256 |
52d2d7d4807a4c16eafdb21611697bf60cac089b55cf5f45a1c3302523da549a
|