Vix.cpp v2.8.4 is here Read the blog
Skip to content

vix install

vix install installs Vix Registry dependencies.

Use it when you want to install the exact dependencies pinned in vix.lock, generate CMake integration files, or install one package globally.

bash
vix install

Overview

vix install has two modes:

txt
project mode
global mode

Project mode installs dependencies for the current project:

bash
vix install

Global mode installs one package globally:

bash
vix install -g gk/jwt

The command is part of the Vix Registry workflow.

It connects:

txt
vix.json
vix.lock
registry index
global package store
project .vix/deps
.vix/vix_deps.cmake
vix.app
CMake

Usage

bash
vix install
vix install -g <package>
vix install --global <package>

Quick Git Workflows

Try One File

For a temporary experiment, pass a Git dependency directly to vix run:

bash
vix run main.cpp --dep https://github.com/fmtlib/fmt

Vix creates a temporary dependency environment, resolves the latest stable Git tag, detects the main CMake target, builds and runs the file, then removes the temporary project files. The current directory is not modified.

A compact version can be written with @:

bash
vix run main.cpp --dep https://github.com/fmtlib/fmt@11.2.0

For advanced cases use a structured dependency spec:

bash
vix run main.cpp \
  --dep "git=https://github.com/fmtlib/fmt;tag=11.2.0;target=fmt::fmt"

Use --save to turn the temporary dependency into a project dependency:

bash
vix run main.cpp --dep https://github.com/fmtlib/fmt --save

Initialize an Existing Folder

vix init makes the current directory a minimal Vix project. It does not create a full template like vix new.

bash
mkdir fmt-test
cd fmt-test
cat > main.cpp <<'CPP'
#include <fmt/format.h>

int main()
{
  fmt::print("Hello from fmt!\n");
}
CPP

vix init
vix install https://github.com/fmtlib/fmt
vix run main.cpp

A generated vix.app looks like this:

toml
name = "fmt-test"
type = "executable"
standard = "c++20"
sources = ["main.cpp"]

Useful options:

bash
vix init --name hello
vix init --lib
vix init --standard c++23
vix init --force

Git Dependency Autodetection

For common CMake and header-only repositories, this is enough:

bash
vix install https://github.com/fmtlib/fmt

When no revision is provided, Vix reads Git tags, keeps SemVer-compatible stable tags, ignores prereleases by default, and chooses the newest stable version. The lockfile stores the exact commit, so later vix build and vix run do not move to a newer tag automatically.

Vix also tries to detect the main CMake target. For fmt, it selects:

toml
target = "fmt::fmt"

Explicit options still win when autodetection is ambiguous or when you want another target:

bash
vix install https://github.com/fmtlib/fmt \
  --tag 11.2.0 \
  --target fmt::fmt-header-only

Header-only repositories without CMake can be detected when they expose one clear include root such as include/ or single_include/. Otherwise declare it explicitly:

bash
vix install https://github.com/example/headers \
  --header-only \
  --include include

Git dependencies currently support CMake and header-only repositories. Other build systems are not configured automatically.

Basic examples

bash
# Install project dependencies from vix.lock
vix install

# Install a global package
vix install -g gk/jwt

# Install a specific global version
vix install -g gk/jwt@1.0.0

# Install with a semver range
vix install -g gk/jwt@^1.0.0

# Scoped-style syntax is also accepted
vix install -g @gk/jwt
vix install -g @gk/jwt@~1.2.0

What it does

ModeCommandPurpose
Project modevix installInstall exact project dependencies from vix.lock.
Global modevix install -g <pkg>Resolve and install one package globally.

Project mode

Run:

bash
vix install

Project mode reads:

txt
vix.lock

Then it installs the exact locked dependencies. It does not choose new versions. It does not rewrite dependency ranges. It does not behave like vix update.

The main purpose is reproducibility:

txt
same vix.lock
same dependency versions
same commits
same install result

Project install outputs

A project install can create:

txt
.vix/
├── deps/
│   └── ...
└── vix_deps.cmake

