1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
|
# MNV — Building
## Build System Overview
MNV ships with **two** fully functional build systems:
| System | Entry point | Status |
|---|---|---|
| CMake | `CMakeLists.txt` (project root) | **Primary** — recommended for new builds |
| Autoconf + Make | `src/configure` / `src/Makefile` | Legacy — widest platform coverage |
This document focuses on the CMake build but covers the Autoconf path as well.
---
## Prerequisites
### Compiler
MNV is written in C99. Any modern C compiler works:
```cmake
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED OFF)
```
Tested compilers:
- GCC 7+
- Clang 7+
- MSVC 2015+ (via `Make_mvc.mak` or CMake generators)
- MinGW / MSYS2
### Required tools
| Tool | Minimum version |
|---|---|
| CMake | 3.15 |
| make / ninja | any recent version |
| pkg-config | recommended (for GTK, Wayland, libcanberra, libsodium) |
### Required libraries
Only a terminal library is strictly required:
- **ncurses** (preferred) or **termcap** / **tinfo**
Without it the build emits a warning:
```
No terminal library found (ncurses/curses/termcap). Build may fail.
```
### Optional libraries
| Library | CMake option | Feature |
|---|---|---|
| GTK 3 | `MNV_GUI=gtk3` | Graphical editor |
| GTK 2 | `MNV_GUI=gtk2` | Graphical editor (older) |
| Motif | `MNV_GUI=motif` | Motif-based GUI |
| X11 + Xt | auto-detected | X clipboard, client-server |
| Wayland + wayland-scanner | auto-detected | Wayland clipboard |
| libcanberra | `MNV_SOUND=ON` | Sound playback |
| libsodium | `MNV_SODIUM=ON` | XChaCha20 encryption |
| libacl | `MNV_ACL=ON` | POSIX ACL preservation |
| libgpm | `MNV_GPM=ON` | GPM mouse in console |
| Lua | `MNV_LUA=ON` | Lua scripting |
| Python 3 | `MNV_PYTHON3=ON` | Python 3 scripting |
| Ruby | `MNV_RUBY=ON` | Ruby scripting |
| Perl | `MNV_PERL=ON` | Perl scripting |
| Tcl | `MNV_TCL=ON` | Tcl scripting |
| MzScheme / Racket | `MNV_MZSCHEME=ON` | Scheme scripting |
### Ubuntu / Debian quick install
```bash
# Minimal build
sudo apt install git make cmake gcc libncurses-dev
# With X clipboard
sudo apt install libxt-dev
# With GTK 3 GUI
sudo apt install libgtk-3-dev
# With Wayland clipboard
sudo apt install libwayland-dev wayland-protocols wayland-scanner
# Optional interpreters
sudo apt install liblua5.4-dev libpython3-dev ruby-dev libperl-dev tcl-dev
# Optional features
sudo apt install libcanberra-dev libsodium-dev libacl1-dev libgpm-dev
```
---
## CMake Build — Quick Start
```bash
cd mnv
mkdir build && cd build
cmake ..
cmake --build . -j$(nproc)
ctest # run tests
sudo cmake --install . # install to /usr/local
```
---
## CMake Configuration Options
### Feature Level
```cmake
set(MNV_FEATURE "huge" CACHE STRING "Feature level: tiny, normal, huge")
```
| Level | Description |
|---|---|
| `tiny` | Minimal — no `+eval`, no terminal, no channels |
| `normal` | Default selection of features; includes `+eval` |
| `huge` | Everything: terminal, channels, NetBeans, cscope, beval, … |
On Unix/macOS/Windows the default is `huge`.
The CMake build translates the feature level into `config.h` defines consumed
by `feature.h`:
```cmake
if(MNV_FEATURE STREQUAL "huge")
set(FEAT_HUGE 1)
set(FEAT_EVAL 1)
set(FEAT_BEVAL 1)
set(FEAT_CSCOPE 1)
set(FEAT_NETBEANS_INTG 1)
set(FEAT_JOB_CHANNEL 1)
set(FEAT_TERMINAL 1)
set(FEAT_IPV6 1)
...
endif()
```
### GUI Selection
```cmake
set(MNV_GUI "auto" CACHE STRING "GUI toolkit: auto, gtk3, gtk2, motif, none")
```
- `auto` — tries GTK 3 → GTK 2 → Motif → none.
- `gtk3` / `gtk2` / `motif` — explicitly request one toolkit.
- `none` — terminal-only build.
When a GUI is found, these variables are set and the corresponding source files
are added:
```cmake
# GTK 3 example
set(GUI_SRC gui.c gui_gtk.c gui_gtk_f.c gui_gtk_x11.c gui_beval.c)
```
### Boolean Options
| Option | Default | Effect |
|---|---|---|
| `MNV_TERMINAL` | `ON` | Built-in terminal emulator (requires channels) |
| `MNV_CHANNEL` | `ON` | Job/channel support |
| `MNV_NETBEANS` | `ON` | NetBeans interface |
| `MNV_CSCOPE` | `ON` | Cscope integration |
| `MNV_SOUND` | `ON` | Sound via libcanberra |
| `MNV_ACL` | `ON` | POSIX ACL support |
| `MNV_GPM` | `ON` | GPM mouse |
| `MNV_SODIUM` | `ON` | libsodium encryption |
| `MNV_MULTIBYTE` | `ON` | Multi-byte character support |
| `MNV_XIM` | `ON` | X Input Method |
### Language Interpreters
All interpreters default to `OFF` and can be loaded dynamically:
```cmake
option(MNV_LUA "Enable Lua interpreter" OFF)
option(MNV_LUA_DYNAMIC "Load Lua dynamically" ON)
option(MNV_PERL "Enable Perl interpreter" OFF)
option(MNV_PERL_DYNAMIC "Load Perl dynamically" ON)
option(MNV_PYTHON3 "Enable Python 3 interpreter" OFF)
option(MNV_PYTHON3_DYNAMIC "Load Python 3 dynamically" ON)
option(MNV_RUBY "Enable Ruby interpreter" OFF)
option(MNV_RUBY_DYNAMIC "Load Ruby dynamically" ON)
option(MNV_TCL "Enable Tcl interpreter" OFF)
option(MNV_TCL_DYNAMIC "Load Tcl dynamically" ON)
option(MNV_MZSCHEME "Enable MzScheme/Racket" OFF)
```
Dynamic loading means MNV `dlopen()`s the interpreter shared library at
runtime instead of linking against it at build time. The library name is
auto-detected:
```cmake
foreach(_lua_lib ${LUA_LIBRARIES})
if(_lua_lib MATCHES "\\.(so|dylib)")
get_filename_component(DYNAMIC_LUA_DLL "${_lua_realpath}" NAME)
break()
endif()
endforeach()
```
### Development Options
```cmake
option(MNV_DEBUG "Enable debug build" OFF)
option(MNV_PROFILE "Enable profiling" OFF)
option(MNV_SANITIZE "Enable address/undefined sanitizers" OFF)
option(MNV_LEAK_CHECK "Enable EXITFREE for leak checking" OFF)
option(MNV_BUILD_TESTS "Build and enable tests" ON)
```
When `MNV_DEBUG` is on:
```cmake
add_compile_options(-g -DDEBUG)
```
When `MNV_SANITIZE` is on:
```cmake
add_compile_options(
-fsanitize=address
-fsanitize=undefined
-fsanitize-recover=all
-fno-omit-frame-pointer
)
add_link_options(
-fsanitize=address
-fsanitize=undefined
)
```
When `MNV_LEAK_CHECK` is on, the `EXITFREE` define ensures all memory is freed
at exit so leak checkers can report accurately.
### Compiled-by string
```cmake
set(MNV_COMPILED_BY "" CACHE STRING "Name of the person compiling MNV")
```
Embedded into `auto/pathdef.c` and shown in `:version` output.
---
## CMake Presets
`CMakePresets.json` defines ready-made configurations. Use them with:
```bash
cmake --preset <name>
cmake --build --preset <name>
```
### Available presets
| Preset | Feature | GUI | Interpreters | Debug |
|---|---|---|---|---|
| `default` | huge | auto | none | no |
| `minimal` | tiny | none | none | no |
| `normal` | normal | none | none | no |
| `nogui` | huge | none | none | no |
| `gtk3` | huge | gtk3 | none | no |
| `all-interp` | huge | auto | all (dynamic) | yes |
| `all-interp-static` | huge | auto | all (static) | yes |
| `lua-only` | huge | none | Lua (dynamic) | yes |
| `python3-only` | huge | none | Python3 (dynamic) | yes |
| `ruby-only` | huge | none | Ruby (dynamic) | yes |
| `perl-only` | huge | none | Perl (dynamic) | yes |
| `tcl-only` | huge | none | Tcl (dynamic) | yes |
| `sanitize` | huge | none | none | ASan+UBSan |
| `profile` | huge | none | none | gprof |
Presets inherit from hidden base presets:
- **`base`** — sets `CMAKE_EXPORT_COMPILE_COMMANDS=ON`, `MNV_BUILD_TESTS=ON`,
output to `build/${presetName}`.
- **`dev-base`** — inherits `base`, adds `MNV_DEBUG=ON`, `MNV_LEAK_CHECK=ON`.
### Example: debug build with all interpreters
```bash
cmake --preset all-interp
cmake --build build/all-interp -j$(nproc)
cd build/all-interp && ctest
```
### Example: sanitiser build
```bash
cmake --preset sanitize
cmake --build build/sanitize -j$(nproc)
cd build/sanitize && ctest
```
---
## System Detection
The CMake build performs extensive detection of headers, functions, and types.
### Header checks
```cmake
check_include_file(stdint.h HAVE_STDINT_H)
check_include_file(unistd.h HAVE_UNISTD_H)
check_include_file(termios.h HAVE_TERMIOS_H)
check_include_file(sys/select.h HAVE_SYS_SELECT_H)
check_include_file(dlfcn.h HAVE_DLFCN_H)
check_include_file(pthread.h HAVE_PTHREAD_H)
# ... 40+ more
```
### Function checks
```cmake
check_function_exists(fchdir HAVE_FCHDIR)
check_function_exists(getcwd HAVE_GETCWD)
check_function_exists(select HAVE_SELECT)
check_function_exists(sigaction HAVE_SIGACTION)
check_function_exists(dlopen HAVE_DLOPEN)
# ... 50+ more
```
### Type-size checks
```cmake
check_type_size(int MNV_SIZEOF_INT)
check_type_size(long MNV_SIZEOF_LONG)
check_type_size(off_t SIZEOF_OFF_T)
check_type_size(time_t SIZEOF_TIME_T)
check_type_size(wchar_t SIZEOF_WCHAR_T)
```
MNV requires `sizeof(int) >= 4`:
```c
#if MNV_SIZEOF_INT < 4 && !defined(PROTO)
# error MNV only works with 32 bit int or larger
#endif
```
### Compile tests
```cmake
# __attribute__((unused))
check_c_source_compiles("
int x __attribute__((unused));
int main() { return 0; }
" HAVE_ATTRIBUTE_UNUSED)
# struct stat.st_blksize
check_c_source_compiles("
#include <sys/stat.h>
int main() { struct stat s; s.st_blksize = 0; return 0; }
" HAVE_ST_BLKSIZE)
# sockaddr_un
check_c_source_compiles("
#include <sys/un.h>
int main() { struct sockaddr_un s; return 0; }
" HAVE_SOCKADDR_UN)
```
---
## Generated Files
### `auto/config.h`
Generated from `cmake/config.h.cmake` by `configure_file()`. Contains all
`HAVE_*`, `FEAT_*`, `SIZEOF_*`, and `DYNAMIC_*` defines.
### `auto/pathdef.c`
Generated from `cmake/pathdef.c.cmake`. Embeds:
- Compiler used (`MNV_ALL_CFLAGS`)
- Linker used (`MNV_ALL_LFLAGS`)
- Compiled-by info (`MNV_COMPILED_USER@MNV_COMPILED_SYS`)
- Install paths for runtime files
### `auto/osdef.h`
On modern systems this is a stub:
```c
/* osdef.h - generated by CMake */
/* On modern systems most definitions come from system headers */
```
The Autoconf build generates a real `osdef.h` from `osdef.sh`.
### Wayland protocol files
When Wayland is detected and `wayland-scanner` is available, the build
generates `.c` and `.h` files for each supported protocol:
```cmake
set(WAYLAND_PROTOCOLS
ext-data-control-v1
primary-selection-unstable-v1
wlr-data-control-unstable-v1
xdg-shell
)
```
Protocol XMLs must exist under `src/auto/wayland/protocols/`.
---
## Build Targets
### `mnv` (main executable)
All `MNV_CORE_SRC` files + `xdiff` object library → single binary.
```cmake
add_executable(mnv ${MNV_CORE_SRC} $<TARGET_OBJECTS:xdiff>)
```
### `xdiff` (object library)
```cmake
add_library(xdiff OBJECT
src/xdiff/xdiffi.c
src/xdiff/xemit.c
src/xdiff/xprepare.c
src/xdiff/xutils.c
src/xdiff/xhistogram.c
src/xdiff/xpatience.c
)
```
### `vterm` (static library)
Built when `FEAT_TERMINAL` is enabled:
```cmake
add_subdirectory(src/libvterm)
```
### `xxd` (executable)
Hex dump utility:
```cmake
add_subdirectory(src/xxd)
```
### Unit tests
Four test executables built by `mnv_add_unit_test()`:
```cmake
mnv_add_unit_test(json_test json.c json_test.c)
mnv_add_unit_test(kword_test charset.c kword_test.c)
mnv_add_unit_test(memfile_test memfile.c memfile_test.c)
mnv_add_unit_test(message_test message.c message_test.c)
```
Each replaces `main.c` **and** the file under test with its `_test.c` variant.
---
## Testing
### Running all tests
```bash
cd build && ctest
```
### Specific test categories
```bash
ctest -L scripts # Script tests (src/testdir/)
ctest -L indent # Indent tests (runtime/indent/)
ctest -L syntax # Syntax tests (runtime/syntax/)
ctest -R json_test # Just the JSON unit test
```
### Test environment
Tests run with explicit environment to avoid GUI interference:
```cmake
set_tests_properties(${TEST_NAME} PROPERTIES
TIMEOUT 120
ENVIRONMENT "DISPLAY=;WAYLAND_DISPLAY="
)
```
Script tests use:
```cmake
MNVPROG=$<TARGET_FILE:mnv>
MNVRUNTIME=${CMAKE_CURRENT_SOURCE_DIR}/runtime
LINES=24
COLUMNS=80
```
---
## Installation
```bash
sudo cmake --install build
# Default prefix: /usr/local
```
### What gets installed
| Component | Destination |
|---|---|
| `mnv` binary | `${CMAKE_INSTALL_BINDIR}` (e.g. `/usr/local/bin`) |
| Symlinks (ex, view, vi, vim, rmnv, rview, mnvdiff) | same |
| GUI symlinks (gmnv, gview, gvi, gvim, …) | same (if GUI) |
| Runtime files | `${CMAKE_INSTALL_DATADIR}/mnv/mnv100/` |
| Man pages | `${CMAKE_INSTALL_MANDIR}/man1/` |
| Desktop files | `${CMAKE_INSTALL_DATADIR}/applications/` (if GUI) |
| Icons | `${CMAKE_INSTALL_DATADIR}/icons/hicolor/.../` (if GUI) |
### Runtime subdirectories installed
```cmake
set(RUNTIME_SUBDIRS
colors compiler doc ftplugin import indent keymap
lang macros pack plugin print spell syntax tools
tutor autoload
)
```
### Individual runtime scripts installed
```cmake
set(RUNTIME_SCRIPTS
defaults.mnv emnv.mnv filetype.mnv ftoff.mnv ftplugin.mnv
ftplugof.mnv indent.mnv indoff.mnv menu.mnv mswin.mnv
optwin.mnv bugreport.mnv scripts.mnv synmenu.mnv delmenu.mnv
)
```
---
## Legacy Autoconf Build
```bash
cd mnv/src
./configure --with-features=huge --enable-gui=gtk3
make -j$(nproc)
make test
sudo make install
```
Key configure flags:
| Flag | Effect |
|---|---|
| `--with-features=tiny\|normal\|huge` | Feature level |
| `--enable-gui=gtk3\|gtk2\|motif\|no` | GUI selection |
| `--enable-luainterp=dynamic` | Lua support |
| `--enable-python3interp=dynamic` | Python 3 support |
| `--enable-rubyinterp=dynamic` | Ruby support |
| `--enable-perlinterp=dynamic` | Perl support |
| `--enable-tclinterp=dynamic` | Tcl support |
Platform-specific Make files:
| File | Platform |
|---|---|
| `Make_cyg.mak` | Cygwin |
| `Make_cyg_ming.mak` | Cygwin + MinGW |
| `Make_ming.mak` | MinGW |
| `Make_mvc.mak` | MSVC |
| `Make_ami.mak` | Amiga |
| `Make_vms.mms` | OpenVMS (MMS/MMK) |
---
## Build Summary
At the end of configuration, CMake prints a summary:
```
=== MNV 10.0 Build Configuration ===
Feature level: huge
GUI: auto (found: TRUE)
Terminal: 1
Channel/Job: 1
X11: 1
Wayland: 1
Terminal lib: /usr/lib/x86_64-linux-gnu/libncurses.so
Sound: canberra
Encryption: libsodium
Lua: 5.4.6
Python 3: 3.12.3
Install prefix: /usr/local
Compiled by: user@hostname
=============================================
```
---
## Cross-Compilation
See `src/INSTALLx.txt` for cross-compile instructions. With CMake, use a
toolchain file:
```bash
cmake .. -DCMAKE_TOOLCHAIN_FILE=/path/to/toolchain.cmake
```
The legacy build uses `toolchain-mingw32.cmake` (from `cmark/`) as a reference.
---
## Troubleshooting
| Problem | Solution |
|---|---|
| "No terminal library found" | Install `libncurses-dev` (Debian/Ubuntu) or `ncurses-devel` (RHEL/Fedora) |
| GUI not detected | Install `libgtk-3-dev` and ensure `pkg-config` is available |
| `configure did not run properly` | Autoconf build: check `auto/config.log` |
| Perl `xsubpp` not found | Install `perl-ExtUtils-MakeMaker` or the full Perl dev package |
| Wayland protocols missing | Ensure protocol XML files exist in `src/auto/wayland/protocols/` |
| `MNV only works with 32 bit int or larger` | Your platform has 16-bit int — unsupported |
---
*This document describes MNV 10.0 as of build 287 (2026-04-03).*
|