Skip to content

Vix.cpp v2.8.4

Vix.cpp v2.8.4 focuses on the part of development that is repeated most often: edit, build, run, change a file, and build again.

The release reduces unnecessary compiler work in Vix public headers, improves the way standalone programs and full projects reuse previous build state, and brings vix build, vix run, and vix dev closer to one consistent execution model. It also tightens cache invalidation, improves diagnostics, and avoids consuming every available hardware thread during normal builds.

The result is not a new application model or a new module. It is a refinement of the development loop itself, with most of the work aimed at making common C++ workflows faster without hiding the information developers need when something goes wrong.

Release focus

C++ build performance is affected by more than the compiler command that eventually runs.

A public header can force large implementation dependencies into every translation unit. A cache can save time when its inputs are correct, but create confusing behavior when dependency tracking is incomplete. A development watcher can rebuild quickly while still feeling slow if it performs redundant validation, restarts twice for one change, or floods the terminal with internal state.

v2.8.4 addresses these problems together.

The public API has been made lighter where implementation details did not need to be visible. Standalone C++ execution keeps a direct compilation path when possible, while code that depends on compiled Vix libraries uses the CMake-backed path needed for correct linkage. Build caches now track source and header content more carefully, and the watch paths used by vix dev and vix build --watch share more of the same underlying behavior.

The goal is simple: unchanged work should not be repeated, changed work should invalidate the right artifacts, and the terminal should make it clear what Vix is doing.

A unified vix build experience

vix build now uses one compact live build presentation across native builds, graph-executor builds, and CMake/Ninja builds.

The normal command remains:

bash
vix build

Verbose mode uses the same presentation instead of switching to a different build experience:

bash
vix build -v

-v adds useful toolchain and build information while preserving the higher-level Vix output. Developers who need Vix's own structured diagnostics can use:

bash
vix build --debug

Raw CMake, Ninja, and compiler output remains available through:

bash
vix build --cmake-verbose

Build logs can also be inspected directly:

bash
vix build --log

This separation keeps the default build readable without removing access to the lower-level tools. Normal development can stay concise, while build-system investigation still has an explicit path to the complete output.

Cross-compilation controls

The build command now exposes clearer controls for selecting native and cross-compilation environments.

The host platform can be selected explicitly with:

bash
vix build --target native

Available native and cross toolchains can be inspected with:

bash
vix build --targets

Target toolchains can also receive an explicit sysroot through --sysroot.

These options make target selection visible at the Vix CLI level rather than relying entirely on implicit toolchain state. They do not replace CMake toolchains, but give the build command a clearer way to participate in cross-platform configuration.

Lighter public headers

A significant part of the work in v2.8.4 is below the CLI.

Vix public headers previously exposed more implementation detail than many applications needed. Including a high-level type could indirectly pull router internals, HTTP server implementation, request handling, runtime execution details, Asio types, JSON-heavy configuration code, or logging implementation into user translation units.

That increases parsing and template work even when an application only uses a small part of the public API.

The App interface has now been decoupled from several of those implementation details. Router, HTTP server, request handler, runtime executor, and Asio internals are no longer exposed unnecessarily through the main application surface.

The core umbrella path has also been reduced. Including <vix.hpp> no longer means importing advanced HTTP and router implementation headers that are unrelated to the code being compiled.

JSON-heavy Config implementation has been moved out of headers where possible. Response implementation follows the same direction, logger internals no longer expose spdlog throughout user translation units, and RuntimeExecutor lifecycle implementation is kept outside application translation units where the public API does not require it.

These changes preserve common public workflows such as GET routes, POST JSON handling, middleware, configuration, logging, and runtime executors. The change is primarily about reducing what the compiler must see to use those APIs.

Faster standalone execution

vix run now distinguishes more carefully between standalone C++ programs that can use direct compilation and programs that require compiled Vix runtime functionality.

A simple file can continue through the lightweight path:

bash
vix run test.cpp

When the source requires compiled Vix libraries, Vix uses the CMake-backed path so that the program receives the correct targets, libraries, and transitive linkage.

