Modules determine their own compatibility with the library

A module is built against the system-installed libdpm-core.so and is
responsible for being correct against it. Where it needs to act on the
version it is running under, dpm_core_version() reports that and the
module decides for itself.

dpm_module_core_min() is removed. It was a declaration handed to the
library to enforce on the module's behalf, and enforcement of that kind
belongs nowhere in a library that routes and hosts. The contract is now
three reserved symbols and load validation is two steps: the reserved
symbols resolve, and the version and description probes return
well-formed values.

compare_versions had no remaining caller and is removed; parse_version
stays for the well-formedness probe. The core_too_new fixture went with
the handshake it existed to exercise.
This commit is contained in:
2026-08-15 04:21:58 -04:00
parent 97b39cac6c
commit 17acad2b02
17 changed files with 101 additions and 185 deletions

View File

@@ -53,7 +53,7 @@ The context owns everything it hands out. Every string a caller receives stays v
**Acquiring a module.** `dpm_require` resolves a module by name, validates it completely, and returns a handle — or returns NULL, with `dpm_last_error` carrying the precise reason. Modules load at most once per context, and repeated calls return the same handle.
**Reading what the library saw.** `dpm_module_info_of` fills in a module's name, version, description, and minimum-library version. Those values are reported, and no conclusion is drawn from them.
**Reading what the library saw.** `dpm_module_info_of` fills in a module's name, version, and description. Those values are reported, and no conclusion is drawn from them.
**Calling into a module.** `dpm_execute` passes a command name and an argument vector to the module's entry point and returns its result. This is the only path into module code, and it is the same one the `dpm` binary takes.
@@ -104,17 +104,18 @@ The `ctx` a module needs is the one handed to it in its own entry point, so it r
*What a module author implements.*
A module is one `.so` in the module directory exporting four reserved symbols: a command entry point, its own version, a one-line description, and the minimum library version it supports. It includes `<dpm/core.h>` for those declarations and links `-ldpm-core`, and that is its entire build dependency.
A module is one `.so` in the module directory exporting three reserved symbols: a command entry point, its own version, and a one-line description. It includes `<dpm/core.h>` for those declarations and links `-ldpm-core`, and that is its entire build dependency.
The entry point receives the context that dispatched the call, the command name, and an argument vector, and returns an int. Everything a module offers the rest of the system is reachable through that one function, addressed by command name — which is what keeps a caller free of any compile-time knowledge of the module it is calling.
A module is built against the system-installed `libdpm-core.so` and is responsible for being correct against it. Where it needs to know what it is running on, `dpm_core_version()` reports the running version and the module acts on that itself.
## Load-time enforcement
libdpm-core.so validates a module completely before offering it to anyone:
1. Every reserved contract symbol resolves.
2. The module's minimum library version is not newer than the running library's own.
3. The version and description probes return well-formed values.
2. The version and description probes return well-formed values.
A module failing any step is refused with an itemized reason and its library handle closed. Validation is all-or-nothing: if a handle comes back, the contract already passed. Consumers never defend against partially valid modules, because they cannot receive one.
@@ -122,9 +123,11 @@ From the command line this shows up as a module missing from `--list-modules` wi
## Versioning
libdpm-core.so enforces exactly one version rule, the one where it is the host: each module states the oldest library version it supports, and a library older than that refuses to load the module, with a message naming the remedy.
Every version question belongs to the party that has to live with the answer.
Every other version question belongs to the consumer. A module that depends on another requires it, reads the version reported back, and decides for itself whether that version is suitable for the commands it intends to issue. libdpm-core.so reports what it saw and draws no conclusion from it, so a handle means the module is valid rather than that it suits any particular caller.
A module determines its own compatibility with the library it is running against. `dpm_core_version()` reports the running version, and the module proceeds or fails on its own judgement. A module is built against the system-installed `libdpm-core.so` and is responsible for being correct against it.
A module that depends on another module requires it, reads the version reported back, and decides for itself whether that version is suitable for the commands it intends to issue. libdpm-core.so reports what it saw and draws no conclusion from it, so a handle means the module is valid rather than that it suits any particular caller.
## Why it works this way
@@ -157,7 +160,7 @@ One repository per module, plus the libdpm-core.so repository. A module links li
- A harness that links the real libdpm-core.so and points the module path at build output plus fixture stubs exercises the real validation on a bare builder.
- Only final integration needs the whole system, and because alternate roots are first-class, it needs a directory rather than a virtual machine.
This repository's own fixtures are deliberately broken stub modules — missing symbols, a too-new minimum version, a malformed version — plus one known-good stub. Developing libdpm-core.so never requires a real package module to exist.
This repository's own fixtures are deliberately broken stub modules — missing symbols, a malformed version — plus one known-good stub. Developing libdpm-core.so never requires a real package module to exist.
## What this repository produces