Important outputs:

PathPurpose
.vix/deps/Project-local links or copies of installed packages.
.vix/vix_deps.cmakeGenerated CMake integration for dependencies.

Do not edit:

txt
.vix/vix_deps.cmake

It is generated by Vix.

Global mode

Run:

bash
vix install -g gk/jwt

or:

bash
vix install --global gk/jwt

Global mode resolves one package from the registry, fetches it, prepares its Vix dependencies, builds it with CMake when needed, runs CMake install rules when they exist, and records installed files in the global manifest.

Typical Linux/macOS layout:

txt
~/.vix/global/
├── bin/
├── include/
├── lib/
├── share/
├── build/
├── tmp/
└── installed.json

On Windows the same layout is used under the Vix user root unless VIX_GLOBAL_PREFIX is set. Global install does not use /usr/local by default and does not require sudo.

Global install is useful when you want a package available outside one specific project, including CLI packages installed similarly to npm global commands.

Global install syntax

Accepted package forms:

txt
namespace/name
namespace/name@version
namespace/name@range
@namespace/name
@namespace/name@version
@namespace/name@range

Examples:

bash
vix install -g gk/jwt
vix install -g gk/jwt@1.0.0
vix install -g gk/jwt@^1.0.0
vix install -g @gk/jwt
vix install -g @gk/jwt@~1.2.0

Global executables

If a package installs executables into bin through CMake, those files are recorded as global commands. Example:

bash
vix install -g vixcpp/ovi
ovi --version
ovi --help
ovi greet Gaspard

Vix installs the real executable under ~/.vix/global/bin. If that directory is not already in PATH, Vix updates the user shell configuration for Bash, Zsh, or Fish. When a user bin directory such as ~/.local/bin is already in the current PATH, Vix also creates a command shim there so the command is available immediately in the current terminal. On Windows, Vix updates the user PATH and handles .exe, .cmd, and .bat.

CMake install and Vix fallback

Global install prefers the package's CMake install rules:

bash
cmake -S <source> -B <build> \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=<temporary-stage-prefix>
cmake --build <build> --config Release
cmake --install <build> --config Release

If a Vix package has dependencies, Vix prepares the package checkout with .vix/deps and .vix/vix_deps.cmake before configuring it, the same integration used by vix build. If CMake install produces no files for a header-only package, Vix falls back to installing headers and keeps the source checkout recorded so vix run and vix build can use the package's source CMake integration.

A package that provides a CLI should still declare CMake install rules for its executables:

cmake
add_executable(ovi_cli src/main.cpp)
set_target_properties(ovi_cli PROPERTIES OUTPUT_NAME ovi)
install(TARGETS ovi_cli RUNTIME DESTINATION bin)

Declaring commands

A package may document and validate expected commands in vix.json using bin:

json
{
  "bin": {
    "ovi": "ovi_cli",
    "ovi-doctor": "ovi_doctor_cli"
  }
}

The keys are command names exposed in bin; the values are CMake target names for documentation. This field is optional. CMake install() still decides what is installed. If bin is present, Vix verifies that every declared command was installed. Command names must be plain file names, not paths.

The older explicit form is also accepted:

json
{
  "executables": [{ "name": "ovi", "target": "ovi_cli" }]
}

Listing and uninstalling globals

bash
vix list -g
vix uninstall -g vixcpp/ovi
vix uninstall -g @vixcpp/ovi

Global install and uninstall print a short npm-style result with elapsed time, for example vixcpp/ovi@0.1.0 installed globally in 1.2s or removed vixcpp/ovi@0.1.0 in 90ms. Uninstall removes only the files and command shims recorded for that package and then removes empty directories left behind. It does not remove unmanaged files from the global prefix.

Version resolution

When a package version is not provided, Vix selects the latest available version from the registry.

bash
vix install -g gk/jwt

When a version range is provided, Vix resolves the highest version that satisfies the range.

bash
vix install -g gk/jwt@^1.0.0

Supported range forms include common semver-style inputs such as:

