diff --git a/example/makefile b/example/makefile
index 5fba930..97985e8 100644
--- a/example/makefile
+++ b/example/makefile
@@ -1,9 +1,12 @@
-CFLAGS = -Wall -Werror -Wextra -g
+CFLAGS = -g
-example:
+bin/out: src/main.nub src/c.nub
dotnet run --project ../src/compiler/CLI/CLI.csproj src/main.nub src/c.nub
mkdir -p bin
- gcc $(CFLAGS) -o bin/out lib/libruntime_x64.a bin-int/out.a
+ gcc $(CFLAGS) -o bin/out bin-int/out/out.a
+
+run: bin/out
+ bin/out
clean:
rm -r bin-int bin
diff --git a/example/src/main.nub b/example/src/main.nub
index fd8ef94..4b2905d 100644
--- a/example/src/main.nub
+++ b/example/src/main.nub
@@ -3,4 +3,5 @@ namespace main
export func main(args: []cstring): i64 {
c::puts("test")
return 0
+
}
diff --git a/src/compiler/CLI/CLI.csproj b/src/compiler/CLI/CLI.csproj
index c101a01..a598c50 100644
--- a/src/compiler/CLI/CLI.csproj
+++ b/src/compiler/CLI/CLI.csproj
@@ -18,4 +18,9 @@
+
+
+
+
+
diff --git a/src/compiler/CLI/HexString.cs b/src/compiler/CLI/HexString.cs
new file mode 100644
index 0000000..2be6ef3
--- /dev/null
+++ b/src/compiler/CLI/HexString.cs
@@ -0,0 +1,38 @@
+namespace CLI;
+
+internal static class HexString
+{
+ private static readonly HashSet _used = [];
+
+ private static readonly char[] StringChars = "0123456789abcdef".ToArray();
+
+ public static string CreateUnique(int length)
+ {
+ string hex;
+
+ while (true)
+ {
+ hex = Create(length);
+ if (_used.Add(hex))
+ {
+ break;
+ }
+ }
+
+ return hex;
+ }
+
+ public static string Create(int length)
+ {
+ var rand = new Random();
+ var hexString = "";
+
+ for (var i = 0; i < length; i++)
+ {
+ var randIndex = rand.Next(0, StringChars.Length);
+ hexString += StringChars[randIndex];
+ }
+
+ return hexString;
+ }
+}
\ No newline at end of file
diff --git a/src/compiler/CLI/Options.cs b/src/compiler/CLI/Options.cs
new file mode 100644
index 0000000..947ed50
--- /dev/null
+++ b/src/compiler/CLI/Options.cs
@@ -0,0 +1,6 @@
+namespace CLI;
+
+public class Options
+{
+ public string? CustomRuntime { get; set; }
+}
\ No newline at end of file
diff --git a/src/compiler/CLI/Program.cs b/src/compiler/CLI/Program.cs
index 027ff11..44d1be2 100644
--- a/src/compiler/CLI/Program.cs
+++ b/src/compiler/CLI/Program.cs
@@ -1,20 +1,49 @@
-using CLI;
+using System.Reflection;
+using CLI;
using Generation.QBE;
using Syntax;
using Syntax.Diagnostics;
using Syntax.Parsing;
using Syntax.Tokenization;
using Syntax.Typing;
+using Binder = Syntax.Typing.Binder;
-const string OUT_DIR = "bin-int";
+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");
+if (Directory.Exists(INT_DIR))
+{
+ Directory.Delete(INT_DIR, true);
+}
+
+Directory.CreateDirectory(BUILTIN_DIR);
+Directory.CreateDirectory(OBJECT_DIR);
Directory.CreateDirectory(OUT_DIR);
+var options = new Options();
+
var files = new List();
-foreach (var arg in args)
+for (var i = 0; i < args.Length; i++)
{
- files.Add(arg);
+ var arg = args[i];
+ if (arg.StartsWith("-r") || arg.StartsWith("--runtime"))
+ {
+ i++;
+ if (i >= args.Length - 1)
+ {
+ Console.Error.WriteLine($"{arg} must be followed by a value");
+ return 1;
+ }
+
+ options.CustomRuntime = args[i];
+ }
+ else
+ {
+ files.Add(arg);
+ }
}
var diagnostics = new List();
@@ -80,7 +109,7 @@ foreach (var file in files)
return 1;
}
- var fileName = Path.GetTempFileName();
+ var fileName = Path.Join(OBJECT_DIR, $"{HexString.CreateUnique(8)}_{Path.GetFileNameWithoutExtension(file)}.o");
var asmSuccess = await GCC.Assemble(asm, fileName);
if (!asmSuccess)
{
@@ -90,10 +119,57 @@ foreach (var file in files)
objectFiles.Add(fileName);
}
+if (options.CustomRuntime == null)
+{
+ try
+ {
+ objectFiles.Add(await CreateBuiltinRuntime());
+ }
+ catch (RuntimeCreationException e)
+ {
+ Console.Error.WriteLine(e.Message);
+ return 1;
+ }
+}
+else
+{
+ if (!File.Exists(options.CustomRuntime))
+ {
+ Console.Error.WriteLine($"file '{options.CustomRuntime}' does not exist'");
+ return 1;
+ }
+
+ objectFiles.Add(options.CustomRuntime);
+}
+
var archiveResult = await Archive.Invoke(Path.Join(OUT_DIR, "out.a"), objectFiles);
if (!archiveResult)
{
return 1;
}
-return 0;
\ No newline at end of file
+return 0;
+
+async Task CreateBuiltinRuntime()
+{
+ const string RUNTIME_NAME = "libruntime_x64.a";
+
+ var resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();
+ var runtime = resources.First(r => r.EndsWith(RUNTIME_NAME));
+
+ await using var reader = Assembly.GetExecutingAssembly().GetManifestResourceStream(runtime);
+
+ if (reader == null)
+ {
+ throw new RuntimeCreationException($"Cannot open stream to '{RUNTIME_NAME}'");
+ }
+
+ var runtimePath = Path.Combine(BUILTIN_DIR, RUNTIME_NAME);
+ await using var writer = new FileStream(runtimePath, FileMode.Create);
+
+ reader.CopyTo(writer);
+
+ return runtimePath;
+}
+
+class RuntimeCreationException(string message) : Exception(message);
\ No newline at end of file
diff --git a/example/lib/libruntime_x64.a b/src/compiler/CLI/assets/libruntime_x64.a
similarity index 100%
rename from example/lib/libruntime_x64.a
rename to src/compiler/CLI/assets/libruntime_x64.a