Eric Streit 0031cfa65b m2make: adapt to the current compiler (short-circuit, --extra, dogfood build) hai 1 semana
..
tests 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 hai 2 semanas
.gitignore 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 hai 2 semanas
M2make.mod 0031cfa65b m2make: adapt to the current compiler (short-circuit, --extra, dogfood build) hai 1 semana
M2makeC.def 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 hai 2 semanas
M2makeOS.def 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 hai 2 semanas
M2makeOS_gm2.mod 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 hai 2 semanas
M2makeOS_v3.mod 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 hai 2 semanas
README.md 0031cfa65b m2make: adapt to the current compiler (short-circuit, --extra, dogfood build) hai 1 semana
build_gm2.sh 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 hai 2 semanas
build_m2.sh 0031cfa65b m2make: adapt to the current compiler (short-circuit, --extra, dogfood build) hai 1 semana
m2make_os.c 2f243ed497 m2make: build-order front-end for M2/gm2 (topo-sort imports, incremental build); FileIO argv starts at 1 hai 2 semanas

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] [--extra 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).
  • --extra path: extra C file linked in m2 mode (after the shim; e.g. a tool's own m2make_os.c).

m2 mode runs one session — <m2bin> <ordered .def/.mod files> then qbe then cc <image>.s <shim> [<extra>] -o <out> -lm — and gates on M2's Parsed correctly verdict (M2 exits 0 even on failure). Modules the session needs but that are not named on the command line are resolved from the -I directories (so -I runtime/syslib finds SysShim/FileIO): the same shape the compiler's own bootstrap/fixpoint.sh uses. 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    # -> b_v3/M2make  (bootstraps, then dogfoods)
./tests/run_tests.sh

build_m2.sh builds M2make with the V3 compiler. If a previous b_v3/M2make exists it drives the build itself (M2make -c m2 --extra m2make_os.c -I runtime/syslib …); on the first run (no driver yet) the session is spelled out by hand. Re-running it is therefore a small self-host check for the tool.

Source conventions (both compilers must accept the code)

M2make.mod targets the intersection of GNU Modula-2 and V3. The list below was re-probed against the current compilers; several old restrictions are gone (both V3 and gm2 now accept them):

  • No _ in identifiers (still required by V3's classic lexer); 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).
  • AND/OR short-circuit in both compilers now, so ordinary index guards ((i <= HIGH(s)) AND (s[i] # …)) are safe. (The helpers still compute Len up front where that reads more clearly.)
  • Flat 1D arrays are used throughout; V3 now handles nested arrays and nested-element open-array actuals, so this is a style choice rather than a restriction.
  • LONGINT results from calls compile, but VAL(INTEGER, longval) (64→32) is still rejected by V3, so LONGINT crosses the M2makeOS boundary only as a VAR out-parameter; negative INTEGER printing is still avoided.
  • 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.