Skip to content

Bytecode & cross-platform delivery

The source is for people. DBC is the promise machines agree to keep.

This page explains what the compiler produces and how one compiled program reaches browsers, Windows, Linux, macOS and d/OS, the operating system that brings modern software to 8-bit home computers such as the Atari 800, the Commodore 64 and the Apple II. You will learn the file types, what a compiled file contains, what the runtime checks before it runs anything, how versions work, and a practical routine for shipping one file everywhere.

A .bas file describes a program in d/BASIC. The compiler turns it into the compiled program file, .dbc, whose types, instructions, capabilities, limits, entry points and dependencies are spelled out precisely enough that very different runtimes agree about it. The format inside that file is called DBC.

The file family

Extension Meaning Contains
.bas d/BASIC source the program you write, plus its imports
.dbc the compiled program file checked code, constants, type information, static layout, entry points, requirements
.dbl a shared library file the same kind of code plus an identity and a versioned list of exports; no program entry point
.dpk a d/OS package manifest, digests, signature, program, libraries, assets, file associations
.dmd a native d/OS module envelope a trusted descriptor for a native module; not d/BASIC compiled to native code

The distinction avoids a common deployment mix-up: .dbc is the portable program. .dpk is how that program and its dependencies are distributed and trusted. .dmd describes a different, native kind of module; it is not something the compiler secretly produces on one favoured platform.

Build once

dbasic build postcard.bas -o postcard.dbc

Run the result without recompiling:

dbasic exec postcard.dbc

Or compile and run in one step:

dbasic run postcard.bas

run and trace look at the first bytes of the file rather than trusting its name, so renaming a source file to .dbc cannot trick the loader into executing text.

One file, several homes

                         ┌─ browser WebAssembly runner → WebGL2 composed scene
postcard.bas → postcard.dbc ─┼─ Windows runner → native window / console
                         ├─ Linux runner   → native window / console
                         ├─ macOS runner   → native window / console
                         └─ d/OS runtime   → composed product head

The optimizing compiler and the console runtime build on Windows, Linux and macOS. In the browser, both compiling and running happen through WebAssembly. Desktop windows use the same boundary between the compiled file and the runtime, the program that runs your compiled code. d/OS runs the same instructions and intents (an intent is a named request such as "fill this rectangle" that the machine carries out however it can) through its own runtime and its display side, which composes the final picture.

This is not source compatibility in the weak sense of "recompile several similar programs." One compiled file gives every runtime the same program and the same promises about what it does.

Portability is not the lowest common denominator

Every program declares a coarse maximum of what it may need, and the compiler records the exact vocabulary the program actually uses inside that boundary. A rich runtime can carry those meanings out in a richer way; a small runtime can carry them out more simply. If a destination cannot provide what the program declared, or the version it needs, it declines before running rather than changing the program.

That means you can write a program that needs styled text or persistent DATA without forcing every tiny machine to pretend it offers those things. The same file runs wherever what it declared is available.

Read Intents & Services for how fonts, colour, maths, graphics and bulk operations adapt.

What is inside a compiled file

A .dbc file begins with a fixed 64-byte little-endian header. It identifies and bounds:

  • the code bytes;
  • the constant and type pool;
  • static storage;
  • runtime memory requirements;
  • the total length of the file;
  • the table of entry points;
  • value-stack and call-frame ceilings;
  • feature and version requirements; and
  • dependency and library flags.

The loader checks every range before anything runs. A file may be larger than one 64 KiB window of memory because runtimes page its unchanging parts in and out through managed handles; the file format is not tied to the address space of one vintage CPU. The 6502 large-memory model starts with a 512 KiB profile while keeping banking out of your source.

Check, bind, confirm, run

open bytes → validate DBC → bind exact .dbl dependencies → check versions and capabilities → run in slices → show, stop, or halt

1. Validate

The loader checks the marker bytes, the length, the versions, the sections, instruction boundaries, types, stack effects, entry points and metadata. Malformed data never becomes a half-running program.

2. Bind