txt
1.2.3
^1.2.3
~1.2.3
>=1.0.0
<=2.0.0
>1.0.0
<2.0.0
*
latest

Registry requirement

vix install needs the local registry index.

If the registry has not been synced, Vix reports:

txt
registry not synced
Run: vix registry sync

Fix:

bash
vix registry sync
vix install

For global install:

bash
vix registry sync
vix install -g gk/jwt

Project install workflow

For a new project:

bash
vix new api
cd api
vix install
vix dev

For an existing project:

bash
git clone https://github.com/example/api.git
cd api
vix install
vix dev

For CI:

bash
vix install
vix build --build-target all
vix tests

Registry dependency workflow

Use vix add when adding a new dependency.

bash
vix add gk/json@^1.0.0

Then install:

bash
vix install

A normal dependency workflow is:

bash
vix registry sync
vix add gk/json@^1.0.0
vix install
vix build

Difference between vix add and vix install

CommandPurpose
vix add <pkg>Add a dependency to the project and update dependency metadata.
vix installInstall dependencies already pinned in vix.lock.

Use vix add when you want to add something new.

Use vix install when the lockfile already exists and you want to install what it says.

Difference between vix update and vix install

CommandPurpose
vix updateResolve newer versions and rewrite vix.lock.
vix installInstall exact versions already pinned in vix.lock.

Use vix update when you want newer dependency versions.

Use vix install when you want reproducible locked versions.

Difference between project and global install

ModeStores packages inUses vix.lockGenerates .vix/vix_deps.cmake
Project install.vix/deps/ and global store checkout cacheyesyes
Global install~/.vix/global/packages/nono

Project install is for building a project.

Global install is for installing one package globally.

Package cache

Vix stores fetched Git checkouts under:

txt
~/.vix/store/git/

A package checkout is stored by package identity and commit.

This means repeated installs can reuse existing package checkouts.

The project then receives links or copies under:

txt
.vix/deps/

This keeps project installs fast while keeping dependency state reproducible.

Git dependencies

Vix can install a dependency directly from a Git repository when the project uses vix.app.

bash
vix install https://github.com/fmtlib/fmt --tag 11.2.0 --target fmt::fmt
vix install https://github.com/nlohmann/json.git --tag v3.12.0 --target nlohmann_json::nlohmann_json

The command adds a structured dependency block to vix.app, resolves the requested revision to an exact commit, writes vix.lock, fetches the repository into the Git cache, links it into .vix/deps/, and regenerates .vix/vix_deps.cmake.

Supported revision fields are exclusive:

toml
[dependencies.fmt]
git = "https://github.com/fmtlib/fmt"
tag = "11.2.0"
target = "fmt::fmt"
toml
[dependencies.library]
git = "https://github.com/example/library"
branch = "main"
target = "library::library"
toml
[dependencies.library]
git = "https://github.com/example/library"
rev = "a1b2c3d4e5f6"
target = "library::library"

For monorepos, select a subdirectory:

toml
[dependencies.parser]
git = "https://github.com/company/monorepo"
tag = "v2.0.0"
subdirectory = "libs/parser"
target = "company::parser"

For header-only repositories without CMake:

toml
[dependencies.sample]
git = "https://github.com/example/sample-headers"
tag = "v1.0.0"
header_only = true
include = "include"

Multiple include directories are written as:

toml
includes = ["include", "single_include"]

CMake options use the nested table form:

toml
[dependencies.spdlog]
git = "https://github.com/gabime/spdlog"
tag = "v1.15.3"
target = "spdlog::spdlog"

[dependencies.spdlog.cmake]
SPDLOG_BUILD_TESTS = false
SPDLOG_BUILD_EXAMPLE = false
SPDLOG_BUILD_BENCH = false

Git dependencies currently support CMake projects and header-only repositories. Vix does not claim universal support for Bazel, Meson, Autotools, Premake, or custom Makefiles.

Git dependencies are untrusted code: CMake configure and build scripts may execute code on the machine. Review the repository before adding it.

Git lockfile entries

