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

Build Workflow

A build is not only compilation.

A build is the process that turns a Vix application into something executable, testable, packageable, and deployable.

The simple command is:

bash
vix build

But the workflow behind it is bigger:

txt
resolve project
  -> configure
  -> compile
  -> link
  -> cache when safe
  -> report result

The build workflow must be fast.

But it must be correct first.

The rule

The main rule is:

txt
correct first
fast second

A build tool must never say that a target is up to date when it cannot prove it.

Speed is useful only when trust is preserved.

So the Vix build model is:

txt
reuse only when safe
rebuild when needed
fallback when uncertain

That rule matters everywhere.

What vix build means

When you run:

bash
vix build

you are asking Vix to:

txt
find the current project
resolve its build input
configure it if needed
build the correct target
reuse valid cache when possible
print useful diagnostics

The command should work for:

txt
CMake projects
vix.app projects
apps created from templates
projects with registry dependencies
projects using Vix modules

The user should not need to remember low-level build details for normal workflows.

Project resolution

Before building, Vix resolves the project.

Resolution order:

txt
1. CMakeLists.txt
2. vix.app

If CMakeLists.txt exists, Vix uses the CMake project.

If there is no CMakeLists.txt and vix.app exists, Vix uses the application manifest.

That means the build workflow supports both:

txt
advanced CMake projects
simple vix.app applications

Building a vix.app

For applications, vix.app is the simple path.

Example:

txt
name = "api"
type = "executable"
cpp_standard = "23"

sources = [
  "src/main.cpp",
  "src/app/AppFactory.cpp",
  "src/routes/HealthRoutes.cpp"
]

include_dirs = [
  "src"
]

modules = [
  "core",
  "json",
  "http"
]

When Vix builds this, the workflow is:

txt
read vix.app
  -> validate manifest
  -> generate internal CMakeLists.txt
  -> configure generated project
  -> build target

The generated project is written under:

txt
.vix/generated/app/

The user works with vix.app.

Vix uses generated CMake internally.

This gives a simple application model without losing the power of CMake.

Building a CMake project

If the project already has CMakeLists.txt, Vix keeps that path.

The workflow is:

txt
read CMakeLists.txt
  -> use preset or default config
  -> configure
  -> build

This is the right path for projects that need:

txt
custom CMake logic
multiple targets
platform-specific rules
external native libraries
advanced linking
install rules

Vix does not remove CMake.

It gives CMake projects a better workflow.

Build presets

A build can use presets.

Examples:

bash
vix build --preset dev
vix build --preset release

A development preset should favor fast iteration.

A release preset should favor final output.

The mental model:

txt
dev = fast local feedback
release = production-ready build

A project can also use CMakePresets.json when advanced CMake configuration is needed.

Default build

The default build should be enough for normal development:

bash
vix build

A developer should not need to pass many flags for the common case.

The command should detect the project, prepare the build directory, and build the app.

For many projects, the expected flow is:

bash
vix install
vix build
vix run

Build directories

Build output should not pollute source code.

Common directories:

txt
build/
build-ninja/
build-release/
.vix/

The exact folder can depend on the selected workflow or preset.

Generated Vix state belongs in:

txt
.vix/

Package output belongs in:

txt
dist/

The source tree should stay readable.

Dependencies before build

If the project uses registry dependencies, install them before building.

bash
vix install
vix build

After cloning a project:

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

vix install reads vix.lock.

It installs exact versions.

It does not update dependencies.

That distinction matters:

txt
vix install = reproduce locked state
vix update = change locked state

Modules before build

A vix.app can declare modules:

txt
modules = [
  "core",
  "json",
  "http",
  "db"
]

These modules affect the build.

If the app says it needs db, the build must include database support.

If the app says it needs http, the HTTP module must be available and linked.

The build should not guess hidden modules.

The app should declare what it needs.

Source files

The build must know what files belong to the target.

In vix.app, that means:

txt
sources = [
  "src/main.cpp",
  "src/app/AppFactory.cpp",
  "src/routes/HealthRoutes.cpp"
]

In CMake, that means the source list is defined by CMakeLists.txt.

The rule:

txt
vix.app declares app sources directly
CMakeLists.txt controls advanced source rules

Both paths must produce a clear target.

Include directories

A simple app can declare include directories:

txt
include_dirs = [
  "src",
  "include"
]

This lets code use clean includes:

cpp
#include "app/AppFactory.hpp"
#include "routes/HealthRoutes.hpp"

The include model should stay explicit.

Do not depend on accidental include paths.

Build target

A Vix app should have a clear target name.

In vix.app:

txt
name = "api"

That name becomes the application target.

When building:

bash
vix build

Vix should know which target to build.

In CMake projects, target resolution can come from the CMake project or user options.

The target must not be ambiguous in normal app workflows.

Configure step

Some builds need configuration before compilation.

Configuration is needed when:

