This is a short hands-on tour. It assumes a Linux shell, gcc/gm2,
Coco/R CR, and qbe as described in README.md.
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/.
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.
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.
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.
M2 -cFrom 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 --separateM2make 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
main.main.<Module>_init; the program calls imported inits in
dependency order, then its own init.export data; module procedures use
<Module>__<name>; vtables use <Module>__<Class>__vt.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.
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.
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.For details, see docs/separate-compilation.md and
docs/plan-separate-compilation.md.