Eric Streit 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
..
tests 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
.gitignore 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
M2make.mod 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
M2makeC.def 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
M2makeOS.def 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
M2makeOS_gm2.mod 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
M2makeOS_v3.mod 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
README.md 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
build_gm2.sh 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
build_m2.sh 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад
m2make_os.c 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 2 недель назад

README.md

M2make

Build-order front-end for the M2 (V3) and GNU Modula-2 compilers. Given a main file (M2make main.mod), it follows IMPORT/FROM imports transitively, topologically sorts the modules, skips the build when the output is newer than every source, and otherwise invokes the selected compiler. Exit codes: 0 success (or nothing to do), 1 build failure (incl. import cycles), 2 usage error.

M2make [-n] [-v] [-c m2|gm2] [-I dir] [-o out]
       [--m2bin path] [--shim path] main.mod
  • -n: dry run (print the build order and the command only).
  • -v: verbose (external modules, build order).
  • -c m2|gm2: compiler to drive (default m2).
  • -I dir: extra module search directory (repeatable; the main file's own directory is always searched).
  • -o out: output binary name (default: the program module name as declared in the main file).
  • --m2bin path: M2 driver binary (default M2).
  • --shim path: C runtime shim for m2 mode (default shim.c).

m2 mode runs one session — <m2bin> <ordered .def/.mod files> then qbe then cc <image>.s <shim> -o <out> -lm — and gates on M2's Parsed correctly verdict (M2 exits 0 even on failure). gm2 mode recompiles only stale units (gm2 -fiso -c, objects land in the cwd as <Base>.o) and links the main file with the objects in topological order.

Building M2make itself

The portable core is M2make.mod + M2makeOS.def (plain ISO Modula-2 importing only FileIO and M2makeOS). Everything non-portable lives in the per-compiler layer:

  • m2make_os.c: stat/system/exit/text-input//proc argv helpers, with descriptor (_d, V3) and NUL-string (_s, gm2) variants.
  • gm2 side: M2makeC.def (FOR "C" binding) + M2makeOS_gm2.mod.
  • V3 side: M2makeOS_v3.mod (EXTERNAL binding).
./build_gm2.sh   # gm2 -fiso -> b_gm2/M2make
./build_m2.sh    # M2 session + qbe + cc -> b_v3/M2make
./tests/run_tests.sh

Source conventions (both compilers must accept the code)

M2make.mod is restricted to the intersection the two compilers actually implement (all learned the hard way, via probes):

  • No _ in identifiers, no 0C (use CHR(0)), empty parameter lists need a space (PROCEDURE P () : T).
  • Declaration before use (V3 is single-pass; gm2 tolerates forward references).
  • All strings NUL-terminated; own Len/Copy/Cmp/Cat on top of indexed access (the two FileIO string layers differ).
  • Flat 1D arrays only: V3 rejects a[i][j] loads (233) and miscompiles nested-array elements passed as open-array actuals (double load → segfault).
  • Never rely on AND/OR short-circuit: V3 evaluates both sides and traps out-of-range indexing, so guards must dominate accesses structurally.
  • LONGINT only via VAR out-parameters (V3 rejects LONGINT function results in calls); never print negative INTEGERs.
  • No ExitCode global (gm2 has none): all exits via M2makeOS.ExitNow. No SYSTEM/Storage in portable code.

Limitations

  • File names must match module names (exact or lowercase) with a .def/.mod extension; unknown modules are treated as external (system) libraries and skipped.
  • One main file per invocation; no spaces in paths; physical lines past ~2047 characters are split across reads.
  • m2 mode rebuilds the whole session image when any source is stale (M2's session model); per-file incrementality is a gm2 -mode feature.
  • gm2 -c drops <Base>.o in the cwd: two same-named modules in different directories collide.