txt
build directory does not exist
CMakeLists.txt changed
CMakePresets.json changed
vix.app changed
vix.json changed
vix.lock changed
*.cmake changed
toolchain changed
build preset changed

A configure step prepares the build system.

A compile step builds code.

Do not confuse them.

txt
configure = prepare build graph
compile = build source files

Reconfigure vs rebuild

Not every change needs the same response.

A source change usually needs rebuild only.

txt
src/main.cpp -> rebuild

A header change usually needs rebuild only.

txt
include/App.hpp -> rebuild

A config change usually needs reconfigure and rebuild.

txt
CMakeLists.txt -> reconfigure and rebuild
vix.app -> reconfigure and rebuild
vix.lock -> reconfigure and rebuild

This is also the model used by development mode.

Change classification

For development builds, Vix classifies changes.

Ignored paths:

txt
.git
.vix
build
build-dev
build-ninja
build-release
node_modules
.cache
.idea
.vscode

Source files:

txt
.cpp
.cc
.cxx
.c

Header files:

txt
.hpp
.hh
.hxx
.h
.ipp

Config files:

txt
CMakeLists.txt
CMakePresets.json
vix.json
vix.toml
vix.lock
*.cmake

The result is one of:

txt
ignore
rebuild-only
reconfigure-and-rebuild

That is the practical build model.

Object cache

Object cache exists to avoid recompiling work that is already valid.

The idea:

txt
same source
same flags
same compiler
same relevant inputs
  -> reuse object

If any important input changes, the object must not be reused.

Important inputs can include:

txt
source file content
included headers
compiler path
compiler version
compile flags
defines
include paths
target platform
build mode

Object cache is useful only when correctness is protected.

Artifact cache

Artifact cache is bigger than object cache.

It can reuse build outputs when the complete input state is still valid.

The idea:

txt
same target input state
  -> same artifact
  -> reuse safely

Artifacts can include:

txt
executables
libraries
generated outputs
packaged build outputs

But again, the rule is strict:

txt
reuse only when the input identity is proven

A wrong cache hit is worse than a slow build.

Build graph

A build graph describes what depends on what.

Example:

txt
main.cpp
  -> AppFactory.hpp
  -> Config.hpp
  -> HealthRoutes.hpp

At target level:

txt
api
  -> object files
  -> linked libraries
  -> generated files

A build graph helps Vix answer:

txt
What changed?
What depends on it?
What must rebuild?
What can be reused?

This is the base of fast target builds.

Target-aware builds

A target-aware build does not rebuild everything blindly.

It asks:

txt
Which target was requested?
Which files affect that target?
Which tasks are dirty?

If only one target is requested, Vix should focus on that target.

This matters in large projects.

A backend with many modules should not rebuild unrelated work when the target does not need it.

The rule:

txt
build what the requested target needs
do not rebuild unrelated work

Ninja integration

Vix can use Ninja through CMake.

The model:

txt
Vix resolves the project
CMake generates the build graph
Ninja executes build tasks
Vix improves the workflow around it

Vix does not need to replace Ninja.

Ninja is already good at fast builds.

Vix adds application awareness, dependency workflows, diagnostics, and higher-level commands.

CMake fallback

Fallback is important.

If Vix cannot safely use a direct path, it should use the safer build path.

For scripts:

bash
vix run server.cpp

Vix can compile directly when enough.

But when the file needs modules, dependencies, sanitizers, or project-level config, CMake fallback is safer.

The same rule applies to build workflows:

txt
direct when safe
fallback when needed

Clean builds

Sometimes you need to remove local generated state.

Use:

bash
vix clean

This removes project-local cache directories such as:

txt
.vix/
build/

It does not remove global Vix state under:

txt
~/.vix/

Use clean when the local project state is wrong or stale.

Reset builds

A reset is stronger than clean.

bash
vix reset

It runs:

txt
vix clean
vix install

Use reset when dependency state or generated project state is broken.

Typical workflow:

bash
vix reset
vix build

Build after dependency changes

When dependencies change, rebuild the project.

Examples:

bash
vix add softadastra/json
vix build
bash
vix update --install
vix build
bash
vix remove softadastra/json
vix install
vix build

Dependency changes can affect include paths, link targets, modules, and generated integration files.

So the build must treat dependency state as an input.

Build and tests

A build only proves that the code compiles.

It does not prove behavior.

Use:

bash
vix check --tests

or:

bash
vix tests

A serious workflow should be:

bash
vix build
vix check --tests

For release:

bash
vix build --preset release
vix check --tests

Build and formatting

Formatting is not part of compilation.

But it belongs in the development workflow.

Use:

bash
vix fmt

Check formatting before commit:

bash
vix fmt --check

A clean validation flow:

bash
vix fmt --check
vix build
vix check --tests

Build and packaging

Packaging should happen after a successful build.

bash
vix build --preset release
vix check --tests
vix pack
vix verify

vix pack creates a distributable package.

vix verify checks package integrity.

Do not package broken builds.

Build and production

Production builds should be explicit.

Use:

bash
vix build --preset release

