...
This commit is contained in:
@@ -2,9 +2,7 @@ CFLAGS = -g
|
|||||||
|
|
||||||
bin/out: src/main.nub src/c.nub
|
bin/out: src/main.nub src/c.nub
|
||||||
dotnet build ../src/compiler/CLI/CLI.csproj -c Release
|
dotnet build ../src/compiler/CLI/CLI.csproj -c Release
|
||||||
../src/compiler/CLI/bin/Debug/net9.0/nubc src/main.nub src/c.nub
|
../src/compiler/CLI/bin/Release/net9.0/nubc src/main.nub src/c.nub
|
||||||
mkdir -p bin
|
|
||||||
gcc $(CFLAGS) -o bin/out bin-int/out/out.a
|
|
||||||
|
|
||||||
run: bin/out
|
run: bin/out
|
||||||
bin/out
|
bin/out
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ namespace CLI;
|
|||||||
|
|
||||||
public static class Archive
|
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();
|
using var process = new Process();
|
||||||
process.StartInfo = new ProcessStartInfo("ar", ["rcs", fileName, ..objectFiles])
|
process.StartInfo = new ProcessStartInfo("ar", ["rcs", fileName, ..objectFiles])
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ public static class GCC
|
|||||||
}
|
}
|
||||||
|
|
||||||
using var process = new Process();
|
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,
|
UseShellExecute = false,
|
||||||
RedirectStandardInput = true,
|
RedirectStandardInput = true,
|
||||||
@@ -37,4 +37,35 @@ public static class GCC
|
|||||||
|
|
||||||
return process.ExitCode == 0;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,4 +3,7 @@ namespace CLI;
|
|||||||
public class Options
|
public class Options
|
||||||
{
|
{
|
||||||
public string? CustomRuntime { get; set; }
|
public string? CustomRuntime { get; set; }
|
||||||
|
public string? OutputPath { get; set; }
|
||||||
|
public bool Link { get; set; } = true;
|
||||||
|
public List<string> Files { get; } = [];
|
||||||
}
|
}
|
||||||
@@ -8,28 +8,26 @@ using Syntax.Tokenization;
|
|||||||
using Syntax.Typing;
|
using Syntax.Typing;
|
||||||
using Binder = Syntax.Typing.Binder;
|
using Binder = Syntax.Typing.Binder;
|
||||||
|
|
||||||
|
const string BIN_DIR = "bin";
|
||||||
const string INT_DIR = "bin-int";
|
const string INT_DIR = "bin-int";
|
||||||
var BUILTIN_DIR = Path.Join(INT_DIR, "builtin");
|
var INT_BUILTIN_DIR = Path.Join(INT_DIR, "builtin");
|
||||||
var OBJECT_DIR = Path.Join(INT_DIR, "obj");
|
var INT_OBJECT_DIR = Path.Join(INT_DIR, "obj");
|
||||||
var OUT_DIR = Path.Join(INT_DIR, "out");
|
|
||||||
|
|
||||||
if (Directory.Exists(INT_DIR))
|
if (Directory.Exists(INT_DIR))
|
||||||
{
|
{
|
||||||
Directory.Delete(INT_DIR, true);
|
Directory.Delete(INT_DIR, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory.CreateDirectory(BUILTIN_DIR);
|
Directory.CreateDirectory(BIN_DIR);
|
||||||
Directory.CreateDirectory(OBJECT_DIR);
|
Directory.CreateDirectory(INT_BUILTIN_DIR);
|
||||||
Directory.CreateDirectory(OUT_DIR);
|
Directory.CreateDirectory(INT_OBJECT_DIR);
|
||||||
|
|
||||||
var options = new Options();
|
var options = new Options();
|
||||||
|
|
||||||
var files = new List<string>();
|
|
||||||
|
|
||||||
for (var i = 0; i < args.Length; i++)
|
for (var i = 0; i < args.Length; i++)
|
||||||
{
|
{
|
||||||
var arg = args[i];
|
var arg = args[i];
|
||||||
if (arg.StartsWith("-r") || arg.StartsWith("--runtime"))
|
if (arg == "-r")
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
if (i >= args.Length - 1)
|
if (i >= args.Length - 1)
|
||||||
@@ -40,16 +38,32 @@ for (var i = 0; i < args.Length; i++)
|
|||||||
|
|
||||||
options.CustomRuntime = args[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
|
else
|
||||||
{
|
{
|
||||||
files.Add(arg);
|
options.Files.Add(arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var diagnostics = new List<Diagnostic>();
|
var diagnostics = new List<Diagnostic>();
|
||||||
var syntaxTrees = new Dictionary<string, SyntaxTree>();
|
var syntaxTrees = new Dictionary<string, SyntaxTree>();
|
||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in options.Files)
|
||||||
{
|
{
|
||||||
if (!File.Exists(file))
|
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 content = File.ReadAllText(file);
|
||||||
var sourceText = new SourceText(file, content);
|
var sourceText = new SourceText(file, content);
|
||||||
@@ -100,7 +114,7 @@ if (diagnostics.Any(diagnostic => diagnostic.Severity == DiagnosticSeverity.Erro
|
|||||||
|
|
||||||
var objectFiles = new List<string>();
|
var objectFiles = new List<string>();
|
||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in options.Files)
|
||||||
{
|
{
|
||||||
var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable);
|
var ssa = QBEGenerator.Emit(boundSyntaxTrees[file], boundDefinitionTable);
|
||||||
var asm = await QBE.Invoke(ssa);
|
var asm = await QBE.Invoke(ssa);
|
||||||
@@ -109,7 +123,7 @@ foreach (var file in files)
|
|||||||
return 1;
|
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);
|
var asmSuccess = await GCC.Assemble(asm, fileName);
|
||||||
if (!asmSuccess)
|
if (!asmSuccess)
|
||||||
{
|
{
|
||||||
@@ -142,11 +156,24 @@ else
|
|||||||
objectFiles.Add(options.CustomRuntime);
|
objectFiles.Add(options.CustomRuntime);
|
||||||
}
|
}
|
||||||
|
|
||||||
var archiveResult = await Archive.Invoke(Path.Join(OUT_DIR, "out.a"), objectFiles);
|
if (options.Link)
|
||||||
|
{
|
||||||
|
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)
|
if (!archiveResult)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -164,7 +191,7 @@ async Task<string> CreateBuiltinRuntime()
|
|||||||
throw new RuntimeCreationException($"Cannot open stream to '{RUNTIME_NAME}'");
|
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);
|
await using var writer = new FileStream(runtimePath, FileMode.Create);
|
||||||
|
|
||||||
reader.CopyTo(writer);
|
reader.CopyTo(writer);
|
||||||
@@ -172,4 +199,4 @@ async Task<string> CreateBuiltinRuntime()
|
|||||||
return runtimePath;
|
return runtimePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RuntimeCreationException(string message) : Exception(message);
|
internal class RuntimeCreationException(string message) : Exception(message);
|
||||||
Reference in New Issue
Block a user