Skip to content

The toolchain

To compile, assemble, link, and run CP/M apps with the DCC C Compiler toolchain, you need two things: the DCC C Compiler tools (dcc, dccmake, dccpeep, dccrtlstrip, plus DCCRTL.MAC, m80.com, and l80.com) and the ntvcm CP/M 2.2 emulator to run CP/M binaries, including m80.com, l80.com, and the resulting programs.

You build these tools once. After that, use them from any CP/M app project.

Setup flow:

  • Install the host prerequisites for Windows, macOS, or Linux.
  • Clone the DCC C Compiler (dcc) and ntvcm repositories.
  • Build the DCC C Compiler host tools with pwsh ./scripts/build-dcc.ps1.
  • Build the ntvcm emulator.
  • Add the DCC C Compiler and ntvcm directories to your PATH.
  • Verify the setup with a sample CP/M program.

Install prerequisites

Install the native compiler tools for your host platform before cloning and building DCC C Compiler or ntvcm.

  1. Install Visual Studio Build Tools with the C++ workload. Install with winget:

    winget install --id Microsoft.VisualStudio.BuildTools -e --override "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --quiet --wait --norestart"
    

    You can also use the Visual Studio Installer and select Desktop development with C++. The Windows build uses the Microsoft C/C++ compiler tools from that installation.

  2. Install PowerShell 7 (pwsh) from the Microsoft PowerShell install guide, then verify it is available:

    pwsh --version
    
  1. Install the Xcode Command Line Tools:

    xcode-select --install
    

    This provides the clang and C++ compiler tools used by the macOS build scripts.

  2. Install PowerShell 7 (pwsh) with Homebrew or the Microsoft PowerShell install guide, then verify it is available:

    brew install --cask powershell
    pwsh --version
    
  1. Install gcc, g++, make, and the usual build tools:

    sudo apt install build-essential
    
  2. Install PowerShell 7 (pwsh) using the package instructions for your Ubuntu release in the Microsoft PowerShell install guide, then verify it is available:

    pwsh --version
    
  1. Install gcc, g++, make, and the usual build tools:

    sudo apt install build-essential
    
  2. Install an ARM64 build of PowerShell 7 (pwsh). If the package flow for your Ubuntu release is available, use the Microsoft PowerShell install guide. If not, use the official linux-arm64 tarball from the PowerShell release page. To find the latest available version, check the PowerShell releases page or query the GitHub release metadata:

    curl -fsSL https://api.github.com/repos/PowerShell/PowerShell/releases/latest \
        | sed -n 's/.*"tag_name": "v\([^"]*\)".*/\1/p'
    

    For a user-local install, set version to that release:

    version=7.6.3
    install_dir="$HOME/.local/share/powershell/$version"
    archive="/tmp/powershell-${version}-linux-arm64.tar.gz"
    
    mkdir -p "$install_dir" "$HOME/.local/bin"
    curl -fL \
        "https://github.com/PowerShell/PowerShell/releases/download/v${version}/powershell-${version}-linux-arm64.tar.gz" \
        -o "$archive"
    tar -xzf "$archive" -C "$install_dir"
    chmod +x "$install_dir/pwsh"
    ln -sfn "$install_dir/pwsh" "$HOME/.local/bin/pwsh"
    

    Make sure ~/.local/bin is on your PATH, then verify both the version and architecture:

    export PATH="$HOME/.local/bin:$PATH"
    pwsh --version
    file "$(readlink -f "$HOME/.local/bin/pwsh")"
    

    The file output should report ARM aarch64.

  1. Install Visual Studio Build Tools with the C++ workload and native ARM64 compiler tools. Install with winget:

    winget install --id Microsoft.VisualStudio.BuildTools -e --override "--add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.ARM64 --includeRecommended --quiet --wait --norestart"
    

    You can also use the Visual Studio Installer and select Desktop development with C++, then add the MSVC ARM64/ARM64EC build tools component. The DCC C Compiler Windows build scripts use the native ARM64 MSVC environment (vcvarsarm64.bat) when they run on Windows ARM64.

  2. Verify that the ARM64 MSVC tools were installed:

    $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe"
    $installPath = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.ARM64 -property installationPath
    Test-Path "$installPath\VC\Auxiliary\Build\vcvarsarm64.bat"
    

    The final command should print True.

  3. Install PowerShell 7 (pwsh) from the Microsoft PowerShell install guide, then verify it is available:

    pwsh --version
    

