Template
feat(ext): add builtin C/C++ language modules
This commit is contained in:
+161
@@ -0,0 +1,161 @@
|
||||
#ifndef ST_EXT_ABI_H
|
||||
#define ST_EXT_ABI_H
|
||||
|
||||
/*
|
||||
* The extension ABI (plan todo 13).
|
||||
*
|
||||
* Everything a language module can do goes through this header. Core
|
||||
* knows NOTHING language-specific: no compiler names, no CC/CFLAGS
|
||||
* variables, nothing C/C++-specific anywhere outside the module files
|
||||
* (lang_c.c / lang_cpp.c and their private shared header).
|
||||
*
|
||||
* Three generic facilities:
|
||||
* 1. a variable registry (st_registry_set_var / st_registry_get_var)
|
||||
* -- the configure generator (todo 16) substitutes from this BY
|
||||
* NAME; CC/CFLAGS/CXX/CXXFLAGS are registered here by the C/C++
|
||||
* modules, never hardcoded in core;
|
||||
* 2. a language registry (st_ext_register_language + detect);
|
||||
* 3. a check registry (st_ext_register_check).
|
||||
*
|
||||
* Lua-friendliness (todo 19/21): everything is a plain C function
|
||||
* pointer taking an explicitly passed `struct st_ext_ctx *`. There is
|
||||
* NO static state hidden inside the .c files -- a Lua binding only
|
||||
* needs to wrap these functions; the ctx is a userdata it passes back.
|
||||
* Borrowed results stay valid until the next mutation of the ctx (the
|
||||
* registries are linked lists, so node addresses are stable across
|
||||
* registrations).
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "error.h"
|
||||
|
||||
/* ---------------- generic variable registry ---------------- */
|
||||
|
||||
struct st_registry; /* opaque; owns name/value pairs in insertion order */
|
||||
|
||||
struct st_registry *st_registry_new(void);
|
||||
void st_registry_free(struct st_registry *r); /* NULL is a no-op */
|
||||
|
||||
/* Set or update a variable. `value == NULL` UNSETS (removes) it.
|
||||
* Returns NULL on success, or a heap st_error on allocation failure.
|
||||
* Values are duplicated. */
|
||||
struct st_error *st_registry_set_var(struct st_registry *r, const char *name,
|
||||
const char *value);
|
||||
|
||||
/* Borrowed value, or NULL when unset. */
|
||||
const char *st_registry_get_var(const struct st_registry *r,
|
||||
const char *name);
|
||||
|
||||
/* Ordered iteration (insertion order) for the substitution engine. */
|
||||
size_t st_registry_var_count(const struct st_registry *r);
|
||||
const char *st_registry_var_name(const struct st_registry *r, size_t i);
|
||||
const char *st_registry_var_value(const struct st_registry *r, size_t i);
|
||||
|
||||
/* ---------------- toolchain result ---------------- */
|
||||
|
||||
/* What a successful detection produced. `path` is the command as
|
||||
* invoked (env override value or the candidate that worked); `id` is
|
||||
* derived from the compiler's own `--version` output (vendor name, or
|
||||
* "unknown" when unrecognizable); `version` is likewise ("16.2.1") or
|
||||
* "" when unparsable. All three fields are heap-allocated and owned by
|
||||
* the ctx. */
|
||||
struct st_toolchain {
|
||||
char *path;
|
||||
char *id;
|
||||
char *version;
|
||||
};
|
||||
|
||||
/* ---------------- extension context ---------------- */
|
||||
|
||||
struct st_ext_ctx; /* opaque; owns languages, checks, variables */
|
||||
|
||||
/* Detects a language's toolchain. MUST fill `out` completely on
|
||||
* success (all three fields freshly strdup'd); on failure it returns a
|
||||
* heap st_error and may leave `out` partially filled -- the ctx frees
|
||||
* partial fields automatically. */
|
||||
typedef struct st_error *(*st_lang_detect_fn)(struct st_ext_ctx *ctx,
|
||||
void *module_ctx,
|
||||
struct st_toolchain *out);
|
||||
|
||||
/* A registered language. Borrowed view into the ctx; stable until the
|
||||
* ctx is freed. */
|
||||
struct st_language {
|
||||
const char *name; /* "c", "cxx", ... (owned by the ctx) */
|
||||
st_lang_detect_fn detect; /* how to find the toolchain */
|
||||
void *module_ctx; /* opaque module state, passed back */
|
||||
const char *const *var_names; /* NULL-terminated vars this language
|
||||
registers on detection (CC, CFLAGS…) */
|
||||
const struct st_toolchain *toolchain; /* filled on detect; NULL before */
|
||||
};
|
||||
|
||||
/* A registered check kind ("header" is universal; per-language kinds
|
||||
* arrive with todo 11/12). Borrowed view; stable until ctx free. */
|
||||
struct st_check {
|
||||
const char *language; /* which language this check applies to */
|
||||
const char *kind; /* "header", "function", ... */
|
||||
void *probe_spec; /* opaque module data; may be NULL for now */
|
||||
};
|
||||
|
||||
struct st_ext_ctx *st_ext_ctx_new(void); /* NULL on allocation failure */
|
||||
void st_ext_ctx_free(struct st_ext_ctx *ctx); /* NULL is a no-op */
|
||||
|
||||
/* The ctx's variable registry (same instance the language modules
|
||||
* write into; what todo 16 substitutes from). */
|
||||
struct st_registry *st_ext_var_registry(struct st_ext_ctx *ctx);
|
||||
|
||||
/* Registers a language. `var_names` is copied (NULL-terminated array).
|
||||
* Returns NULL on success, or an error for bad arguments / duplicates. */
|
||||
struct st_error *st_ext_register_language(struct st_ext_ctx *ctx,
|
||||
const char *name,
|
||||
st_lang_detect_fn detect,
|
||||
void *module_ctx,
|
||||
const char *const *var_names);
|
||||
|
||||
size_t st_ext_language_count(const struct st_ext_ctx *ctx);
|
||||
const struct st_language *st_ext_language(const struct st_ext_ctx *ctx,
|
||||
size_t i); /* NULL past end */
|
||||
const char *st_ext_language_name(const struct st_ext_ctx *ctx, size_t i);
|
||||
const struct st_toolchain *st_ext_language_toolchain(
|
||||
const struct st_ext_ctx *ctx, size_t i);
|
||||
const struct st_toolchain *st_ext_language_toolchain_named(
|
||||
const struct st_ext_ctx *ctx, const char *name);
|
||||
|
||||
/* Runs the registered detect fn for the named language and stores the
|
||||
* result. Returns NULL on success, or an error (unknown language /
|
||||
* detection failure -- e.g. no compiler found). */
|
||||
struct st_error *st_ext_detect_language(struct st_ext_ctx *ctx,
|
||||
const char *name);
|
||||
|
||||
/* Registers a check kind for a language. Duplicate (language, kind)
|
||||
* pairs are errors. Returns NULL on success. */
|
||||
struct st_error *st_ext_register_check(struct st_ext_ctx *ctx,
|
||||
const char *language,
|
||||
const char *kind, void *probe_spec);
|
||||
|
||||
size_t st_ext_check_count(const struct st_ext_ctx *ctx);
|
||||
const struct st_check *st_ext_check(const struct st_ext_ctx *ctx,
|
||||
size_t i); /* NULL past end */
|
||||
const char *st_ext_check_language(const struct st_ext_ctx *ctx, size_t i);
|
||||
const char *st_ext_check_kind(const struct st_ext_ctx *ctx, size_t i);
|
||||
void *st_ext_check_probe_spec(const struct st_ext_ctx *ctx, size_t i);
|
||||
|
||||
/* ---------------- builtin module registry ---------------- */
|
||||
|
||||
/* Runs the builtin module entry points (lang_c, lang_cpp). The modules
|
||||
* register themselves through the generic ABI above -- the table here
|
||||
* names entry points only; every compiler string lives in the modules.
|
||||
* Returns NULL on success. */
|
||||
struct st_error *st_ext_init_builtins(struct st_ext_ctx *ctx);
|
||||
|
||||
/* ---------------- process helper for module authors ---------------- */
|
||||
|
||||
/* Runs argv (NULL-terminated; argv[0] looked up via execvp on PATH)
|
||||
* and captures stdout+stderr into *out (malloc'd; caller frees; may be
|
||||
* NULL to discard) with *out_len. Returns the child's exit status
|
||||
* (0-255), or -1 when it could not be spawned (e.g. ENOENT) or was
|
||||
* killed by a signal. No timeout: intended for short commands like
|
||||
* `cc --version`. */
|
||||
int st_ext_run_capture(char *const argv[], char **out, size_t *out_len);
|
||||
|
||||
#endif /* ST_EXT_ABI_H */
|
||||
Reference in New Issue
Block a user