diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-13 03:54:49 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-13 03:54:49 +0000 |
| commit | e28cbb2efac9ed6e56cd9ab6eb1a3f16810d575a (patch) | |
| tree | a0402247ba92259f6b7f3a2ad2c8ed0ca8eab3de /tools | |
| parent | ba1b65f4a20566405c53d4ded90b483ec9aa7d09 (diff) | |
feat: embed a statically linked LLVM execution engine
Add EMBEDDED mode to run generated modules in-process without lli or PATH
lookup. Link LLVM and support archives plus the C++ runtime statically,
while retaining the system C runtime on Linux.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/driver/EmbeddedRunner.cc | 45 | ||||
| -rw-r--r-- | tools/driver/EmbeddedRunner.h | 5 | ||||
| -rw-r--r-- | tools/driver/main.cc | 12 |
3 files changed, 61 insertions, 1 deletions
diff --git a/tools/driver/EmbeddedRunner.cc b/tools/driver/EmbeddedRunner.cc new file mode 100644 index 0000000..81a2265 --- /dev/null +++ b/tools/driver/EmbeddedRunner.cc @@ -0,0 +1,45 @@ +#include "EmbeddedRunner.h" +#include "cps/CodeGen.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" +#include "llvm/Support/DynamicLibrary.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/TargetParser/Host.h" +#include "llvm/Transforms/Utils/Cloning.h" + +int runEmbedded(const cps::CodeGen &CG) { + if (llvm::InitializeNativeTarget() || llvm::InitializeNativeTargetAsmPrinter()) { + llvm::errs() << "Error: cannot initialize the embedded LLVM target\n"; + return 1; + } + std::string Error; + if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr, &Error)) { + llvm::errs() << "Error: cannot load process symbols: " << Error << "\n"; + return 1; + } + // Keep CodeGen's module and context alive while the engine owns its clone. + auto Module = llvm::CloneModule(CG.getModule()); + Module->setTargetTriple(llvm::sys::getProcessTriple()); + llvm::EngineBuilder Builder(std::move(Module)); + Builder.setEngineKind(llvm::EngineKind::JIT); + Builder.setErrorStr(&Error); + Builder.setMCJITMemoryManager(std::make_unique<llvm::SectionMemoryManager>()); + std::unique_ptr<llvm::ExecutionEngine> Engine(Builder.create()); + if (!Engine) { + llvm::errs() << "Error: cannot create the embedded LLVM engine: " << Error << "\n"; + return 1; + } + Engine->finalizeObject(); + if (Engine->hasError()) { + llvm::errs() << "Error: embedded LLVM execution failed: " << Engine->getErrorMessage() << "\n"; + return 1; + } + auto MainAddress = Engine->getFunctionAddress("main"); + if (!MainAddress) { + llvm::errs() << "Error: embedded LLVM could not resolve main\n"; + return 1; + } + auto Main = reinterpret_cast<int (*)()>(MainAddress); + return Main(); +} diff --git a/tools/driver/EmbeddedRunner.h b/tools/driver/EmbeddedRunner.h new file mode 100644 index 0000000..1651f4d --- /dev/null +++ b/tools/driver/EmbeddedRunner.h @@ -0,0 +1,5 @@ +#pragma once + +namespace cps { class CodeGen; } + +int runEmbedded(const cps::CodeGen &CG); diff --git a/tools/driver/main.cc b/tools/driver/main.cc index f5373a0..4df8562 100644 --- a/tools/driver/main.cc +++ b/tools/driver/main.cc @@ -1,6 +1,9 @@ #include "cps/Lexer.h" #include "cps/Parser.h" #include "cps/CodeGen.h" +#ifdef CPSC_RUN_EMBEDDED +#include "EmbeddedRunner.h" +#endif #include "llvm/ADT/SmallString.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" @@ -48,7 +51,9 @@ int main(int argc, char **argv) { llvm::errs() << "Error: no source file specified\n"; return 1; } +#ifdef CPSC_RUN_PATH std::string LliPath; +#endif if (Run) { #ifdef CPSC_RUN_PATH auto Lli = llvm::sys::findProgramByName("lli"); @@ -57,7 +62,7 @@ int main(int argc, char **argv) { return 1; } LliPath = *Lli; -#else +#elif defined(CPSC_RUN_NONE) llvm::errs() << "Error: -r is disabled in this build (CPSC_RUN_MODE=NONE)\n"; return 1; #endif @@ -93,6 +98,9 @@ int main(int argc, char **argv) { if (CG.hadError()) return 1; +#ifdef CPSC_RUN_EMBEDDED + if (Run && OutputPath.empty()) return runEmbedded(CG); +#endif std::error_code EC; int OutputFD; llvm::FileRemover TemporaryOutput; @@ -137,6 +145,8 @@ int main(int argc, char **argv) { return 1; } return Result; +#elif defined(CPSC_RUN_EMBEDDED) + return runEmbedded(CG); #else return 0; #endif |
