Template
104 lines
4.9 KiB
Lua
104 lines
4.9 KiB
Lua
-- ext_fortran.lua -- an example third-party language extension.
|
|
--
|
|
-- WHAT THIS MODULE DOES
|
|
--
|
|
-- Fortran is NOT built into stupidtools: the builtin modules are only the
|
|
-- C/C++ language pair (src/ext/lang_c.c / src/ext/lang_cpp.c). This file
|
|
-- shows how a third party adds another language -- and a language-specific
|
|
-- compiler-flag check -- without touching core or recompiling the binary.
|
|
--
|
|
-- HOW DISCOVERY LOADS IT
|
|
--
|
|
-- Any regular file whose name ends in ".lua" is discovered (src/ext/
|
|
-- discovery.h), from any of these sources, in this order:
|
|
--
|
|
-- 1. each --ext-dir DIR command-line flag (repeatable);
|
|
-- 2. each directory in the colon-separated STUPIDTOOLS_EXT env var;
|
|
-- 3. the per-user directory: $XDG_DATA_HOME/stupidtools/ext, falling
|
|
-- back to $HOME/.local/share/stupidtools/ext;
|
|
-- 4. the builtin directory ("builtin-ext", compile-time configured).
|
|
--
|
|
-- Each module is read into memory and run as ONE sandboxed Lua chunk with
|
|
-- the full file path as its chunkname (so diagnostics name file AND line).
|
|
-- Load order within a directory is bytewise-lexicographic, and a module
|
|
-- that fails to load aborts discovery (fail-fast). Try it:
|
|
--
|
|
-- cp examples/ext_fortran.lua /tmp/extdemo/
|
|
-- ./src/stupidtools --ext-dir /tmp/extdemo
|
|
--
|
|
-- or, equivalently:
|
|
--
|
|
-- STUPIDTOOLS_EXT=/tmp/extdemo ./src/stupidtools
|
|
--
|
|
-- Discovery prints one line per loaded module, built from the ACTUAL
|
|
-- registrations the module performed:
|
|
--
|
|
-- loaded extension: /tmp/extdemo/ext_fortran.lua - checks: 1
|
|
-- (fortran_compiler_flag) languages: 1 (fortran)
|
|
--
|
|
-- THE SANDBOX CONTRACT (what a module CANNOT do)
|
|
--
|
|
-- The runtime is deliberately stripped (src/ext/lua.h). Extension code
|
|
-- runs with:
|
|
-- * os.execute / os.exit / os.remove / os.rename PRESENT but raising
|
|
-- a "sandbox blocked:" error when called;
|
|
-- * dofile / loadfile / require / package / io / debug / coroutine
|
|
-- REMOVED (the globals are nil; their C libraries are not even
|
|
-- linked);
|
|
-- * only the base, table, string, a curated libm-free `math`, and the
|
|
-- hand-built `os` tables available, plus the `st` registration table.
|
|
--
|
|
-- So a module can declare capabilities but cannot execute programs, touch
|
|
-- the filesystem, or load other code. Violating the sandbox fails
|
|
-- discovery with a clear error. Note the probe SOURCE strings below are
|
|
-- inert text compiled by the host C toolchain, not executed here.
|
|
--
|
|
-- THE EXTENSION POINTS (the only API)
|
|
--
|
|
-- st.register_language(name [, spec-table])
|
|
-- Registers a language. v1 registers the NAME only; the optional
|
|
-- table is accepted (and must BE a table) for forward compatibility
|
|
-- -- no language detection or toolchain is wired to it yet (see
|
|
-- "v1 limitations" below).
|
|
--
|
|
-- st.register_check(name, { kind=..., source=..., link={...} })
|
|
-- Registers a custom check. `kind` is the probe MODE
|
|
-- ("compile" | "link" | "run"), `source` is the C snippet the probe
|
|
-- compiles, and `link` (optional) is a list of extra argv elements
|
|
-- for the link step. v1 custom checks are C snippets compiled with
|
|
-- the detected C toolchain (see "v1 limitations" below).
|
|
--
|
|
-- Both names must be non-empty strings free of NUL bytes and must not
|
|
-- collide with an already-registered name (builtin or earlier module).
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- 1. Register the language itself. "fortran" is arbitrary from core's
|
|
-- point of view -- any name works. The table argument is validated
|
|
-- (must be a table) but its contents are NOT consumed in v1.
|
|
-- ---------------------------------------------------------------------------
|
|
st.register_language("fortran", { kind = "compile" })
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
-- 2. Register a language-specific check. The name becomes a new check kind
|
|
-- a build file can reference (like the builtin "header" kind is). The
|
|
-- probe spec says: compile `source` with the C toolchain and require
|
|
-- the compile (and, with `link`, the link) to succeed.
|
|
--
|
|
-- The source below is deliberately trivially-true C and libm-free: it
|
|
-- links nothing, calls nothing, includes nothing -- a probe that must
|
|
-- pass even on the smallest toolchain. A realistic flag probe would
|
|
-- compile a C snippet with the flag in question and FAIL when the
|
|
-- compiler rejects the flag. The `-lfortran` link argument is inert
|
|
-- while the probe compiles (not links) but shows how extra link argv
|
|
-- is carried through for "link"/"run" mode probes.
|
|
-- ---------------------------------------------------------------------------
|
|
st.register_check("fortran_compiler_flag", {
|
|
kind = "compile",
|
|
source = "int main(void) { return 0; }",
|
|
link = { "-lfortran" },
|
|
})
|
|
|
|
-- That is the whole module. Everything else -- detection, probing, the
|
|
-- generated ./configure -- is core's job; an extension only declares
|
|
-- what languages and checks exist.
|