If the file imports shared libraries, the loader resolves each one by exact identity, version, signature, class shape and SHA-256 digest. Binding finishes before any program code runs.

3. Check what the machine offers

The host compares the file's Service, intent, MATH, memory and display needs with what it actually provides.

4. Run in bounded turns

The virtual machine runs a finite slice of instructions, then reports one of: the program halted or stopped with an error, an external operation is pending, a lifecycle boundary was reached, or there is more work to do. This keeps a browser tab and a small d/OS machine responsive without changing what the language means.

5. Complete visibly

A frame is complete when the display confirms it was shown, not merely when a GPU queue accepted it. An external commit is complete when the host confirms it, not merely when the program asked. d/BASIC names these boundaries so that runtimes cannot quietly disagree about them.

Versioning

The DBC version has two independent parts, one for the container and one for the Services. A program that uses only older features can declare an older minimum even when built by a newer compiler; the compiler raises only the parts that the features it emitted require.

This reference was checked against DBC 1.15.1.10 on 2 September 2026. A few feature minimums show how the model works:

Feature Minimum DBC
records 1.1.1.0
objects 1.3.1.0
portable math evaluation batches 1.4.1.0
extended window lifecycle faces 1.8.1.0
dependent program images 1.9.1.10
ARRAYCOPY 1.10.1.0
library artifacts 1.11.1.10
cross-artifact calls 1.12.1.10
typed array signatures 1.13.1.10
ARRAYFILL and ARRAYSWAP 1.14.1.0
shared class descriptors 1.15.1.10

A newer runtime accepts an older declared minimum. An older runtime rejects a future requirement by version before it ever meets an unknown instruction.

Cross-platform runtimes

Destination What stays the same What adapts locally
browser DBC checks, sliced VM, normalized window and input, GFX intents execution in a worker, a retained WebGL2 scene, browser-font textures
Windows compiler, runtime, Service and intent rules native event loop, WGPU presentation, local providers
Linux compiler, runtime, Service and intent rules native event loop, WGPU presentation, Linux providers
macOS compiler, runtime, Service and intent rules native event loop, WGPU presentation, macOS providers
d/OS bytecode, requirements, entry points, handles, intents the product's compositor, hardware and provider routes, bounded paging

Your source contains no platform cfg, no host path, no native pointer, no windowing-toolkit object and no conditional dialect. The runtime owns those adaptations.

Shared libraries travel by identity

IMPORT dworks.widgets SHARED

The compiler records a dependency only for an export the program actually uses. The package installs the exact .dbl; the loader binds it before the program runs. A virtual call into an imported class still follows one class identity and one dispatch model across the file boundary.

For a self-contained delivery, use BAKED. See Imports & Libraries.

Packages and trust

A d/OS package holds the distribution facts that BASIC source should not own:

  • the application's identity and version;
  • which .dbc, .dbl and asset files belong to it;
  • SHA-256 digests;
  • file associations, such as .dbc to run and .bas to edit;
  • capability and product policy; and
  • the publisher's signature.

Checking the signature establishes trust in the publisher and the package at install time. Checking the digests ensures the file opened at launch is the file the manifest named. DBC validation still checks structural safety. Each layer answers a different question.

A practical delivery loop

  1. Write and test the .bas in the playground or the desktop tool.
  2. Run representative cases, both successes and the cases where the program should stop and say why.
  3. Build one .dbc.
  4. Run that exact file on each runtime you intend to ship to.
  5. Compare standard traces where runtime equivalence matters.
  6. Package the exact file together with the .dbl and asset bytes it needs.
  7. Verify the package, then test install and launch.

Do not recompile separately on each platform unless you are testing the compiler itself. Shipping one byte-exact .dbc is how you know every platform received the same program.

The cross-platform habits

  • Store meaning in values, records, objects and handles, not in addresses.
  • Let RESIZE drive layout.
  • Use widgets and named font and colour roles.
  • Use intents for external work.
  • State bulk work with bulk verbs.
  • Make recovery from a missing optional capability explicit.
  • Test the compiled file, not merely the source build.

Next: Compatibility, Migration & Refusals →