This avoids two opposite problems: forcing every small script through a full project build, or trying to compile a program directly when its dependencies require the compiled Vix runtime.

Warm executions reuse validated build state and compiled artifacts. When neither the source nor one of its relevant dependencies has changed, an unchanged script can run without invoking the compiler or linker again.

Local and transitive dependencies remain part of validation, so the faster path does not treat the top-level source file as the only input that matters.

Explicit vix run controls

Runtime options that were previously driven mainly through internal configuration or environment variables are now exposed as documented CLI controls.

The command supports:

text
--ui / --no-ui
--env-hint / --no-env-hint
--trace-cache / --no-trace-cache
--compiler-fingerprint <fast|strict>

These options make runtime behavior easier to reproduce from a command line or CI script.

The compiler fingerprint mode is particularly useful when choosing how aggressively cached compilation state should be reused. The default development path can remain fast, while stricter validation is available when the environment or toolchain needs to be checked more carefully.

Dependency-aware caching

A fast cache is only useful when its invalidation rules are trustworthy.

Script caching now tracks source files together with local and transitive headers by content. Editing a header that affects a standalone program invalidates the relevant build even when the top-level .cpp file is unchanged.

The reverse case is also important: touching a file without changing its contents should not force compilation simply because its timestamp changed.

v2.8.4 uses content-aware dependency information to distinguish those cases more reliably.

Failed compilations are not stored as successful cache states, and compiled dependency graphs are rebuilt only when their inputs require it. Previously compiled source states can also be restored efficiently through the compiler cache when development moves back to code that has already been built.

This makes the cache useful during real editing patterns rather than only during repeated execution of an untouched file.

Faster vix dev for standalone files

The standalone development loop has been simplified around the information a developer normally needs: what is being watched, whether the rebuild succeeded, how long it took, and what the program printed.

A normal session can now look like:

text
Watching test.cpp
Hello, world
Rebuilt test.cpp in 488ms
Hello, world

Internal reload messages, absolute paths, process identifiers, and build-system detail are no longer printed by default when they do not help explain the rebuild.

Fast recompilations also avoid showing progress UI that lasts longer than the work itself. When a rebuild completes, its duration is reported directly and application output follows without unnecessary blank lines.

The watcher tracks both the source and its transitive headers. One relevant change results in one rebuild and restart rather than several reactions to the same edit.

A failed build does not leave the development session in a broken state. Once the source is corrected, the watcher can rebuild and start the program again normally.

Project development builds

Full Vix projects keep the project-level development experience, but rebuild timing now reflects the real build duration.

For example:

text
Dev shop (dev)

  changed: src/main.cpp

  build [============================] done

  ✔ Rebuilt in 7.3s · Started pid=49809

The project path still has more work to perform than a standalone file, so it retains the build progress and process information that are useful for a running application.

The important change is that vix dev and vix build --watch now follow the same underlying build behavior instead of evolving as separate rebuild systems. Cache decisions, source changes, dependency handling, and build execution are therefore less likely to disagree depending on which watch command is used.

Safer build parallelism

Using every hardware thread is not always the fastest development experience.

A large parallel C++ build can saturate the machine, increase memory pressure, and make the editor, browser, terminal, or other development tools noticeably less responsive.

Automatic parallelism now keeps part of the machine available instead of assuming that every detected hardware thread should be occupied by compilation.

The recommendation adapts to the available CPU resources. Developers who want a specific level of parallelism can still override it explicitly with --jobs.

This changes the default, not the control available to experienced users.

Correct compiled-library linkage

The distinction between direct standalone compilation and compiled Vix functionality exposed several cases where a source file could compile but fail at link time because required implementations lived in Vix libraries rather than in headers.

v2.8.4 fixes that boundary.

Programs that depend on compiled Vix components now use a build path that has access to the correct generated CMake targets and their transitive dependencies. The direct path remains for programs that can genuinely be compiled as standalone translation units.

Linker errors have also been made clearer when an implementation or required library is still missing, so failures point toward the linkage problem rather than appearing as an unrelated cache or script error.