Clone the repositories

# Clone DCC C Compiler
git clone https://github.com/davidly/dcc.git

# Clone the ntvcm z80 emulator
git clone https://github.com/davidly/ntvcm.git

Build DCC C Compiler

The cross-platform PowerShell build script is in the scripts directory. It builds dcc, dccpeep, and dccrtlstrip, using MSVC on Windows, clang on macOS, and gcc on Linux by default:

pwsh ./scripts/build-dcc.ps1

Build ntvcm

ntvcm is a C++ project. Build it from its own directory.

Open a Developer PowerShell or Developer Command Prompt so the Microsoft C/C++ compiler (cl) is on your PATH, then run the Windows build script:

cd ntvcm
.\m.bat

Produces ntvcm.exe.

Open a terminal where the Xcode Command Line Tools are available, then run the macOS build script:

cd ntvcm
chmod +x mmac.sh
./mmac.sh

Produces the ntvcm executable.

Open a terminal where g++ is available, then run the Linux build script:

cd ntvcm
chmod +x m.sh
./m.sh

Produces the ntvcm executable.

Open a terminal where g++ is available, then run the Linux build script:

cd ntvcm
chmod +x m.sh
./m.sh

Produces the ntvcm executable.

Open a Developer PowerShell or Developer Command Prompt for ARM64 so the Microsoft C/C++ compiler (cl) is on your PATH, then run the Windows build script:

cd ntvcm
.\m.bat

Produces ntvcm.exe.

Set up your environment

Build scripts live in the scripts directory:

  • dcc-ma — installed package command for building one app on Windows, macOS, and Linux
  • scripts/ma.sh — source-checkout implementation for Linux/macOS without PowerShell
  • scripts/ma.ps1 — source-checkout implementation for Windows PowerShell 5.1 or PowerShell 7+
  • scripts/runall.ps1 — builds and verifies the test suite

Run the single-app shell helper directly on Linux/macOS, or run the PowerShell scripts from your operating-system terminal or the VS Code terminal by changing to the DCC C Compiler checkout, starting pwsh, and running ./scripts/ma.ps1 or ./scripts/runall.ps1.

They resolve each tool the same way: they use an environment variable if you set one, otherwise they look for the tool on your PATH. The relevant tools are:

Recommended setup, especially when building apps in a project outside the DCC C Compiler repo, is to add the directories containing the built dcc and ntvcm binaries to your PATH. The DCC C Compiler directory also provides dccpeep, dccrtlstrip, m80.com, l80.com, and DCCRTL.MAC, so no per-tool variables are needed.

  1. Add the DCC C Compiler and ntvcm directories to PATH for the current PowerShell session:

    $env:PATH += ";C:\path\to\dcc;C:\path\to\ntvcm"
    
  2. To make that permanent for your Windows user account, update the user PATH and then open a new terminal:

    $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
    [Environment]::SetEnvironmentVariable("Path", "$userPath;C:\path\to\dcc;C:\path\to\ntvcm", "User")
    
  3. Replace C:\path\to\dcc and C:\path\to\ntvcm with the actual directories. With this on your PATH, the scripts find dcc, dccpeep, dccrtlstrip, and ntvcm automatically.

To pin specific binaries instead (for example, when juggling multiple DCC C Compiler builds), set the environment variables to explicit paths and only put ntvcm on PATH:

```powershell
$env:PATH += ";C:\path\to\ntvcm"
$env:DCC = "C:\path\to\dcc\dcc.exe"
$env:DCCPEEP = "C:\path\to\dcc\dccpeep.exe"
$env:DCCRTLSTRIP = "C:\path\to\dcc\dccrtlstrip.exe"
```
  1. Add the DCC C Compiler and ntvcm directories to PATH for the current shell session:

    export PATH="$PATH:/path/to/dcc:/path/to/ntvcm"
    
  2. To make that permanent for the default zsh shell, append the same setting to ~/.zshrc, then open a new terminal or reload the file:

    printf '\nexport PATH="$PATH:/path/to/dcc:/path/to/ntvcm"\n' >> ~/.zshrc
    source ~/.zshrc
    
  3. Replace /path/to/dcc and /path/to/ntvcm with the actual directories (e.g. ~/GitHub/dcc and ~/GitHub/ntvcm). With this on your PATH, the scripts find dcc, dccpeep, dccrtlstrip, and ntvcm automatically.

