feat(solver): implement SolverRegistry with plugin loading (#293)

Phase 1b of the pluggable solver system. Converts KCSolve from a
header-only INTERFACE target to a SHARED library and implements
the SolverRegistry with dynamic plugin discovery.

Changes:
- Add KCSolveGlobal.h export macro header (KCSolveExport)
- Move SolverRegistry method bodies from header to SolverRegistry.cpp
- Implement scan() with dlopen/LoadLibrary plugin loading
- Add scan_default_paths() for KCSOLVE_PLUGIN_PATH + system paths
- Plugin entry points: kcsolve_api_version() + kcsolve_create()
- API version checking (major version compatibility)
- Convert CMakeLists.txt from INTERFACE to SHARED library
- Link FreeCADBase (PRIVATE) for Console logging
- Link dl on POSIX for dynamic loading
- Fix -Wmissing-field-initializers warnings in IKCSolver.h defaults

The registry discovers plugins by scanning directories for shared
libraries that export the kcsolve C entry points. Plugins are
validated for API version compatibility before registration.
Manual registration via register_solver() remains available for
built-in solvers (e.g. OndselAdapter in Phase 1c).
This commit is contained in:
forbes
2026-02-19 16:07:37 -06:00
parent 47e6c14461
commit 76b91c6597
5 changed files with 445 additions and 75 deletions

View File

@@ -107,7 +107,7 @@ public:
virtual SolveResult drag_step(
const std::vector<SolveResult::PartResult>& /*drag_placements*/)
{
return SolveResult {SolveStatus::Success};
return SolveResult {SolveStatus::Success, {}, -1, {}, 0};
}
/// End an interactive drag session and finalize state.
@@ -123,7 +123,7 @@ public:
/// Default: delegates to solve() (ignoring simulation params).
virtual SolveResult run_kinematic(const SolveContext& /*ctx*/)
{
return SolveResult {SolveStatus::Failed};
return SolveResult {SolveStatus::Failed, {}, -1, {}, 0};
}
/// Number of simulation frames available after run_kinematic().
@@ -136,7 +136,7 @@ public:
/// @pre index < num_frames()
virtual SolveResult update_for_frame(std::size_t /*index*/)
{
return SolveResult {SolveStatus::Failed};
return SolveResult {SolveStatus::Failed, {}, -1, {}, 0};
}
// ── Diagnostics ────────────────────────────────────────────────