A Git dependency is stored in vix.lock with source = "git" data in JSON form. The lock records the normalized URL, requested revision, resolved commit, targets, include directories, subdirectory, CMake options, and content hash. Branches are resolved to a commit and are not updated by vix build.

Git cache

Registry packages use ~/.vix/store/git/. Direct Git dependencies use:

txt
~/.vix/cache/git/

The cache identity includes the repository URL and resolved commit. The project receives a link or copy under .vix/deps/<name>/, so normal builds can run offline after vix install or vix deps has completed.

Removing a Git dependency

bash
vix uninstall sample

This removes the [dependencies.sample] block from vix.app, removes the lock entry, removes .vix/deps/sample, and leaves the shared Git cache intact.

Integrity checks

If a dependency in vix.lock contains a hash, Vix can verify the checkout content.

If the hash does not match, Vix reports an integrity failure.

Example shape:

txt
integrity check failed: gk/json
expected: ...
actual:   ...

This protects the install from using unexpected dependency contents.

Generated CMake integration

Project install generates:

txt
.vix/vix_deps.cmake

This file can:

  • add package roots to CMAKE_PREFIX_PATH
  • add header-only packages as interface targets
  • add CMake-based dependencies with add_subdirectory
  • disable dependency tests, examples, benchmarks, and docs
  • bridge package targets to canonical Vix aliases
  • expose aliases such as gk::json

The canonical alias for a registry package is:

txt
namespace::name

For:

txt
gk/json

the alias is:

txt
gk::json

Header-only packages

Header-only packages expose include directories through an interface target.

Example package:

txt
gk/json

Expected alias:

txt
gk::json

After vix install, use it from CMake through:

cmake
target_link_libraries(app PRIVATE gk::json)

For vix.app, add the alias to links:

ini
links = [
  vix::vix,
  gk::json,
]

Compiled packages

Compiled packages can contain their own CMakeLists.txt.

When Vix detects a CMake-based package, it can load the package through generated CMake integration.

Vix also tries to bridge the package’s real CMake target to the canonical registry alias.

For example:

txt
gk/http

should be usable as:

txt
gk::http

when the dependency exposes a compatible target.

Dependency order

When dependencies depend on other dependencies, Vix sorts them topologically before generating CMake integration.

This matters because a dependency should be available before another package tries to use it.

If Vix detects a dependency cycle, it reports an error.

Example shape:

txt
dependency cycle detected while generating .vix/vix_deps.cmake

vix.app projects

For vix.app projects, vix install is simple.

After install, Vix prints a next step like:

txt
Dependencies ready
1 package(s) installed
CMake integration generated

Next:
  run vix build

That is because vix.app generated CMake can load the generated dependency integration automatically.

A typical vix.app dependency flow:

bash
vix add gk/json@^1.0.0
vix install
vix build

Then in vix.app:

ini
deps = [
  gk/json@^1.0.0,
]

links = [
  vix::vix,
  gk::json,
]

CMake projects

For manual CMake projects, Vix may print a next step like:

cmake
include(.vix/vix_deps.cmake)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE gk::json)

In a real project, add:

cmake
include(.vix/vix_deps.cmake)

near the top of your CMakeLists.txt after project(...).

Then link only the packages your target actually uses:

cmake
target_link_libraries(app PRIVATE gk::json)

vix.app vs CMake install behavior

Project typeWhat you do after vix install
vix.app projectRun vix build.
CMake projectInclude .vix/vix_deps.cmake and link needed aliases.

Vix detects a vix.app project when:

txt
vix.app exists
CMakeLists.txt does not exist

If CMakeLists.txt exists, Vix treats the project as a CMake project.

Full vix.app example

ini
name = api
type = executable
standard = c++20

sources = [
  src/main.cpp,
]

include_dirs = [
  src,
]

deps = [
  gk/json@^1.0.0,
]

packages = [
  vix,
]

links = [
  vix::vix,
  gk::json,
]

output_dir = bin

Install:

bash
vix install

Build:

bash
vix build

Run:

bash
vix run

Full CMake example