To pin specific binaries instead (for example, when juggling multiple DCC C Compiler builds), set the environment variables to explicit paths and only put ntvcm on PATH:

```bash
export PATH="$PATH:/path/to/ntvcm"
export DCC=/path/to/dcc/dcc
export DCCPEEP=/path/to/dcc/dccpeep
export DCCRTLSTRIP=/path/to/dcc/dccrtlstrip
```
  1. Add the DCC C Compiler and ntvcm directories to PATH for the current shell session:

    export PATH="$PATH:/path/to/dcc:/path/to/ntvcm"
    
  2. To make that permanent for bash, append the same setting to ~/.bashrc, then open a new terminal or reload the file:

    printf '\nexport PATH="$PATH:/path/to/dcc:/path/to/ntvcm"\n' >> ~/.bashrc
    source ~/.bashrc
    
  3. Replace /path/to/dcc and /path/to/ntvcm with the actual directories (e.g. ~/GitHub/dcc and ~/GitHub/ntvcm). With this on your PATH, the scripts find dcc, dccpeep, dccrtlstrip, and ntvcm automatically.

To pin specific binaries instead (for example, when juggling multiple DCC C Compiler builds), set the environment variables to explicit paths and only put ntvcm on PATH:

```bash
export PATH="$PATH:/path/to/ntvcm"
export DCC=/path/to/dcc/dcc
export DCCPEEP=/path/to/dcc/dccpeep
export DCCRTLSTRIP=/path/to/dcc/dccrtlstrip
```
  1. Add the DCC C Compiler and ntvcm directories to PATH for the current shell session:

    export PATH="$PATH:/path/to/dcc:/path/to/ntvcm"
    
  2. To make that permanent for bash, append the same setting to ~/.bashrc, then open a new terminal or reload the file:

    printf '\nexport PATH="$PATH:/path/to/dcc:/path/to/ntvcm"\n' >> ~/.bashrc
    source ~/.bashrc
    
  3. Replace /path/to/dcc and /path/to/ntvcm with the actual directories (e.g. ~/GitHub/dcc and ~/GitHub/ntvcm). With this on your PATH, the scripts find dcc, dccpeep, dccrtlstrip, and ntvcm automatically.

To pin specific binaries instead (for example, when juggling multiple DCC C Compiler builds), set the environment variables to explicit paths and only put ntvcm on PATH:

```bash
export PATH="$PATH:/path/to/ntvcm"
export DCC=/path/to/dcc/dcc
export DCCPEEP=/path/to/dcc/dccpeep
export DCCRTLSTRIP=/path/to/dcc/dccrtlstrip
```
  1. Add the DCC C Compiler and ntvcm directories to PATH for the current PowerShell session:

    $env:PATH += ";C:\path\to\dcc;C:\path\to\ntvcm"
    
  2. To make that permanent for your Windows user account, update the user PATH and then open a new terminal:

    $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
    [Environment]::SetEnvironmentVariable("Path", "$userPath;C:\path\to\dcc;C:\path\to\ntvcm", "User")
    
  3. Replace C:\path\to\dcc and C:\path\to\ntvcm with the actual directories. With this on your PATH, the scripts find dcc, dccpeep, dccrtlstrip, and ntvcm automatically.

To pin specific binaries instead (for example, when juggling multiple DCC C Compiler builds), set the environment variables to explicit paths and only put ntvcm on PATH:

```powershell
$env:PATH += ";C:\path\to\ntvcm"
$env:DCC = "C:\path\to\dcc\dcc.exe"
$env:DCCPEEP = "C:\path\to\dcc\dccpeep.exe"
$env:DCCRTLSTRIP = "C:\path\to\dcc\dccrtlstrip.exe"
```

Verify the setup

With the tools on your PATH, build and run one of the DCC C Compiler repo's sample tests to confirm everything is wired up. From your operating-system terminal or the VS Code terminal, change to the DCC C Compiler checkout, start PowerShell, build tests/tstr.c, then run the generated .COM file under ntvcm:

cd /path/to/dcc
pwsh
./scripts/ma.ps1 tstr -Mode fast       # compiles tests/tstr.c -> TSTR.COM
ntvcm TSTR.COM                         # runs it under the emulator

The DCC C Compiler repo's tests/ programs are suitable samples for scratch projects, but day-to-day work does not need to happen inside the DCC C Compiler repo. The tools build CP/M apps from wherever your sources live. Once that works, move on to Building and linking for the day-to-day workflow.