TUTORIAL.md 4.4 KB

V3 tutorial — build and run Modula-2

This is a short hands-on tour. It assumes a Linux shell, gcc/gm2, Coco/R CR, and qbe as described in README.md.

1. Build the compiler

From the repository root:

cd compiler
./build.sh          # M2.atg -> scanner/parser/driver -> ./M2
./run_tests.sh      # 304/304

M2 reads Modula-2 sources and writes QBE IR to gen_ssa/.

2. Hello, world (one-shot)

The one-shot mode compiles every unit named on the command line into one image. The program module comes last.

cd compiler
./M2 tests/hello.mod                 # -> gen_ssa/Hello.ssa
qbe -o gen_ssa/Hello.s gen_ssa/Hello.ssa
cc gen_ssa/Hello.s ../runtime/syslib/shim.c -o /tmp/hello -lm
/tmp/hello

Expected output:

Hello, Modula-2!

A global VAR ExitCode : INTEGER becomes the process exit code; without one, the program returns 0.

3. A library and a program (one-shot)

A definition/implementation pair plus a program can still be compiled in one invocation:

./M2 tests/sep_lib.def tests/sep_lib.mod tests/sep_prog.mod
qbe -o gen_ssa/SepProg.s gen_ssa/SepProg.ssa
cc gen_ssa/SepProg.s ../runtime/syslib/shim.c -o /tmp/sep -lm
/tmp/sep

This produces one image and is the mode used by the test suite and the corpus harness.

4. Separate compilation

Separate compilation reads only the imported .def files when compiling a unit. The library object and the program object are linked with cc; a .def is never passed to the linker.

Direct M2 -c

From compiler/:

# Library: Lib.def is found beside Lib.mod automatically.
./M2 -c tests/sep_lib.mod

# Program: pass the imported interface explicitly.
./M2 -c tests/sep_lib.def tests/sep_prog.mod

qbe -o gen_ssa/SepLib.s   gen_ssa/SepLib.ssa
qbe -o gen_ssa/SepProg.s  gen_ssa/SepProg.ssa
cc -c gen_ssa/SepLib.s  -o gen_ssa/SepLib.o
cc -c gen_ssa/SepProg.s -o gen_ssa/SepProg.o
cc gen_ssa/SepProg.o gen_ssa/SepLib.o ../runtime/syslib/shim.c \
   -o /tmp/sep -lm
/tmp/sep

M2 -c accepts -I directories and resolves imported interfaces transitively; the target’s own .def is found automatically. Explicit interface lists still work.

M2make --separate

M2make is the convenient transitive-interface resolver. Build it once:

cd tools/m2make
./build_m2.sh
cd ../..

Then, from the repository root:

tools/m2make/b_v3/M2make --separate --dialect iso \
    --m2bin ./compiler/M2 \
    --shim runtime/syslib/shim.c \
    -o /tmp/hello compiler/tests/hello.mod
/tmp/hello

M2make scans imports transitively, passes the ordered .def files to each M2 -c, writes gen_ssa/<Module>.o, and links. The one-shot default is still:

M2make -o /tmp/sep compiler/tests/sep_prog.mod

What the object model guarantees

  • Library objects have no main.
  • The program object has the only main.
  • Every object exports <Module>_init; the program calls imported inits in dependency order, then its own init.
  • Exported globals are export data; module procedures use <Module>__<name>; vtables use <Module>__<Class>__vt.

5. Dialect library folders

Libraries are split by dialect:

lib/pim/     classic PIM modules (InOut, RealInOut, …)
lib/iso/     ISO 10514-1 modules (TextIO, IOChan, Files, …)
lib/common/  shared Strings, Math, Storage, SysIO, CharClass
lib/gm2/     optional gm2 compatibility modules
runtime/syslib/  shared runtime/shim

Select one dialect per session:

M2make --dialect iso ... main.mod

or add the folders explicitly with -I lib/iso -I lib/common -I runtime/syslib. Do not mix lib/pim and lib/iso in one session.

6. Useful checks

cd compiler && ./run_tests.sh
cd .. && TMP="$PWD/.scratch/fixpoint" ./bootstrap/fixpoint.sh
tools/v3-corpus/corpus.sh

Current gates: suite 304/304, fixpoint OK (3,806,078 bytes), corpus 519/612 compile-OK, 0 crashes.

7. Current limits

  • M2 -I transitive interface scanning is implemented.
  • M2make --separate rebuilds only stale objects, relinks when an object, the shim, or the output changes, and treats a newer compiler binary as an ABI event. There is no content-based ABI version marker yet.
  • Generic instance objects are not emitted separately yet.
  • Per-object self-hosting is not yet a green fixpoint gate; the one-shot fixpoint remains the comparison.

For details, see docs/separate-compilation.md and docs/plan-separate-compilation.md.