diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-20 11:44:48 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-20 11:44:48 +0000 |
| commit | bfe2e75d7e3b372e55369677028429990c49bc54 (patch) | |
| tree | b64b0e999b428f7740c0cd2c4ec05d51a213ddd9 /tools | |
| parent | a3335110dc4f1283cf1680e273cc9775b7e8c8ac (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.cc | 43 | ||||
| -rw-r--r-- | tools/driver/StandardLibrary.h | 12 | ||||
| -rw-r--r-- | tools/driver/embed-standard-library.pl | 28 | ||||
| -rw-r--r-- | tools/driver/main.cc | 10 |
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 : ""; |