Local build-tree consumption

Vix can now be consumed more reliably directly from the current build tree.

Local build-tree CMake package exports have been corrected so a project can resolve the Vix targets produced by the current source build without silently falling back to an installed runtime.

This matters when developing Vix itself, testing changes against another local project, or validating an installation before publishing it.

Reducing transitive public includes also exposed headers that had been relying on unrelated includes to compile. Those direct dependencies have been corrected so public headers remain self-contained under the lighter include model.

Build cache and configuration fixes

Several fixes in this release address cases where valid reusable build state existed but was ignored, or where stale state was accepted when it should have been invalidated.

--fast builds now reuse compatible configuration state correctly.

Graph-executor builds are no longer bypassed by unrelated cache paths, and generated CMake targets used for script builds are handled consistently.

Standalone script execution avoids redundant cache validation, while transitive compiled dependencies are rebuilt when one of their relevant inputs changes.

Build-log lookup has also been corrected when a build directory is passed explicitly, so vix build --log resolves the log associated with the selected build instead of relying on unrelated default state.

Server startup reporting

Runtime startup now distinguishes more carefully between starting a process and successfully starting a server.

READY is emitted only after startup has actually succeeded.

Port configuration is propagated correctly, and bind failures are returned through the normal error path rather than allowing the process to appear ready before the listening socket exists.

This is especially important for development tooling and automation that uses startup output as a signal that the application can receive requests.

Diagnostics

v2.8.4 separates normal build output from diagnostic depth more clearly.

The default build remains compact. -v adds useful Vix-level information, --debug exposes structured internal diagnostics, and --cmake-verbose provides the raw output from the underlying CMake, Ninja, and compiler tools.

This means a developer can increase detail according to the problem being investigated instead of choosing between an overly quiet command and an uncontrolled stream of build-system output.

Link failures, cache decisions, build-path selection, and startup failures now have clearer places in that diagnostic model.

Validation

The release was validated across standalone C++ files, complete Vix projects, direct script compilation, CMake-backed script builds, graph-executor builds, watched development sessions, local headers, transitive headers, and compiled Vix dependencies.

Cache testing covered unchanged warm runs, source changes, direct header changes, transitive header changes, timestamp-only file touches, failed compilations, recovery after a failed build, and restoration of previously compiled source states.

Development watching was tested for one-change/one-rebuild behavior, rebuild timing, process restart, application output, and recovery after compilation errors.

The public-header work was checked against common application APIs including routing, JSON requests and responses, middleware, configuration, logging, and runtime execution.

Build validation also covered managed and local build paths, generated CMake targets, graph execution, reusable configuration state, build-log resolution, startup readiness, port binding failures, and direct consumption of Vix from its current build tree.

Compatibility

The public API used by normal Vix applications remains compatible. The header changes move implementation details out of user translation units rather than replacing the high-level interfaces developers already use.

Standalone programs still use direct compilation when their dependency model allows it. Programs that require compiled Vix functionality may now take the CMake-backed path where necessary for correct linkage.

Existing explicit --jobs values continue to take precedence over automatic parallelism.

--cmake-verbose remains available for developers who need the complete underlying build output, while the normal and -v modes use the unified Vix presentation.

The cache changes may cause an initial rebuild where older cache state cannot be validated under the new dependency rules. Once rebuilt, subsequent warm runs can reuse the new state normally.

Release summary

Vix.cpp v2.8.4 improves the daily C++ development loop rather than adding another layer to it.

Public headers require less compiler work, standalone programs can reuse validated artifacts more effectively, and programs that depend on compiled Vix libraries now take the build path required for correct linkage. vix dev reacts to source and header changes with less terminal noise, while vix build --watch follows the same underlying behavior.

Caching is more careful about real content changes, build parallelism leaves room for the rest of the development environment, and diagnostics are divided more clearly between normal output, Vix debugging information, and raw CMake or compiler output.

The common workflow remains the same:

text
edit -> build -> run -> change -> rebuild

v2.8.4 makes each pass through that loop more predictable and avoids repeating work that has already been proven valid.

Last updated: