From 8ce8656de2ede82eacd91351b71f98e7fd7dd339 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Wed, 15 Jul 2026 10:14:43 -0500 Subject: [PATCH] epm: declare cross-module callees as extern fn so strict compilers accept generated C epm's sibling modules (registry/install/update) call functions defined in other modules and in the El runtime (config, read_installed, registry_find, manifest_deps, manifest_name, registry_latest_version, registry_token, install_vessel, installed_version) without importing them, so elc emits no C prototype for those calls. gcc<=13 treated the resulting implicit declarations as warnings; gcc>=14 and clang reject them as hard errors, which is why the "Build epm" CI step fails and blocks the whole dev/stage pipeline. Add `extern fn` forward declarations -- El's own separate-compilation mechanism -- for each cross-module callee at the top of registry/install/update. This gives elc the correct C prototype in every generated translation unit, so the calls compile cleanly and still resolve at link time. Simply suppressing -Wimplicit-function-declaration would be unsafe: an implicit int return truncates the 64-bit pointer returns of config/registry_find into a latent crash, so declaring the true signatures is the correct fix. Localized to epm; touches neither elc nor the runtime. --- epm/src/install.el | 10 ++++++++++ epm/src/registry.el | 9 +++++++++ epm/src/update.el | 9 +++++++++ 3 files changed, 28 insertions(+) diff --git a/epm/src/install.el b/epm/src/install.el index 882fc90..1561cf8 100644 --- a/epm/src/install.el +++ b/epm/src/install.el @@ -17,6 +17,16 @@ // 4. Append dep to order after all its transitive deps // 5. Deduplicate: skip already-ordered vessels +// ── Cross-module forward declarations ───────────────────────────────────────── +// Defined in sibling epm modules; resolved at link time. The `extern fn` decls +// give elc the C prototypes so generated install.c compiles cleanly under strict +// compilers (gcc>=14 / clang) that reject implicit function declarations. +extern fn manifest_name(src: String) -> String // manifest.el +extern fn manifest_deps(src: String) -> String // manifest.el +extern fn registry_token() -> String // registry.el +extern fn registry_find(name: String, version: String) -> String // registry.el +extern fn registry_latest_version(name: String) -> String // registry.el + // ── Install paths ───────────────────────────────────────────────────────────── // packages_dir returns the root directory for installed vessels. diff --git a/epm/src/registry.el b/epm/src/registry.el index 8e1b2b5..d6f9730 100644 --- a/epm/src/registry.el +++ b/epm/src/registry.el @@ -14,6 +14,15 @@ // EPM_REGISTRY_ORG — org name that hosts vessel repos (default: neuron-technologies) // EPM_TOKEN — Gitea personal access token (required for publish) +// ── Cross-module forward declarations ───────────────────────────────────────── +// These symbols are defined in sibling epm modules or the El runtime and are +// resolved at link time. The `extern fn` decls give elc the C prototype so the +// generated registry.c compiles cleanly under strict compilers (gcc>=14 / clang) +// that reject implicit function declarations. Signature arity must match the +// definition; return/param types are informational (all lower to el_val_t). +extern fn config(key: String) -> String // El runtime builtin +extern fn read_installed() -> String // install.el + // ── Config helpers ──────────────────────────────────────────────────────────── // registry_api_url returns the Gitea API base URL with no trailing slash. diff --git a/epm/src/update.el b/epm/src/update.el index 42f60a5..3804ab2 100644 --- a/epm/src/update.el +++ b/epm/src/update.el @@ -6,6 +6,15 @@ // Depends on: registry.el (registry_latest_version, registry_find), // install.el (read_installed, install_vessel, installed_version) +// ── Cross-module forward declarations ───────────────────────────────────────── +// Defined in sibling epm modules; resolved at link time. The `extern fn` decls +// give elc the C prototypes so generated update.c compiles cleanly under strict +// compilers (gcc>=14 / clang) that reject implicit function declarations. +extern fn read_installed() -> String // install.el +extern fn installed_version(name: String) -> String // install.el +extern fn install_vessel(name: String, version: String) -> Bool // install.el +extern fn registry_latest_version(name: String) -> String // registry.el + // ── Semver helpers ──────────────────────────────────────────────────────────── // semver_part extracts the Nth dot-separated component from a semver string.