cmake
cmake_minimum_required(VERSION 3.24)

project(api LANGUAGES CXX)

include(.vix/vix_deps.cmake)

add_executable(api
  src/main.cpp
)

target_compile_features(api PRIVATE cxx_std_20)

target_link_libraries(api PRIVATE
  gk::json
)

Install:

bash
vix install
vix build

Global install example

Install:

bash
vix registry sync
vix install -g gk/jwt@^1.0.0

This writes global install state under:

txt
~/.vix/global/

Typical structure:

txt
~/.vix/global/
├── packages/
│   └── ...
└── installed.json

The global manifest records information such as:

json
{
  "packages": [
    {
      "id": "gk/jwt",
      "version": "1.0.0",
      "repo": "https://github.com/...",
      "tag": "v1.0.0",
      "commit": "...",
      "hash": "...",
      "type": "header-only",
      "include": "include",
      "installed_path": "/home/user/.vix/global/packages/gk.jwt"
    }
  ]
}

Package specification

A package spec has this shape:

txt
namespace/name

Optional version or range:

txt
namespace/name@version
namespace/name@range

Examples:

txt
gk/json
gk/json@1.0.0
gk/json@^1.0.0
gk/json@~1.2.0

Scoped-style syntax is also accepted:

txt
@gk/json
@gk/json@1.0.0

Invalid package spec

Wrong:

bash
vix install -g jwt

Correct:

bash
vix install -g gk/jwt

If the package spec is invalid or not found, Vix reports:

txt
invalid package spec or package not found: jwt
Expected: @namespace/name[@version]
Example: vix install -g @gk/jwt@1.0.0

Project mode requires vix.lock

Project mode installs from:

txt
vix.lock

If the lockfile is missing, create it by adding or updating dependencies.

Typical flow:

bash
vix registry sync
vix add gk/json@^1.0.0
vix install

or:

bash
vix update
vix install

Manual edits to vix.json

Avoid manually editing dependency ranges in vix.json without updating the lockfile.

If you change dependency ranges manually, run:

bash
vix update
vix install

or use:

bash
vix add <package>

so vix.json and vix.lock stay aligned.

CI usage

Project install is the right command for CI because it respects vix.lock.

Example:

bash
vix registry sync
vix install
vix build --build-target all
vix tests

Release build:

bash
vix registry sync
vix install
vix build --preset release --build-target all
vix tests --preset release

With validation:

bash
vix registry sync
vix install
vix check --tests

Options

OptionDescription
-g, --globalInstall one package globally.
-h, --helpShow command help.

Commands reference

CommandPurpose
vix installInstall project dependencies from vix.lock.
vix install -g <pkg>Install one package globally.
vix install --global <pkg>Same as -g.

Common workflows

Install project dependencies

bash
vix install

Install after clone

bash
git clone https://github.com/example/api.git
cd api
vix registry sync
vix install
vix build

Install then run dev mode

bash
vix install
vix dev

Add and install a dependency

bash
vix registry sync
vix add gk/json@^1.0.0
vix install
vix build

Install a global package

bash
vix registry sync
vix install -g gk/jwt

Install a specific global version

bash
vix install -g gk/jwt@1.0.0

Install a global semver range

bash
vix install -g gk/jwt@^1.0.0

Common mistakes

Expecting vix install to update dependencies

Wrong expectation:

txt
vix install should choose newer versions

Correct model:

txt
vix install installs locked versions

Use:

bash
vix outdated
vix update

when you want to inspect and update versions.

Editing vix.json and expecting install to resolve new ranges

If you manually edit dependencies in vix.json, update the lockfile first:

bash
vix update
vix install

Better:

bash
vix add gk/json@^1.0.0
vix install

Forgetting registry sync

If the package cannot be found, run:

bash
vix registry sync
vix install

For global packages:

bash
vix registry sync
vix install -g gk/jwt

Using global install when the project needs a dependency

Wrong:

bash
vix install -g gk/json
vix build

Correct:

bash
vix add gk/json@^1.0.0
vix install
vix build

