aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-22 03:41:04 +0000
committer_ov4 <ov4@ov4.org>2026-10-22 03:58:36 +0000
commiteba981b4f515010f8f6e9602c563d2074d8bd915 (patch)
tree632e5b72446e5fdfa8b575e19fd6d01ea25598de
parent6f11b59dff6ddc84c20fc1847a42344bfdddf066 (diff)
refactor(driver): move PATH-mode lli runner into PathRunner
PathRunner.cc holds the lli lookup, LLVM 23 version check and lli execution, and is built only with CPSC_RUN_MODE=PATH like EmbeddedRunner.cc is for EMBEDDED. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--AGENTS/ARCH/DRIVER.md5
-rw-r--r--AGENTS/ARCH/LAYOUT.md1
-rw-r--r--CMakeLists.txt2
-rw-r--r--tools/driver/PathRunner.cc83
-rw-r--r--tools/driver/PathRunner.h13
-rw-r--r--tools/driver/main.cc84
6 files changed, 105 insertions, 83 deletions
diff --git a/AGENTS/ARCH/DRIVER.md b/AGENTS/ARCH/DRIVER.md
index 1b37d01..ef739b2 100644
--- a/AGENTS/ARCH/DRIVER.md
+++ b/AGENTS/ARCH/DRIVER.md
@@ -47,8 +47,9 @@ style is in [CONVENTIONS/SYMBOLS_AND_ERRORS.md](../CONVENTIONS/SYMBOLS_AND_ERROR
than grepping stderr.
- Successful compilation overwrites the output, but paths aliasing any input source
(including symlinks/hard links) are rejected.
-- In PATH mode, `-r` executes PATH's `lli` using LLVM Support process APIs, with
- inherited stdin/stdout/stderr and no shell. Missing lli is rejected before
+- In PATH mode (`tools/driver/PathRunner.cc`, built only in that mode), `-r`
+ executes PATH's `lli` using LLVM Support process APIs, with inherited
+ stdin/stdout/stderr and no shell. Missing lli is rejected before
compiling or writing output. The selected `lli --version` must identify LLVM 23
and succeed within five seconds; other or unrecognized versions fail before
source compilation. Without `-r`, no external tools are checked; clang/clang++
diff --git a/AGENTS/ARCH/LAYOUT.md b/AGENTS/ARCH/LAYOUT.md
index 4abe414..6c70d3b 100644
--- a/AGENTS/ARCH/LAYOUT.md
+++ b/AGENTS/ARCH/LAYOUT.md
@@ -28,6 +28,7 @@
| `CMakeLists.txt` | 3 static libs (CPSLexer, CPSParser, CPSCodeGen) + `cpsc`. **New .cc files must be added to the source lists here** |
| `tools/driver/NativeCompiler.cc`, `cmake/NativeCompiler.cmake` | Host object generation, embedded Clang/LLD linking and compressed link resources |
| `tools/driver/EmbeddedRunner.cc`, `tools/driver/MinGWJIT.cc`, `cmake/EmbeddedLLVM.cmake` | EMBEDDED-only LLJIT/JITLink runner and MinGW COFF/SEH support; static support-library selection for all modes |
+| `tools/driver/PathRunner.cc` | PATH-only `-r` runner: lli lookup, LLVM 23 version check and lli execution |
| `cmake/LocalDependencies.cmake`, `cmake/*Packages.cmake` | Local package extraction and platform relocation |
| `cmake/DependencyPaths.cmake`, `cmake/FindDependency.cmake` | Shared local paths and local-first/system-fallback lookup |
| `cmake/BuildTools.cmake`, `cmake/LLVMDependencies.cmake` | Compiler/build tool selection and LLVM dependency discovery |
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3dea04e..32e6c1b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -101,6 +101,8 @@ if(CPSC_RUN_MODE STREQUAL "EMBEDDED")
target_sources(cpsc PRIVATE
tools/driver/EmbeddedRunner.cc
tools/driver/MinGWJIT.cc)
+elseif(CPSC_RUN_MODE STREQUAL "PATH")
+ target_sources(cpsc PRIVATE tools/driver/PathRunner.cc)
endif()
if(MINGW)
target_link_options(cpsc PRIVATE -static)
diff --git a/tools/driver/PathRunner.cc b/tools/driver/PathRunner.cc
new file mode 100644
index 0000000..01d8478
--- /dev/null
+++ b/tools/driver/PathRunner.cc
@@ -0,0 +1,83 @@
+#include "PathRunner.h"
+#include "cps/Diagnostics.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FileUtilities.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/Regex.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace {
+
+bool checkLliVersion(llvm::StringRef LliPath) {
+ llvm::SmallString<256> VersionPath;
+ if (auto EC = llvm::sys::fs::createTemporaryFile("cpsc-lli-version", "txt", VersionPath)) {
+ llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "cannot check lli version: " << EC.message() << "\n";
+ return false;
+ }
+ llvm::FileRemover TemporaryVersion(VersionPath);
+ std::string ExecutionError;
+ int Result = llvm::sys::ExecuteAndWait(LliPath, {LliPath, "--version"},
+ std::nullopt, {llvm::StringRef(""), llvm::StringRef(VersionPath), llvm::StringRef("")},
+ 5, 0, &ExecutionError);
+ if (Result != 0) {
+ llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "cannot check lli version at '" << LliPath
+ << "' (status " << Result << ")";
+ if (!ExecutionError.empty()) llvm::errs() << ": " << ExecutionError;
+ llvm::errs() << "\n";
+ return false;
+ }
+ auto Version = llvm::MemoryBuffer::getFile(VersionPath);
+ if (!Version) {
+ llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "cannot read lli version: "
+ << Version.getError().message() << "\n";
+ return false;
+ }
+ llvm::SmallVector<llvm::StringRef, 2> Matches;
+ if (!llvm::Regex("LLVM version ([0-9]+)\\.").match((*Version)->getBuffer(), &Matches)) {
+ llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "cannot identify LLVM version of lli at '"
+ << LliPath << "'; LLVM 23 is required\n";
+ return false;
+ }
+ if (Matches[1] != "23") {
+ llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "-r requires lli from LLVM 23; found LLVM "
+ << Matches[1] << " at '" << LliPath << "'\n";
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+bool findLli(std::string &LliPath) {
+ auto Lli = llvm::sys::findProgramByName("lli");
+ if (!Lli) {
+ llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "-r requires lli from LLVM 23 in PATH: " << Lli.getError().message() << "\n";
+ return false;
+ }
+ LliPath = *Lli;
+ return checkLliVersion(LliPath);
+}
+
+int runLli(const std::string &LliPath, const std::string &IRPath,
+ const std::vector<std::string> &Objects) {
+ llvm::SmallString<256> RunPath(IRPath);
+ if (auto PathError = llvm::sys::fs::make_absolute(RunPath)) {
+ llvm::errs() << cps::diagnosticPrefix(cps::Severity::Error) << "cannot resolve IR path: " << PathError.message() << "\n";
+ return 1;
+ }
+ std::string ExecutionError;
+ std::vector<std::string> LliArgs = {LliPath};
+ for (const auto &Object : Objects) LliArgs.push_back("-extra-object=" + Object);
+ LliArgs.push_back(std::string(RunPath));
+ std::vector<llvm::StringRef> LliArgv(LliArgs.begin(), LliArgs.end());
+ int Result = llvm::sys::ExecuteAndWait(LliPath, LliArgv,
+ std::nullopt, {}, 0, 0, &ExecutionError);
+ if (Result < 0) {
+ llvm::errs() << cps::diagnosticPrefix(cps::Severity::Error) << "lli execution failed (status " << Result << "): "
+ << ExecutionError << "\n";
+ return 1;
+ }
+ return Result;
+}
diff --git a/tools/driver/PathRunner.h b/tools/driver/PathRunner.h
new file mode 100644
index 0000000..2043d4f
--- /dev/null
+++ b/tools/driver/PathRunner.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <string>
+#include <vector>
+
+// Finds PATH's lli for -r and checks that it is from LLVM 23. Reports a fatal
+// error and returns false otherwise.
+bool findLli(std::string &LliPath);
+
+// Executes the IR at IRPath with lli and returns the program's status.
+// Objects named by INCLUDE_OBJ are passed to lli as extra objects.
+int runLli(const std::string &LliPath, const std::string &IRPath,
+ const std::vector<std::string> &Objects);
diff --git a/tools/driver/main.cc b/tools/driver/main.cc
index 6893a63..d1dda81 100644
--- a/tools/driver/main.cc
+++ b/tools/driver/main.cc
@@ -7,16 +7,14 @@
#ifdef CPSC_RUN_EMBEDDED
#include "EmbeddedRunner.h"
#endif
+#ifdef CPSC_RUN_PATH
+#include "PathRunner.h"
+#endif
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
-#ifdef CPSC_RUN_PATH
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Regex.h"
-#endif
#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
#include "llvm/Support/raw_ostream.h"
#include <fstream>
#include <string>
@@ -74,82 +72,6 @@ llvm::SmallString<256> relativeToUnit(llvm::StringRef UnitPath, llvm::StringRef
return Result;
}
-#ifdef CPSC_RUN_PATH
-bool checkLliVersion(llvm::StringRef LliPath) {
- llvm::SmallString<256> VersionPath;
- if (auto EC = llvm::sys::fs::createTemporaryFile("cpsc-lli-version", "txt", VersionPath)) {
- llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "cannot check lli version: " << EC.message() << "\n";
- return false;
- }
- llvm::FileRemover TemporaryVersion(VersionPath);
- std::string ExecutionError;
- int Result = llvm::sys::ExecuteAndWait(LliPath, {LliPath, "--version"},
- std::nullopt, {llvm::StringRef(""), llvm::StringRef(VersionPath), llvm::StringRef("")},
- 5, 0, &ExecutionError);
- if (Result != 0) {
- llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "cannot check lli version at '" << LliPath
- << "' (status " << Result << ")";
- if (!ExecutionError.empty()) llvm::errs() << ": " << ExecutionError;
- llvm::errs() << "\n";
- return false;
- }
- auto Version = llvm::MemoryBuffer::getFile(VersionPath);
- if (!Version) {
- llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "cannot read lli version: "
- << Version.getError().message() << "\n";
- return false;
- }
- llvm::SmallVector<llvm::StringRef, 2> Matches;
- if (!llvm::Regex("LLVM version ([0-9]+)\\.").match((*Version)->getBuffer(), &Matches)) {
- llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "cannot identify LLVM version of lli at '"
- << LliPath << "'; LLVM 23 is required\n";
- return false;
- }
- if (Matches[1] != "23") {
- llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "-r requires lli from LLVM 23; found LLVM "
- << Matches[1] << " at '" << LliPath << "'\n";
- return false;
- }
- return true;
-}
-#endif
-
-#ifdef CPSC_RUN_PATH
-// Finds PATH's lli for -r and checks that it is from LLVM 23.
-bool findLli(std::string &LliPath) {
- auto Lli = llvm::sys::findProgramByName("lli");
- if (!Lli) {
- llvm::errs() << cps::diagnosticPrefix(cps::Severity::Fatal) << "-r requires lli from LLVM 23 in PATH: " << Lli.getError().message() << "\n";
- return false;
- }
- LliPath = *Lli;
- return checkLliVersion(LliPath);
-}
-
-// Executes the IR at IRPath with lli and returns the program's status.
-int runLli(const std::string &LliPath, const std::string &IRPath,
- const std::vector<std::string> &Objects) {
- llvm::SmallString<256> RunPath(IRPath);
- if (auto PathError = llvm::sys::fs::make_absolute(RunPath)) {
- llvm::errs() << cps::diagnosticPrefix(cps::Severity::Error) << "cannot resolve IR path: " << PathError.message() << "\n";
- return 1;
- }
- std::string ExecutionError;
- std::vector<std::string> LliArgs = {LliPath};
- for (const auto &Object : Objects) LliArgs.push_back("-extra-object=" + Object);
- LliArgs.push_back(std::string(RunPath));
- std::vector<llvm::StringRef> LliArgv(LliArgs.begin(), LliArgs.end());
- int Result = llvm::sys::ExecuteAndWait(LliPath, LliArgv,
- std::nullopt, {}, 0, 0, &ExecutionError);
- if (Result < 0) {
- llvm::errs() << cps::diagnosticPrefix(cps::Severity::Error) << "lli execution failed (status " << Result << "): "
- << ExecutionError << "\n";
- return 1;
- }
- return Result;
-}
-#endif
-
// -h anywhere prints a documentation pointer instead of compiling.
bool printHelp(int argc, char **argv) {
for (int I = 1; I < argc; ++I) {