...
This commit is contained in:
@@ -1,10 +1,77 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO.Compression;
|
||||
using System.Text.Json;
|
||||
using Compiler;
|
||||
|
||||
var nubFiles = new List<string>();
|
||||
var libFiles = new List<string>();
|
||||
var compileLib = false;
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
{
|
||||
string arg = args[i];
|
||||
|
||||
if (arg.StartsWith("--type="))
|
||||
{
|
||||
var value = arg.Split("--type=")[1];
|
||||
switch (value)
|
||||
{
|
||||
case "lib":
|
||||
compileLib = true;
|
||||
break;
|
||||
case "exe":
|
||||
compileLib = false;
|
||||
break;
|
||||
default:
|
||||
DiagnosticFormatter.Print(Diagnostic.Error("Type must be 'exe' or 'lib'").Build(), Console.Error);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else if (arg.EndsWith(".nub"))
|
||||
{
|
||||
nubFiles.Add(arg);
|
||||
}
|
||||
else if (arg.EndsWith(".nublib"))
|
||||
{
|
||||
libFiles.Add(arg);
|
||||
}
|
||||
else if (arg == "--help")
|
||||
{
|
||||
Console.WriteLine("""
|
||||
Usage: nubc [options] <files>
|
||||
|
||||
Options:
|
||||
--type=exe Compile the input files into an executable (default)
|
||||
--type=lib Compile the input files into a library
|
||||
--help Show this help message
|
||||
|
||||
Files:
|
||||
*.nub Nub source files to compile
|
||||
*.nublib Precompiled Nub libraries to link
|
||||
|
||||
Example:
|
||||
nubc --type=exe main.nub utils.nub math.nublib
|
||||
""");
|
||||
}
|
||||
else
|
||||
{
|
||||
DiagnosticFormatter.Print(Diagnostic.Error($"Unrecognized option '{arg}'").Build(), Console.Error);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
var moduleGraphBuilder = ModuleGraph.Create();
|
||||
var asts = new List<Ast>();
|
||||
var archivePaths = new List<string>();
|
||||
|
||||
foreach (var fileName in args)
|
||||
foreach (var libPath in libFiles)
|
||||
{
|
||||
var lib = ReadNublib(libPath);
|
||||
archivePaths.Add(lib.ArchivePath);
|
||||
moduleGraphBuilder.AddManifest(lib.Manifest);
|
||||
}
|
||||
|
||||
foreach (var fileName in nubFiles)
|
||||
{
|
||||
var file = File.ReadAllText(fileName);
|
||||
|
||||
@@ -54,13 +121,97 @@ foreach (var ast in asts)
|
||||
}
|
||||
}
|
||||
|
||||
var output = Generator.Emit(functions, moduleGraph);
|
||||
var output = Generator.Emit(functions, moduleGraph, compileLib);
|
||||
|
||||
Directory.Delete(".build", recursive: true);
|
||||
Directory.CreateDirectory(".build");
|
||||
if (Directory.Exists(".build"))
|
||||
{
|
||||
CleanDirectory(".build");
|
||||
}
|
||||
else
|
||||
{
|
||||
Directory.CreateDirectory(".build");
|
||||
}
|
||||
|
||||
File.WriteAllText(".build/out.c", output);
|
||||
if (compileLib)
|
||||
{
|
||||
File.WriteAllText(".build/out.c", output);
|
||||
Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-c", "-o", ".build/out.o", ".build/out.c", .. archivePaths]).WaitForExit();
|
||||
Process.Start("ar", ["rcs", ".build/out.a", ".build/out.o"]).WaitForExit();
|
||||
WriteNublib(".build/out.nublib", ".build/out.a", moduleGraph.CreateManifest());
|
||||
}
|
||||
else
|
||||
{
|
||||
File.WriteAllText(".build/out.c", output);
|
||||
Process.Start("gcc", ["-Og", "-fvisibility=hidden", "-fno-builtin", "-o", ".build/out", ".build/out.c", .. archivePaths]).WaitForExit();
|
||||
}
|
||||
|
||||
Process.Start("gcc", ["-Og", "-g", "-o", ".build/out", ".build/out.c", "-fvisibility=hidden","-fno-builtin"]);
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
static void CleanDirectory(string dirName)
|
||||
{
|
||||
var dir = new DirectoryInfo(dirName);
|
||||
|
||||
foreach (var file in dir.GetFiles())
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
|
||||
foreach (var subdir in dir.GetDirectories())
|
||||
{
|
||||
CleanDirectory(subdir.FullName);
|
||||
subdir.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
static void WriteNublib(string outputPath, string archivePath, ModuleGraph.Manifest manifest)
|
||||
{
|
||||
using var fs = new FileStream(outputPath, FileMode.Create);
|
||||
using var zip = new ZipArchive(fs, ZipArchiveMode.Create);
|
||||
|
||||
var serialized = JsonSerializer.Serialize(manifest, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = true,
|
||||
});
|
||||
|
||||
var manifestEntry = zip.CreateEntry("manifest.json");
|
||||
using (var writer = new StreamWriter(manifestEntry.Open()))
|
||||
{
|
||||
writer.Write(JsonSerializer.Serialize(manifest));
|
||||
}
|
||||
|
||||
var archiveEntry = zip.CreateEntry("lib.a");
|
||||
|
||||
using var entryStream = archiveEntry.Open();
|
||||
using var fileStream = File.OpenRead(archivePath);
|
||||
|
||||
fileStream.CopyTo(entryStream);
|
||||
}
|
||||
|
||||
static NublibLoadResult ReadNublib(string nublibPath)
|
||||
{
|
||||
using var fs = new FileStream(nublibPath, FileMode.Open, FileAccess.Read);
|
||||
using var zip = new ZipArchive(fs, ZipArchiveMode.Read);
|
||||
|
||||
var manifestEntry = zip.GetEntry("manifest.json") ?? throw new FileNotFoundException("Manifest not found in nublib", "manifest.json");
|
||||
|
||||
ModuleGraph.Manifest manifest;
|
||||
using (var reader = new StreamReader(manifestEntry.Open()))
|
||||
{
|
||||
var json = reader.ReadToEnd();
|
||||
manifest = JsonSerializer.Deserialize<ModuleGraph.Manifest>(json) ?? throw new InvalidDataException("Failed to deserialize manifest.json");
|
||||
}
|
||||
|
||||
var archiveEntry = zip.Entries.FirstOrDefault(e => e.Name.EndsWith(".a")) ?? throw new FileNotFoundException("Archive not found in nublib", "*.a");
|
||||
|
||||
string tempArchivePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".a");
|
||||
using (var entryStream = archiveEntry.Open())
|
||||
using (var tempFile = File.Create(tempArchivePath))
|
||||
{
|
||||
entryStream.CopyTo(tempFile);
|
||||
}
|
||||
|
||||
return new NublibLoadResult(manifest, tempArchivePath);
|
||||
}
|
||||
|
||||
public record NublibLoadResult(ModuleGraph.Manifest Manifest, string ArchivePath);
|
||||
|
||||
Reference in New Issue
Block a user