Appearance
vix.app Project Resolution
vix.app project resolution is the step where Vix decides what kind of project it is working with.
Before Vix can build or run anything, it needs to answer a few questions:
txt
Where is the project root?
Is this a CMake project?
Is this a vix.app project?
What source directory should CMake use?
What target name should be built?
Where should build directories be created?This resolution step is small, but it is important.
If project resolution is wrong, the build system can use the wrong directory, the wrong target name, or the wrong generated CMake source.
The resolution rule
Vix uses this rule:
txt
1. If CMakeLists.txt exists, use CMakeLists.txt.
2. Otherwise, if vix.app exists, use vix.app.This keeps existing CMake projects safe.
A project like this is resolved as a CMake project:
txt
myapp/
CMakeLists.txt
vix.app
src/
main.cppA project like this is resolved as a vix.app project:
txt
myapp/
vix.app
src/
main.cppCMake has priority because it is the full-control path.
vix.app is used only when there is no CMakeLists.txt.
Why CMake has priority
CMake projects can contain arbitrary build logic.
If a CMakeLists.txt exists, Vix should not ignore it.
That file may define:
txt
custom targets
generated sources
install rules
CTest integration
toolchains
package exports
platform branches
dependency setupUsing vix.app instead would risk breaking the project.
The safe rule is:
txt
CMakeLists.txt is explicit full control.
vix.app is the simple project path.The project root
The project root is the directory that contains one of these files:
txt
CMakeLists.txt
vix.appWhen Vix starts from a directory, it can search upward until it finds a project root.
Example:
txt
myapp/
vix.app
src/
main.cpp
features/
auth.cppIf the user runs Vix from:
txt
myapp/src/features/Vix can walk upward and find:
txt
myapp/vix.appThe resolved project root is:
txt
myapp/CMake project resolution
For a normal CMake project:
txt
myapp/
CMakeLists.txt
src/
main.cppthe resolved model is simple:
txt
project kind: CMake
user project dir: myapp/
CMake source dir: myapp/
CMakeLists path: myapp/CMakeLists.txt
target name: usually myapp
generated: falseIn this case, the user project directory and the CMake source directory are the same.
Vix can configure CMake with:
bash
cmake -S myapp -B myapp/build-ninjavix.app project resolution
For a vix.app project:
txt
myapp/
vix.app
src/
main.cppVix resolves the project differently.
The user project directory is still:
txt
myapp/But the CMake source directory is generated:
txt
myapp/.vix/generated/app/The resolved model becomes:
txt
project kind: vix.app
user project dir: myapp/
CMake source dir: myapp/.vix/generated/app/
CMakeLists path: myapp/.vix/generated/app/CMakeLists.txt
target name: manifest name
generated: trueSo if vix.app contains:
ini
name = hello
type = executable
standard = c++20
sources = [
src/main.cpp,
]then the default target name is:
txt
hellonot necessarily the project folder name.
Why target name matters
The target name is important because it is used by:
txt
vix build
vix run
CMake target selection
executable lookup
diagnostics
artifact identityIf the project folder is called:
txt
hello-project/but the manifest says:
ini
name = hellothen Vix should build and run:
txt
hellonot:
txt
hello-projectThis is why vix.app resolution must expose the manifest target name.
The important separation
For vix.app, there are two different directories:
txt
userProjectDir
cmakeSourceDirThey must not be confused.
The user project directory is where the real project lives:
txt
myapp/It contains:
txt
vix.app
src/
include/
assets/
tests/The CMake source directory is internal:
txt
myapp/.vix/generated/app/It contains the generated:
txt
CMakeLists.txtThese two paths serve different purposes.
userProjectDir
userProjectDir should be used for user-facing project operations.
Examples:
txt
build directories
.env lookup
.vix metadata
resources
source path resolution
snapshots
local cache state
exported binaries
watch modeFor a vix.app project:
txt
userProjectDir = myapp/That should remain true even though the generated CMake file is somewhere else.
cmakeSourceDir
cmakeSourceDir should be used for CMake configuration.
Examples:
txt
cmake -S
generated CMake diagnostics
CMakeLists.txt path
CMake configure source directoryFor a vix.app project:
txt
cmakeSourceDir = myapp/.vix/generated/app/So Vix configures CMake with:
bash
cmake -S myapp/.vix/generated/app -B myapp/build-ninjanot with:
bash
cmake -S myapp -B myapp/build-ninjabecause the original project root does not contain a CMakeLists.txt.
The bug this separation avoids
A common mistake is to store only one projectDir.
For CMake projects, that works because:
txt
projectDir = user project dir = CMake source dirBut for vix.app, that breaks down.
If projectDir is changed to:
txt
myapp/.vix/generated/app/then other systems may accidentally treat the generated directory as the real project.
That can break:
txt
target name detection
build directory placement
export paths
input snapshots
watch mode
resource paths
.env lookup
cache keysThe correct model is to keep both paths.
A better build plan model
A build plan should distinguish:
txt
userProjectDir
cmakeSourceDir
defaultTargetName
generatedFromVixAppFor a CMake project:
txt
userProjectDir = myapp/
cmakeSourceDir = myapp/
defaultTargetName = myapp
generatedFromVixApp = falseFor a vix.app project:
txt
userProjectDir = myapp/
cmakeSourceDir = myapp/.vix/generated/app/
defaultTargetName = manifest.name
generatedFromVixApp = trueThis makes the rest of the build system simpler.
Each operation can choose the correct path.
Configure uses cmakeSourceDir
CMake configure should use:
txt
cmakeSourceDirFor CMake projects:
bash
cmake -S myapp -B myapp/build-ninjaFor vix.app projects:
bash
cmake -S myapp/.vix/generated/app -B myapp/build-ninjaThis is the only path that should be passed to cmake -S.
Build directories use userProjectDir
Build directories should be created under the user project directory.
For example:
txt
myapp/build-ninja/
myapp/build-dev/
myapp/build-release/Not under:
txt
myapp/.vix/generated/app/build-ninja/The generated CMake directory is internal source metadata.
It should not become the visible project root.
Default target uses manifest name
For vix.app, the default target should come from:
ini
name = helloSo vix build should build:
bash
cmake --build build-ninja --target hellonot:
bash
cmake --build build-ninja --target appThe generated directory is named app, but that is not the target name.
The target name belongs to the manifest.
vix build project resolution
For vix build, project resolution should produce a build plan.
The build plan should contain:
txt
userProjectDir
cmakeSourceDir
buildDir
configureLog
buildLog
defaultTargetName
generatedFromVixAppThen the build command can do:
txt
configure:
cmake -S cmakeSourceDir -B buildDir
build:
cmake --build buildDir --target defaultTargetName
cache/snapshot/export:
use userProjectDirThis keeps CMake integration and user project handling separate.
vix run project resolution
vix run also needs the same resolved project metadata.
It needs to know:
txt
where to configure
where to build
which target to build
which executable to run
where the real project livesFor vix.app, it should use:
txt
resolved.userProjectDir
resolved.cmakeSourceDir
resolved.targetName
resolved.generatedThen it can build the correct target and search for the executable by manifest name.
Executable lookup
After building, vix run needs to find the executable.
For a vix.app project:
ini
name = hello
output_dir = binVix should search common locations such as:
txt
build-ninja/hello
build-ninja/bin/hello
build-ninja/src/helloThe lookup should use:
txt
targetName = hellonot the folder name and not the generated directory name.
Watch mode
Watch mode should watch the real project directory.
For CMake projects:
txt
watch myapp/For vix.app projects:
txt
watch myapp/It should not watch only:
txt
myapp/.vix/generated/app/The generated directory does not contain the user’s real source files.
Watch mode belongs to the user project directory.
Diagnostics
Project resolution also affects diagnostics.
For a generated vix.app project, build errors may involve:
txt
generated CMakeLists.txt
real source files
manifest fieldsA good diagnostic should show the correct context.
Examples:
txt
Project directory:
myapp/
Generated CMake source:
myapp/.vix/generated/app/
Build directory:
myapp/build-ninja/This helps engineers understand which layer failed.
Generated CMake path
When configure fails for a vix.app project, the relevant CMake file is:
txt
.vix/generated/app/CMakeLists.txtSo CMake diagnostics should point there.
But source validation errors should point back to:
txt
vix.app
src/main.cpp
include/The diagnostic layer should not confuse generated files with user-authored files.
Why AppProjectResolver exists
A dedicated project resolver makes this logic reusable.
Both vix build and vix run need the same answer:
txt
What project is this?
Where is the real root?
Where is the CMake source?
What target should I build?
Was this generated from vix.app?If each command implements its own resolution logic, they can drift.
A shared resolver keeps behavior consistent.
Resolver result
A useful resolver result contains:
txt
kind
userProjectDir
cmakeSourceDir
cmakeListsPath
appManifestPath
targetName
generated
errorFor a CMake project:
txt
kind = CMake
userProjectDir = project/
cmakeSourceDir = project/
cmakeListsPath = project/CMakeLists.txt
targetName = project folder name
generated = falseFor a vix.app project:
txt
kind = vix.app
userProjectDir = project/
cmakeSourceDir = project/.vix/generated/app/
cmakeListsPath = project/.vix/generated/app/CMakeLists.txt
appManifestPath = project/vix.app
targetName = manifest.name
generated = trueSearch behavior
The resolver can start from:
txt
current directory
a file path
a directory passed with --dirThen it searches upward for:
txt
CMakeLists.txt
vix.appThe first directory containing either file becomes the project root.
Inside that root, CMake has priority.
Example: current directory
Project:
txt
hello/
vix.app
src/
main.cppCommand:
bash
cd hello
vix buildResolved result:
txt
kind = vix.app
userProjectDir = hello/
cmakeSourceDir = hello/.vix/generated/app/
targetName = manifest.nameExample: nested directory
Project:
txt
hello/
vix.app
src/
features/
auth.cppCommand:
bash
cd hello/src/features
vix buildThe resolver walks upward and finds:
txt
hello/vix.appResolved root:
txt
hello/Example: CMake wins
Project:
txt
hello/
CMakeLists.txt
vix.app
src/
main.cppResolved result:
txt
kind = CMake
userProjectDir = hello/
cmakeSourceDir = hello/
generated = falseThe vix.app file is ignored for project resolution.
Failure cases
Resolution can fail when neither file exists.
Example:
txt
empty-folder/
src/
main.cppCommand:
bash
vix buildError:
txt
Unable to determine the project directory.
Missing CMakeLists.txt or vix.app.The fix is to add either:
txt
CMakeLists.txtor:
txt
vix.appManifest load failure
For vix.app, resolution includes loading the manifest.
This can fail when:
txt
name is missing
sources are missing
type is invalid
standard is invalid
array syntax is malformed
unknown field is presentIn that case, project resolution should return a structured error.
The command should display that error clearly and stop before CMake runs.
Generated CMake failure
After the manifest is loaded, Vix generates the internal CMake project.
Generation can fail when:
txt
source files do not exist
resource paths are invalid
output paths are invalid
package syntax is invalid
target name is invalidThese are still manifest-level or generation-level errors.
They should be reported before the configure/build stage when possible.
Why this is important for native builds
Project resolution is also the foundation for future native vix.app builds.
The future build path may be:
txt
vix.app
-> native BuildGraph
-> ObjectCache
-> Scheduler
-> LinkThat path still needs the same resolved metadata:
txt
userProjectDir
targetName
sources
include_dirs
defines
output_dir
resourcesSo clean project resolution is not only about generated CMake.
It is also preparation for a native build engine.
The clean architecture
A clean architecture has three layers:
txt
Project resolution
decides what project this is
Build planning
decides what to configure, build, cache, and run
Execution
runs CMake, Ninja, native tasks, or the final executablevix.app should enter the system at the resolution layer.
It should not be patched into every command separately.
Practical rule for engineers
When changing Vix project resolution, keep this rule in mind:
txt
CMake source directory is not always the user project directory.
Target name is not always the project folder name.This is the core lesson from vix.app.
For normal CMake projects, those values often look the same.
For generated projects, they are different.
Conclusion
vix.app project resolution is about keeping identities separate.
A vix.app project has:
txt
a real user project directory
a generated CMake source directory
a manifest-defined target name
a generated flagCMake projects remain the full-control path.
vix.app projects become the simple path.
The resolver connects both models through one consistent result.
That consistency lets vix build, vix run, diagnostics, caching, and future native builds all reason about the project the same way.