aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-20 11:44:48 +0000
committer_ov4 <ov4@ov4.org>2026-10-20 11:44:48 +0000
commitbfe2e75d7e3b372e55369677028429990c49bc54 (patch)
treeb64b0e999b428f7740c0cd2c4ec05d51a213ddd9 /tools
parenta3335110dc4f1283cf1680e273cc9775b7e8c8ac (diff)
feat(driver): embed and automatically link the standard library
Add -no-std to disable default library loading and linking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/driver/StandardLibrary.cc43
-rw-r--r--tools/driver/StandardLibrary.h12
-rw-r--r--tools/driver/embed-standard-library.pl28
-rw-r--r--tools/driver/main.cc10
4 files changed, 93 insertions, 0 deletions
diff --git a/tools/driver/StandardLibrary.cc b/tools/driver/StandardLibrary.cc
new file mode 100644
index 0000000..ac88745
--- /dev/null
+++ b/tools/driver/StandardLibrary.cc
@@ -0,0 +1,43 @@
+#include "StandardLibrary.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace {
+struct LibraryFile {
+ const char *Name;
+ const char *Data;
+ size_t Size;
+};
+#include "StandardLibrary.inc"
+}
+
+StandardLibrary::~StandardLibrary() {
+ if (!Directory.empty()) llvm::sys::fs::remove_directories(Directory);
+}
+
+bool StandardLibrary::load(std::vector<std::string> &Inputs) {
+ auto Error = llvm::sys::fs::createUniqueDirectory("cpsc-std", Directory);
+ if (Error) {
+ llvm::errs() << "cpsc: fatal error: cannot extract standard library: " << Error.message() << "\n";
+ return false;
+ }
+ for (const auto &File : LibraryFiles) {
+ llvm::SmallString<256> Path(Directory);
+ llvm::sys::path::append(Path, File.Name);
+ llvm::raw_fd_ostream Output(Path, Error);
+ if (!Error) {
+ Output.write(File.Data, File.Size);
+ Output.close();
+ Error = Output.error();
+ }
+ if (Error) {
+ llvm::errs() << "cpsc: fatal error: cannot extract standard library file '"
+ << File.Name << "': " << Error.message() << "\n";
+ Output.clear_error();
+ return false;
+ }
+ if (llvm::sys::path::extension(Path) == ".cps") Inputs.emplace_back(Path);
+ }
+ return true;
+}
diff --git a/tools/driver/StandardLibrary.h b/tools/driver/StandardLibrary.h
new file mode 100644
index 0000000..5aa4f8c
--- /dev/null
+++ b/tools/driver/StandardLibrary.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "llvm/ADT/SmallString.h"
+#include <string>
+#include <vector>
+
+// Extracted files live through native linking and runner execution.
+class StandardLibrary {
+ llvm::SmallString<256> Directory;
+public:
+ ~StandardLibrary();
+ bool load(std::vector<std::string> &Inputs);
+};
diff --git a/tools/driver/embed-standard-library.pl b/tools/driver/embed-standard-library.pl
new file mode 100644
index 0000000..68be7ef
--- /dev/null
+++ b/tools/driver/embed-standard-library.pl
@@ -0,0 +1,28 @@
+#!/usr/bin/env perl
+use strict;
+use warnings;
+use File::Basename qw(basename);
+
+my ($output, @inputs) = @ARGV;
+open my $out, '>', $output or die "$output: $!\n";
+print {$out} "// Generated from pseudocode-lib; do not edit.\n";
+for my $index (0 .. $#inputs) {
+ open my $in, '<:raw', $inputs[$index] or die "$inputs[$index]: $!\n";
+ local $/;
+ my $data = <$in>;
+ close $in or die "$inputs[$index]: $!\n";
+ print {$out} "static const char LibraryData$index\[\] =\n";
+ while (length $data) {
+ my $chunk = substr($data, 0, 32, '');
+ print {$out} '"', join('', map { sprintf '\\%03o', $_ } unpack 'C*', $chunk), "\"\n";
+ }
+ print {$out} ";\n";
+}
+print {$out} "static const LibraryFile LibraryFiles[] = {\n";
+for my $index (0 .. $#inputs) {
+ my $name = basename($inputs[$index]);
+ die "Invalid library filename: $name\n" unless $name =~ /^[A-Za-z0-9_.-]+$/;
+ print {$out} " {\"$name\", LibraryData$index, sizeof(LibraryData$index) - 1},\n";
+}
+print {$out} "};\n";
+close $out or die "$output: $!\n";
diff --git a/tools/driver/main.cc b/tools/driver/main.cc
index 5f3aaa2..4d41e5e 100644
--- a/tools/driver/main.cc
+++ b/tools/driver/main.cc
@@ -3,6 +3,7 @@
#include "cps/Parser.h"
#include "cps/CodeGen.h"
#include "NativeCompiler.h"
+#include "StandardLibrary.h"
#ifdef CPSC_RUN_EMBEDDED
#include "EmbeddedRunner.h"
#endif
@@ -91,12 +92,15 @@ int main(int argc, char **argv) {
std::string OutputPath;
bool Run = false;
bool EmitIR = false;
+ bool NoStd = false;
for (int I = 1; I < argc; ++I) {
std::string Arg = argv[I];
if (Arg == "-r") {
Run = true;
} else if (Arg == "-S") {
EmitIR = true;
+ } else if (Arg == "-no-std") {
+ NoStd = true;
} else if (Arg == "-o") {
if (!OutputPath.empty()) {
llvm::errs() << "cpsc: error: -o may only be specified once\n";
@@ -137,6 +141,9 @@ int main(int argc, char **argv) {
#endif
}
const bool Save = !Run || EmitIR || !OutputPath.empty();
+ const size_t UserInputCount = InputPaths.size();
+ StandardLibrary StdLibrary;
+ if (!NoStd && !StdLibrary.load(InputPaths)) return compilationTerminated();
std::vector<std::vector<std::unique_ptr<cps::StmtAST>>> Programs(InputPaths.size());
std::vector<cps::SourceUnit> Units;
for (size_t I = 0; I < InputPaths.size(); ++I) {
@@ -163,6 +170,9 @@ int main(int argc, char **argv) {
if (Lex.hadError() || Parser.hadError()) return compilationTerminated();
Units.push_back({InputPath, Programs[I], std::vector<bool>(InputPaths.size(), false), Lex.isLibrary()});
Units.back().Visible[I] = true;
+ if (!NoStd && I < UserInputCount)
+ for (size_t J = UserInputCount; J < InputPaths.size(); ++J)
+ Units.back().Visible[J] = true;
}
for (size_t I = 0; I < Units.size(); ++I) {
cps::DiagnosticSource = Units.size() > 1 ? Units[I].Path : "";