Global install does not add the dependency to your project lockfile.

Installing a dependency does not automatically mean your target uses it.

For vix.app, add the alias to links:

ini
links = [
  vix::vix,
  gk::json,
]

For CMake:

cmake
target_link_libraries(api PRIVATE gk::json)

Editing .vix/vix_deps.cmake

Wrong:

txt
edit .vix/vix_deps.cmake manually

Correct:

txt
edit vix.json, vix.lock, vix.app, or CMakeLists.txt

The file is generated and can be replaced by the next install.

Wrong:

ini
deps = [
  gk::json,
]

Correct:

ini
deps = [
  gk/json@^1.0.0,
]

links = [
  gk::json,
]

deps uses registry package specs.

links uses CMake target aliases.

Troubleshooting

Registry not synced

Run:

bash
vix registry sync

Then try again:

bash
vix install

Package not found

Check the package name:

txt
namespace/name

Then sync the registry:

bash
vix registry sync

Try:

bash
vix install -g namespace/name

or add it to your project:

bash
vix add namespace/name

No version matches range

If Vix reports:

txt
no version matches range: gk/json@^2.0.0

the registry has no compatible version.

Use:

bash
vix outdated

or check available versions in the registry.

Dependency hash mismatch

If integrity verification fails, do not ignore it.

Run:

bash
vix registry sync
vix reset
vix install

If it still fails, the registry entry or package content may be inconsistent.

Dependency cycle detected

If Vix reports a dependency cycle, one or more packages depend on each other in a loop.

Fix the package dependency metadata.

CMake cannot find dependency target

Check that install generated:

txt
.vix/vix_deps.cmake

For CMake projects, make sure you included it:

cmake
include(.vix/vix_deps.cmake)

For vix.app, make sure the dependency alias is in links:

ini
links = [
  gk::json,
]

Header not found

Check that the dependency exposes the expected include directory.

Then make sure your target links the dependency alias.

Example:

cmake
target_link_libraries(api PRIVATE gk::json)

or in vix.app:

ini
links = [
  gk::json,
]

Compiled package has no CMakeLists.txt

If a package is marked as compiled but has no CMakeLists.txt, Vix cannot build it as a CMake dependency.

Fix the package metadata or add a valid package build file.

Best practices

Commit vix.json.

Commit vix.lock.

Do not commit .vix/deps.

Do not manually edit .vix/vix_deps.cmake.

Run vix registry sync before adding or resolving dependencies.

Use vix add to add dependencies.

Use vix install after clone or in CI.

Use vix update only when you intentionally want new dependency versions.

Use deps for registry specs in vix.app.

Use links for CMake aliases in vix.app.

Prefer canonical aliases:

txt
namespace::name

Keep project installs reproducible with vix.lock.

CommandPurpose
vix addAdd a new dependency to the project.
vix updateResolve newer versions and rewrite vix.lock.
vix outdatedCheck outdated dependencies.
vix removeRemove a dependency.
vix listList installed project dependencies.
vix resetClean and reinstall project dependency state.
vix registry syncRefresh the registry index.
vix buildBuild the project after install.
vix runRun the app after install.
vix devStart dev mode after install.

Next step

Update dependency versions intentionally.

Open the vix update guide

Global Note extensions

vix install -g is also the installation path for Vix Note extensions.

bash
vix install -g softadastra/pyrelune

The package is resolved from the registry like any other global package. Vix fetches the resolved commit, builds it when needed, runs CMake install rules, copies installed files into the global prefix, and records the package in:

txt
~/.vix/global/installed.json

If the resolved registry version contains extensions.note, Vix preserves that version-level metadata in the installed manifest. Vix Note reads that installed metadata during global extension discovery.

For executable extensions, the package should install its runtime command under the global bin/ directory and declare it in bin:

json
{
  "bin": {
    "pyrelune": "pyrelune"
  }
}

CMake install rules remain authoritative. If the package declares an executable command but CMake does not install it, global install fails rather than recording a broken command as installed.

Released under the MIT License.