MEX Compiler
Using the MEX compiler
The MEX compiler (mex) is the tool that turns your .mex source files
into .vm bytecode — the format Maximus actually loads and runs. You write
human-readable code, the compiler translates it into instructions for the
Maximus VM, and your callers never see the difference. They just see
whatever cool thing you built.
If the compiler finds a problem — a missing semicolon, an undeclared variable, a function that doesn’t exist — it’ll tell you exactly where the problem is. Fix the line, recompile, try again. The cycle is fast.
Where It Lives
The compiler binary lands in build/bin/mex after you build Maximus. It’s
not something you install separately — if you’ve built the project, you’ve
got it.
MEX source files (.mex) and their compiled output (.vm) typically live
in resources/m/. The all-important header file max.mh — which every
MEX script needs to include — lives in resources/m/include/.
Compiling a Script
The simplest invocation is just:
cd resources/m
../../build/bin/mex myscript.mex
If everything compiles cleanly, you’ll get myscript.vm in the same
directory. No news is good news — the compiler is quiet on success.
If something’s wrong, you’ll get an error message with a line number:
myscript.mex 12: Undeclared identifier: 'naem'
The line number points you to the approximate location. Fix the typo, recompile, move on. The error messages are straightforward — they tell you what went wrong and where.
For Developers: compile-mex.sh
Note: This section is for people building Maximus from source — not sysops running a release. If you installed a release package, the
mexcompiler is already in your path and you compile scripts directly as shown above.
If you’re working in the source tree and want a quick way to compile a script, test it against a local build, and optionally stage it for a release package, there’s a convenience wrapper:
./scripts/compile-mex.sh myscript
This compiles resources/m/myscript.mex and copies the resulting .vm
to build/scripts/ — handy for testing against a local build without
manually shuffling files around.
Add --deploy to also push the files into the install tree for
packaging:
./scripts/compile-mex.sh myscript --deploy
That copies both the .mex source and the .vm bytecode to
resources/install_tree/scripts/, which is what ends up in a release
tarball.
What the Compiler Actually Does
Under the hood, the compiler:
- Preprocesses — handles
#includeand#definedirectives, expands macros, strips comments. - Parses — reads your source into an abstract syntax tree, checking syntax and types along the way.
- Generates bytecode — emits
.vminstructions that the Maximus VM can execute at runtime.
The .vm file is a compact binary. You don’t need to read it or edit it —
it’s purely machine food. If you want to change what the script does, you
edit the .mex source and recompile.
UTF-8 and CP437
Maximus displays in CP437 — the classic IBM PC character set that gives
you box-drawing characters, block elements, and all the symbols that make
a BBS look like a BBS. If you save your .mex file as UTF-8 (which most
modern editors do by default), those fancy characters won’t match what
the caller’s terminal expects, and you’ll get garbage on screen.
The MEX compiler handles this automatically. During compilation, any
UTF-8 multi-byte sequences in your source — in strings, char literals,
anywhere — are converted to their CP437 equivalents. You can type ═ in
your editor and the compiled .vm will contain the correct CP437 byte
(0xCD). No manual hex codes required.
If you’re saving your .mex file as CP437 already (the way you’d edit
an .ans file), the conversion isn’t needed. Use the -u flag to
disable it:
mex -u myscript.mex
Compiler Flags
| Flag | What It Does |
|---|---|
-d |
Debug output — show internal compiler state |
-o <file> |
Write output to a specific filename |
-h <size> |
Set heap size in bytes |
-s <size> |
Set stack size in bytes |
-q |
Quad output (dump intermediate representation, no .vm) |
-u |
Disable UTF-8 to CP437 conversion |
Include Files
Most MEX scripts start with at least one #include:
#include <max.mh>
This pulls in the standard Maximus header — type definitions, constants,
and declarations for all the built-in intrinsic functions (print(),
input(), usr.*, etc.). Without it, the compiler won’t know about any
of the Maximus-specific functions your script wants to call.
There are additional headers for specialized functionality:
| Header | What It Provides |
|---|---|
max.mh |
Core types, constants, and intrinsics (always needed) |
maxui.mh |
UI library — lightbar menus, cursor positioning, color attributes |
max_menu.mh |
Menu command dispatch (menu_cmd()) |
socket.mh |
HTTP requests (http_request()) |
json.mh |
JSON parsing and building (json_open(), json_get_str(), etc.) |
prm.mh |
System path and configuration access (prm_string()) |
input.mh |
Extended input functions and constants |
rand.mh |
Random number generation (srand(), rand()) |
intpad.mh |
Number-to-string formatting helpers |
Headers are searched in the include/ subdirectory relative to your
.mex file, which is why the standard layout puts max.mh in
resources/m/include/.
Next Steps
Now that you know how to compile, the next page explains what goes inside
a .mex file — the structure of a script, from includes to main() to
everything in between.