Files
dpm-core-ng/docs/CONSUMERS.md
Christopher M. Punches 267529bee3 Drop the append-only versioning doctrine; document the version script
Module APIs and the library's exported ABI are versioned and retired
deliberately: a break ships as a new table version or a new symbol
version node, and consumers judge the versions they are handed.

Document src/libdpm-core.map — what it pins, what belongs in it, and
how a generation is retired — and declare DPM_CORE_0.1 as the shape
the next retired node takes.
2026-08-14 02:42:55 -04:00

5.0 KiB

Consuming libdpm-core

Programs link libdpm-core to operate the package manager directly: build systems, installers, image builders, system tooling, and foreign-language bindings all use the same library the dpm CLI is built on. A program holding a default context is operating the installed package manager itself — system configuration, system module path, system tree, system locking — identically to invoking the installed dpm command.

Compiling and linking

With libdpm-core installed, include the public header and link the library:

#include <dpm/core.h>
g++ myprog.cpp -ldpm-core

The header installs to the standard include path and the library to the standard lib path, so no additional flags are required. The interface is a C ABI: every function is extern "C", every type crossing the boundary is a C type, and state passes through opaque handles — callable from C, C++, or any language with C FFI.

The context

All work happens through a context handle:

dpm_ctx* ctx = dpm_open(NULL);
...
dpm_close(ctx);

dpm_open(NULL) reads the system configuration (/etc/dpm/conf.d/), resolves the system module path, and targets the root filesystem. dpm_close releases every handle the context issued; all pointers obtained through the context are invalid after it.

To point a context elsewhere, pass overrides — every field is optional:

dpm_open_overrides ov = {
    "/path/to/conf.d",    /* config_dir:  NULL = /etc/dpm/conf.d/      */
    "/path/to/modules",   /* module_path: NULL = config, then default  */
    "/path/to/root",      /* root: target root for package operations  */
    -1                    /* log_level: -1 = from config               */
};
dpm_ctx* ctx = dpm_open(&ov);

The root override is what makes chroot builds, image assembly, and sysroot management work: package operations act on the given tree instead of the running system. Multiple simultaneous contexts with different roots are legal.

Acquiring and using modules

dpm_require loads a module by name, on demand:

dpm_module* mod = dpm_require(ctx, "mymodule");

libdpm-core validates the module completely at load; a handle is returned only for a fully valid module. NULL means the module is absent or invalid — dpm_last_error(ctx) carries the precise reason. Modules load at most once per context; repeated calls return the same handle.

dpm_module_info_of reports what libdpm-core saw in the loaded module:

dpm_module_info info;
dpm_module_info_of(ctx, mod, &info);   /* info.name, .version, .description, .core_min */

Deciding whether that version is too new or too old is yours. libdpm-core applies no version criterion of its own — a handle means the module is valid, not that it suits you.

dpm_execute drives a module the way the CLI does — a command name and arguments:

int rc = dpm_execute(ctx, mod, "command", argc, argv);

dpm_get_api returns a module's typed function table for direct calls:

const mymodule_api_v1_s* api = (const mymodule_api_v1_s*)dpm_get_api(ctx, mod, "mymodule", 1);

The returned table was validated at load and is usable for the life of the context. NULL means the module does not provide that API at that version.

Enumerating modules

dpm_cursor* cur = dpm_list_modules(ctx);
dpm_module_info info;
while (dpm_cursor_next(cur, &info) == 0) {
    /* info.name, info.version, info.description, info.core_min */
}
dpm_cursor_free(cur);

The cursor covers every valid module in the module path; invalid candidates are excluded and logged.

Services

  • dpm_core_version() — the libdpm-core version; callable without a context.
  • dpm_module_info_of(ctx, mod, out) — the name, version, description, and minimum-libdpm-core version read from a loaded module.
  • dpm_config_get(ctx, module, section, key) — a value from a module's configuration namespace, or NULL if unset.
  • dpm_log(ctx, level, message) — writes to the context's configured log targets; levels are DPM_LOG_FATAL through DPM_LOG_DEBUG.
  • dpm_module_path(ctx) — the resolved module directory.
  • dpm_last_error(ctx) — a human-readable description of the most recent failure on the context, or NULL.

Ownership and errors

Strings returned by the library are owned by the context (or by the module that produced them) and remain valid until dpm_close; callers never free them. Functions returning int use 0 for success. Functions returning pointers use NULL for failure, with detail available from dpm_last_error.

Complete example

#include <dpm/core.h>
#include <stdio.h>

int main(void) {
    dpm_ctx* ctx = dpm_open(NULL);
    if (!ctx) {
        fprintf(stderr, "failed to initialize\n");
        return 1;
    }

    dpm_module* mod = dpm_require(ctx, "info");
    if (!mod) {
        fprintf(stderr, "%s\n", dpm_last_error(ctx));
        dpm_close(ctx);
        return 1;
    }

    int rc = dpm_execute(ctx, mod, "version", 0, NULL);

    dpm_close(ctx);
    return rc;
}