This commit is contained in:
nub31
2025-06-29 17:40:17 +02:00
parent 2b40612f1b
commit edbab69c00
5 changed files with 83 additions and 24 deletions

View File

@@ -4,7 +4,7 @@ namespace CLI;
public static class Archive
{
public static async Task<bool> Invoke(string fileName, IEnumerable<string> objectFiles)
public static async Task<bool> Invoke(string fileName, params IEnumerable<string> objectFiles)
{
using var process = new Process();
process.StartInfo = new ProcessStartInfo("ar", ["rcs", fileName, ..objectFiles])

View File

@@ -13,7 +13,7 @@ public static class GCC
}
using var process = new Process();
process.StartInfo = new ProcessStartInfo("gcc", ["-g", "-xassembler", "-c", "-o", objPath, "-"])
process.StartInfo = new ProcessStartInfo("gcc", ["-xassembler", "-c", "-o", objPath, "-"])
{
UseShellExecute = false,
RedirectStandardInput = true,
@@ -37,4 +37,35 @@ public static class GCC
return process.ExitCode == 0;
}
public static async Task<bool> Link(string executablePath, params IEnumerable<string> objectFiles)
{
var dir = Path.GetDirectoryName(executablePath);
if (dir != null)
{
Directory.CreateDirectory(dir);
}
using var process = new Process();
process.StartInfo = new ProcessStartInfo("gcc", ["-nostartfiles", "-o", executablePath, ..objectFiles])
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true
};
process.Start();
await process.WaitForExitAsync();
var errors = await process.StandardError.ReadToEndAsync();
if (!string.IsNullOrWhiteSpace(errors))
{
await Console.Error.WriteLineAsync("gcc error when linking:\n" + errors);
}
return process.ExitCode == 0;
}
}

View File

@@ -3,4 +3,7 @@ namespace CLI;
public class Options
{
public string? CustomRuntime { get; set; }
public string? OutputPath { get; set; }
public bool Link { get; set; } = true;
public List<string> Files { get; } = [];
}

View File

@@ -8,28 +8,26 @@ using Syntax.Tokenization;
using Syntax.Typing;
using Binder = Syntax.Typing.Binder;
const string BIN_DIR = "bin";
const string INT_DIR = "bin-int";
var BUILTIN_DIR = Path.Join(INT_DIR, "builtin");
var OBJECT_DIR = Path.Join(INT_DIR, "obj");
var OUT_DIR = Path.Join(INT_DIR, "out");
var INT_BUILTIN_DIR = Path.Join(INT_DIR, "builtin");
var INT_OBJECT_DIR = Path.Join(INT_DIR, "obj");
if (Directory.Exists(INT_DIR))
{
Directory.Delete(INT_DIR, true);
}
Directory.CreateDirectory(BUILTIN_DIR);
Directory.CreateDirectory(OBJECT_DIR);
Directory.CreateDirectory(OUT_DIR);
Directory.CreateDirectory(BIN_DIR);
Directory.CreateDirectory(INT_BUILTIN_DIR);
Directory.CreateDirectory(INT_OBJECT_DIR);
var options = new Options();
var files = new List<string>();
for (var i = 0; i < args.Length; i++)
{
var arg = args[i];
if (arg.StartsWith("-r") || arg.StartsWith("--runtime"))
if (arg == "-r")
{
i++;
if (i >= args.Length - 1)
@@ -40,16 +38,32 @@ for (var i = 0; i < args.Length; i++)
options.CustomRuntime = args[i];
}
else if (arg == "-o")
{
i++;
if (i >= args.Length - 1)
{
Console.Error.WriteLine($"{arg} must be followed by a value");
return 1;
}
options.OutputPath = args[i];
}
else if (arg == "-c")
{
i++;
options.Link = false;
}
else
{
files.Add(arg);
options.Files.Add(arg);
}
}
var diagnostics = new List<Diagnostic>();
var syntaxTrees = new Dictionary<string, SyntaxTree>();
foreach (var file in files)
foreach (var file in options.Files)
{
if (!File.Exists(file))
{
@@ -58,7 +72,7 @@ foreach (var file in files)
}
}
foreach (var file in files)
foreach (var file in options.Files)
{
var content = File.ReadAllText(file);
var sourceText = new SourceText(file, content);
@@ -100,7 +114,7 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
var objectFiles = new List<string>();
foreach (var file in files)
foreach (var file in options.Files)
{
var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable);
var asm = await QBE.Invoke(ssa);
@@ -109,7 +123,7 @@ foreach (var file in files)
return 1;
}
var fileName = Path.Join(OBJECT_DIR, $"{HexString.CreateUnique(8)}_{Path.GetFileNameWithoutExtension(file)}.o");
var fileName = Path.Join(INT_OBJECT_DIR, $"{HexString.CreateUnique(8)}_{Path.GetFileNameWithoutExtension(file)}.o");
var asmSuccess = await GCC.Assemble(asm, fileName);
if (!asmSuccess)
{
@@ -142,10 +156,23 @@ else
objectFiles.Add(options.CustomRuntime);
}
var archiveResult = await Archive.Invoke(Path.Join(OUT_DIR, "out.a"), objectFiles);
if (!archiveResult)
if (options.Link)
{
return 1;
var outPath = options.OutputPath ?? Path.Join(BIN_DIR, "out");
var linkResult = await GCC.Link(outPath, objectFiles);
if (!linkResult)
{
return 1;
}
}
else
{
var outPath = options.OutputPath ?? Path.Join(BIN_DIR, "out.a");
var archiveResult = await Archive.Invoke(outPath, objectFiles);
if (!archiveResult)
{
return 1;
}
}
return 0;
@@ -164,7 +191,7 @@ async Task<string> CreateBuiltinRuntime()
throw new RuntimeCreationException($"Cannot open stream to '{RUNTIME_NAME}'");
}
var runtimePath = Path.Combine(BUILTIN_DIR, RUNTIME_NAME);
var runtimePath = Path.Combine(INT_BUILTIN_DIR, RUNTIME_NAME);
await using var writer = new FileStream(runtimePath, FileMode.Create);
reader.CopyTo(writer);
@@ -172,4 +199,4 @@ async Task<string> CreateBuiltinRuntime()
return runtimePath;
}
class RuntimeCreationException(string message) : Exception(message);
internal class RuntimeCreationException(string message) : Exception(message);