From bfe2e75d7e3b372e55369677028429990c49bc54 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Tue, 20 Oct 2026 11:44:48 +0000 Subject: 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 --- tools/driver/StandardLibrary.cc | 43 ++++++++++++++++++++++++++++++++++ tools/driver/StandardLibrary.h | 12 ++++++++++ tools/driver/embed-standard-library.pl | 28 ++++++++++++++++++++++ tools/driver/main.cc | 10 ++++++++ 4 files changed, 93 insertions(+) create mode 100644 tools/driver/StandardLibrary.cc create mode 100644 tools/driver/StandardLibrary.h create mode 100644 tools/driver/embed-standard-library.pl (limited to 'tools') 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 &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 +#include + +// Extracted files live through native linking and runner execution. +class StandardLibrary { + llvm::SmallString<256> Directory; +public: + ~StandardLibrary(); + bool load(std::vector &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>> Programs(InputPaths.size()); std::vector 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(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 : ""; -- cgit v1.3.1-4-g156e