Documentation

Getting started

Open raw manual.md

This page builds a minimal C++ hello world program with nobs. The point of the example is to show the basic project shape: source files describe the program, and nobs.txt describes what the target is made from.

1. Create a project

Create this directory structure:

hello-nobs
|-- nobs.txt
`-- src
    `-- main.cpp

2. Add the source file

src/main.cpp:

#include <iostream>

int main()
{
    std::cout << "Hello from nobs\n";
    return 0;
}

3. Add nobs.txt

nobs.txt:

app:
{
  CPP_FILES = P"(src/*.cpp)"
}

This declares one target named app. The target says that the program is built from every C++ source file under src/.

CPP_FILES is what makes a C++ compiler builder applicable. The P"(...) syntax creates a path value. It is resolved relative to the nobs.txt file and supports globbing, so src/*.cpp expands to the matching source files.

4. Configure toolchains once

If this is the first time you are running nobs on the machine, let it detect installed compilers:

nobs --find-compilers

This writes or updates the machine-local registry used for compiler selection. On Windows this registry is %APPDATA%\nobs\.nobs_registry.txt; on Unix-like systems it is ~/.config/nobs/.nobs_registry.txt. You normally only need to do this after installing nobs or after changing compiler installations.

5. Build

From the hello-nobs directory, run:

nobs app

nobs reads nobs.txt, creates the context for app, selects the best matching compiler toolchain from the registry, and builds the executable.

If app is the first target in the file, this is equivalent:

nobs

6. Add build settings

Targets are just contexts, so adding compiler inputs is a matter of adding variables:

app:
{
  CPP_FILES = P"(src/*.cpp)"
  C_DEFINES = ["UNICODE", "TRACE_LEVEL=1"]
}

C_DEFINES adds preprocessor definitions. CPP_FILES is resolved to the matching source files before the compiler is run.

Compiler flags are passed to the selected compiler as-is, so use flags that belong to that toolchain. _FLAGS variables should be lists, with one compiler option per list item, because each list item is passed as one command-line argument.

For MSVC:

app:
{
  MSVC
  CPP_FILES = P"(src/*.cpp)"
  C_DEFINES = ["UNICODE", "TRACE_LEVEL=1"]
  C_FLAGS += ["/std:c++latest"]
}

For GNU g++:

app:
{
  GNU
  CPP_FILES = P"(src/*.cpp)"
  C_DEFINES = ["UNICODE", "TRACE_LEVEL=1"]
  C_FLAGS += ["-std=c++20"]
}

The exact compiler path and resolved source path depend on your machine, but the command line has this shape:

MSVC cl.exe
cl.exe /std:c++latest "...\hello-nobs\src\main.cpp" /DUNICODE /DTRACE_LEVEL=1 /Fe"app.exe"
Tool
selected from the registry because the target matches MSVC and CPP_FILES
C_FLAGS
copied directly as compiler arguments
CPP_FILES
expanded from P"(src/*.cpp)" to resolved source file paths
C_DEFINES
emitted as /D... arguments
Target output
named from the target when OUTPUT_NAME is not set
GNU g++
g++ -std=c++20 ".../hello-nobs/src/main.cpp" -DUNICODE -DTRACE_LEVEL=1 -o "app"
Tool
selected from the registry because the target matches GNU and CPP_FILES
C_FLAGS
copied directly as compiler arguments
CPP_FILES
expanded from P"(src/*.cpp)" to resolved source file paths
C_DEFINES
emitted as -D... arguments
Target output
named from the target when OUTPUT_NAME is not set

What to remember

  • A target describes what should be built.
  • Variables such as CPP_FILES, C_FILES, C_DEFINES, and C_FLAGS describe the target inputs and compiler arguments.
  • nobs chooses the builder by matching the target context against available tools.
  • Run nobs --find-compilers once on a machine so normal builds can select a registered compiler.
  • Dependencies are added after the target name. Use app: core for a normal dependency, or app: +core when the dependency output should be merged directly into app.