Then validate:

bash
vix check --tests

Then deploy:

bash
vix deploy

A production deployment can also run its own configured build command.

Example production config can point to:

txt
vix build --preset release

The deployment workflow should not rely on an accidental debug build.

Debug builds vs release builds

Development builds favor speed and diagnostics.

Release builds favor optimized output.

Simple model:

BuildPurpose
devfast local work
debugdebugging and symbols
releaseoptimized production output

Use the right build for the right stage.

Do not benchmark debug builds.

Do not deploy accidental local builds.

Sanitizer builds

Some builds need sanitizers.

Examples:

txt
address sanitizer
undefined behavior sanitizer
thread sanitizer
leak sanitizer

Sanitizers are useful for finding bugs.

They can affect flags, linking, and runtime behavior.

That is why scripts or projects using sanitizer modes may need a safer CMake-backed path.

The principle:

txt
sanitizer builds must be explicit and reproducible

Build diagnostics

Good build diagnostics should show:

txt
project kind
build directory
preset
target
compiler
generator
cache status
configured or reused
number of sources
errors with useful context

A failed build should not leave the developer guessing.

Bad output:

txt
build failed

Better output:

txt
error: build failed
target: api
preset: dev
step: compile
file: src/routes/HealthRoutes.cpp
fix: run vix build -v for details

A build tool should help you continue.

Verbose build

Verbose mode is useful when normal output is not enough.

Example:

bash
vix build -v

Verbose output can show:

txt
resolved project kind
source count
header count
compile tasks
imported compile commands
Ninja tasks
cache hits
cache misses
linker
launcher
jobs

Use verbose mode for debugging, not every normal build.

Build failure categories

Most build failures fall into a few categories:

txt
project resolution failed
configuration failed
dependency missing
compile error
link error
generated file missing
toolchain missing
cache invalid
runtime target missing

The fix depends on the category.

Examples:

bash
vix doctor
vix info
vix install
vix reset
vix build -v

Use vix doctor for environment issues.

Use vix info for local Vix state.

Use vix reset when project-local state is broken.

Build and vix dev

vix dev uses the build workflow repeatedly.

It watches changes, classifies them, then rebuilds or reconfigures.

The model:

txt
file changed
  -> classify
  -> rebuild-only or reconfigure-and-rebuild
  -> restart app

That means vix dev depends on a correct build model.

If build invalidation is wrong, dev mode becomes unreliable.

Build and vix run

vix run can trigger a build before execution.

For a project:

bash
vix run

The workflow can be:

txt
resolve project
  -> build target if needed
  -> run target

For a single file:

bash
vix run main.cpp

The workflow can be direct compile or fallback.

The build system supports runtime.

Runtime depends on build correctness.

Build and vix.app

The vix.app build path should be invisible enough to be simple, but visible enough to debug.

The user should know:

txt
vix.app was detected
internal CMake project was generated
target name was resolved
build directory was used

The generated CMake file is an implementation detail.

But when build fails, Vix should show where it generated the project.

That helps debugging.

Common workflows

Install and build:

bash
vix install
vix build

Build release:

bash
vix build --preset release

Clean and rebuild:

bash
vix clean
vix build

Reset and rebuild:

bash
vix reset
vix build

Build then test:

bash
vix build
vix check --tests

Release validation:

bash
vix fmt --check
vix build --preset release
vix check --tests
vix pack
vix verify

Common mistakes

Building before installing dependencies

Wrong after clone:

bash
vix build

Correct:

bash
vix install
vix build

Using update when install is needed

Wrong after clone:

bash
vix update

Correct:

bash
vix install

Deploying without release build

Wrong:

bash
vix deploy

Better:

bash
vix build --preset release
vix check --tests
vix deploy

Trusting cache blindly

If something looks wrong:

bash
vix clean
vix build

If dependency state is also suspicious:

bash
vix reset
vix build

Editing build config during dev and expecting rebuild only

Config changes require reconfigure.

Examples:

txt
vix.app
CMakeLists.txt
CMakePresets.json
vix.lock

These are not normal source changes.

Build checklist

A good Vix build should answer:

txt
Which project was resolved?
Was it CMake or vix.app?
Which target was built?
Which preset was used?
Were dependencies installed?
Was configuration needed?
Was cache used?
What compiler was used?
Where is the output?
What failed if it failed?

If a build cannot answer these questions, the output is not good enough.

What you should remember

Build workflow is not only compilation.

It is:

txt
resolve
  -> configure
  -> compile
  -> link
  -> cache safely
  -> report clearly

For apps:

txt
vix.app gives the simple build model
CMakeLists.txt gives the advanced build model

For correctness:

txt
reuse only when safe
fallback when uncertain

For daily work:

bash
vix build

For release:

bash
vix build --preset release
vix check --tests

For broken local state:

bash
vix reset
vix build

The core build model:

txt
correct first
fast second
clear always

Next chapter

Next: Modules and Composition

Released under the MIT License.