Stop using fatal errors
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
build
|
build
|
||||||
recovery
|
recovery
|
||||||
BeefSpace_User.toml
|
BeefSpace_User.toml
|
||||||
|
BeefSpace_Lock.toml
|
||||||
|
|
||||||
clang-c.h
|
clang-c.h
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
FileVersion = 1
|
|
||||||
|
|
||||||
[Locks."Clang-C.git".Git]
|
|
||||||
URL = "https://git.unicon-gmbh.de/BeefBindings/Clang-C.git"
|
|
||||||
Tag = ""
|
|
||||||
Hash = "a64e7a0cac26e4844385b87e595e27e95b46e5a0"
|
|
||||||
@@ -7,7 +7,13 @@ namespace CxxBuilder;
|
|||||||
|
|
||||||
static class FileMatcher
|
static class FileMatcher
|
||||||
{
|
{
|
||||||
public static void HandleMatches(Span<StringView> patterns, StringView directory, delegate void(StringView match) callback)
|
public enum Error
|
||||||
|
{
|
||||||
|
ExpectedEscapeSequence,
|
||||||
|
CharacterClassNotClosed,
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Result<void, Error> HandleMatches(Span<StringView> patterns, StringView directory, delegate void(StringView match) callback)
|
||||||
{
|
{
|
||||||
Runtime.Assert(Directory.Exists(directory), scope $"No such directory {directory}");
|
Runtime.Assert(Directory.Exists(directory), scope $"No such directory {directory}");
|
||||||
void Dir(StringView dir)
|
void Dir(StringView dir)
|
||||||
@@ -38,13 +44,14 @@ static class FileMatcher
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Dir(directory);
|
Dir(directory);
|
||||||
|
return .Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsMatch(StringView pattern, StringView path)
|
public static Result<bool, Error> IsMatch(StringView pattern, StringView path)
|
||||||
{
|
{
|
||||||
var pattern, path;
|
var pattern, path;
|
||||||
|
|
||||||
bool Matches(StringView pattern, char8 c)
|
Result<bool, Error> Matches(StringView pattern, char8 c)
|
||||||
{
|
{
|
||||||
if (pattern.IsEmpty) return false;
|
if (pattern.IsEmpty) return false;
|
||||||
|
|
||||||
@@ -56,7 +63,7 @@ static class FileMatcher
|
|||||||
return !Path.IsDirectorySeparatorChar(c);
|
return !Path.IsDirectorySeparatorChar(c);
|
||||||
case '?': return true;
|
case '?': return true;
|
||||||
case '\\':
|
case '\\':
|
||||||
Runtime.Assert(pattern.Length > 1, "Expected escape sequence");
|
if (pattern.Length <= 1) return .Err(.ExpectedEscapeSequence);
|
||||||
return c == pattern[1];
|
return c == pattern[1];
|
||||||
case '/': return Path.IsDirectorySeparatorChar(c);
|
case '/': return Path.IsDirectorySeparatorChar(c);
|
||||||
case '[':
|
case '[':
|
||||||
@@ -64,13 +71,14 @@ static class FileMatcher
|
|||||||
char8 Next()
|
char8 Next()
|
||||||
{
|
{
|
||||||
if (pattern.Length <= ++i)
|
if (pattern.Length <= ++i)
|
||||||
Runtime.FatalError("Character class not closed");
|
return (.)7;
|
||||||
return pattern[i];
|
return pattern[i];
|
||||||
}
|
}
|
||||||
bool negated = false;
|
bool negated = false;
|
||||||
char8 current;
|
char8 current;
|
||||||
switch (Next())
|
switch (Next())
|
||||||
{
|
{
|
||||||
|
case (.)7: return .Err(.CharacterClassNotClosed);
|
||||||
case '^', '!': negated = true; fallthrough;
|
case '^', '!': negated = true; fallthrough;
|
||||||
case '\\': current = Next();
|
case '\\': current = Next();
|
||||||
case ']': return false;
|
case ']': return false;
|
||||||
@@ -100,7 +108,12 @@ static class FileMatcher
|
|||||||
{
|
{
|
||||||
if (path.IsEmpty) return true;
|
if (path.IsEmpty) return true;
|
||||||
if (pattern.IsEmpty) return false;
|
if (pattern.IsEmpty) return false;
|
||||||
if (!Matches(pattern, path[0])) return false;
|
switch (Matches(pattern, path[0]))
|
||||||
|
{
|
||||||
|
case .Err: return _;
|
||||||
|
case .Ok(false): return false;
|
||||||
|
case .Ok:
|
||||||
|
}
|
||||||
switch (pattern[0])
|
switch (pattern[0])
|
||||||
{
|
{
|
||||||
case '*':
|
case '*':
|
||||||
@@ -114,8 +127,8 @@ static class FileMatcher
|
|||||||
defer { pattern = lazy; }
|
defer { pattern = lazy; }
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (IsMatch(lazy, path)) continue reduce;
|
if (Try!(IsMatch(lazy, path))) continue reduce;
|
||||||
if (!Matches(pattern, path[0])) continue reduce;
|
if (!Try!(Matches(pattern, path[0]))) continue reduce;
|
||||||
path.RemoveFromStart(1);
|
path.RemoveFromStart(1);
|
||||||
if (path.IsEmpty) return lazy.IsEmpty;
|
if (path.IsEmpty) return lazy.IsEmpty;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,24 +16,45 @@ static class Program
|
|||||||
Console.WriteLine("""
|
Console.WriteLine("""
|
||||||
Simple and fast build tool using clang and ninja.
|
Simple and fast build tool using clang and ninja.
|
||||||
|
|
||||||
Usage: $(Var CxxBuilderExe) <patterns...> -- src=<> target=<> builddir=<> output=<> [cflags=<>]
|
Usage: $(Var CxxBuilderExe) [<options>] <patterns...> -- src=<> target=<> config=<> builddir=<> output=<> [cflags=<>]
|
||||||
Example: $(Var CxxBuilderExe) **.c vk_*.cpp -- "src=$(ProjectDir)/MyLib/src" target=$(TargetTriple) "builddir=$(BuildDir)" output=MyLib cflags=-Isome/dir
|
Example: $(Var CxxBuilderExe) **.c vk_*.cpp -- "src=$(ProjectDir)/MyLib/src" target=$(TargetTriple) config=$(Configuration) "builddir=$(BuildDir)" output=MyLib cflags=-Isome/dir
|
||||||
|
|
||||||
src - The source dir, all patterns are rooted here
|
--template - TODO
|
||||||
target - the llvm target triple passed to clang
|
--cmake - builds $src/CMakeLists.txt to build, patterns and output are ignored
|
||||||
builddir - contains build artifacts and ninja files
|
|
||||||
output - the name of the output object archive $builddir/$output.lib on windows and $builddir/$output.a elsewhere
|
$src - The source dir, all patterns are rooted here
|
||||||
cflags - additional flags passed to clang
|
$target - the llvm target triple passed to clang
|
||||||
|
$config - the build configuration
|
||||||
|
$builddir - contains build artifacts and ninja files
|
||||||
|
$output - the name of the output object archive $builddir/$output.lib on windows and $builddir/$output.a elsewhere
|
||||||
|
$cflags - additional flags passed to clang
|
||||||
""");
|
""");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringView src = null, target = null, builddir = null, output = null, cflags = null;
|
mixin Assert(bool condition, StringView str)
|
||||||
|
{
|
||||||
|
if (!condition)
|
||||||
|
{
|
||||||
|
Console.WriteLine(str);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { Default, CMake, Template } mode = .Default;
|
||||||
|
StringView src = null, target = null, config = null, builddir = null, output = null, cflags = null;
|
||||||
var iter = args.GetEnumerator();
|
var iter = args.GetEnumerator();
|
||||||
skipPatterns: do
|
skipPatterns: do
|
||||||
{
|
{
|
||||||
for (let arg in iter)
|
for (let arg in iter)
|
||||||
|
{
|
||||||
if (arg == "--") break skipPatterns;
|
if (arg == "--") break skipPatterns;
|
||||||
|
if (arg == "--cmake")
|
||||||
|
{
|
||||||
|
Assert!(mode == .Default, "Conflicting options");
|
||||||
|
mode = .CMake;
|
||||||
|
}
|
||||||
|
}
|
||||||
PrintUsage!();
|
PrintUsage!();
|
||||||
}
|
}
|
||||||
for (let arg in iter)
|
for (let arg in iter)
|
||||||
@@ -50,20 +71,24 @@ static class Program
|
|||||||
value.Trim();
|
value.Trim();
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case "src": Runtime.Assert(src.IsNull, "Duplicate var 'src'"); src = value;
|
case "src": Assert!(src.IsNull, "Duplicate var 'src'"); src = value;
|
||||||
case "target": Runtime.Assert(target.IsNull, "Duplicate var 'target'"); target = value;
|
case "target": Assert!(target.IsNull, "Duplicate var 'target'"); target = value;
|
||||||
case "builddir": Runtime.Assert(builddir.IsNull, "Duplicate var 'builddir'"); builddir = value;
|
case "config": Assert!(config.IsNull, "Duplicate var 'config'"); config = value;
|
||||||
case "output": Runtime.Assert(output.IsNull, "Duplicate var 'output'"); output = value;
|
case "builddir": Assert!(builddir.IsNull, "Duplicate var 'builddir'"); builddir = value;
|
||||||
case "cflags": Runtime.Assert(cflags.IsNull, "Duplicate var 'cflags'"); cflags = value;
|
case "output": Assert!(output.IsNull, "Duplicate var 'output'"); output = value;
|
||||||
|
case "cflags": Assert!(cflags.IsNull, "Duplicate var 'cflags'"); cflags = value;
|
||||||
default: PrintUsage!();
|
default: PrintUsage!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Runtime.Assert(!src.IsNull, "Missing var 'src'");
|
Assert!(!src.IsNull, "Missing var 'src'");
|
||||||
Runtime.Assert(!target.IsNull, "Missing var 'target'");
|
Assert!(!target.IsNull, "Missing var 'target'");
|
||||||
Runtime.Assert(!builddir.IsNull, "Missing var 'builddir'");
|
Assert!(!config.IsNull, "Missing var 'config'");
|
||||||
Runtime.Assert(!builddir.IsNull, "Missing var 'output'");
|
Assert!(!builddir.IsNull, "Missing var 'builddir'");
|
||||||
|
Assert!(!output.IsNull || mode == .CMake, "Missing var 'output'");
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
{
|
{
|
||||||
|
case .Default:
|
||||||
StreamWriter writer = scope .()..Create(scope $"{builddir}/build.ninja");
|
StreamWriter writer = scope .()..Create(scope $"{builddir}/build.ninja");
|
||||||
{
|
{
|
||||||
String buffer = scope .(1024);
|
String buffer = scope .(1024);
|
||||||
@@ -79,7 +104,7 @@ static class Program
|
|||||||
WriteVarPath("builddir", builddir);
|
WriteVarPath("builddir", builddir);
|
||||||
buffer.AppendF($"""
|
buffer.AppendF($"""
|
||||||
target = {target}
|
target = {target}
|
||||||
cflags = {cflags}
|
cflags = {(config == "Release") ? "-O2" : "-O2 -g"} {cflags}
|
||||||
""");
|
""");
|
||||||
writer.Write(buffer);
|
writer.Write(buffer);
|
||||||
}
|
}
|
||||||
@@ -121,9 +146,25 @@ static class Program
|
|||||||
ar.Append(" $builddir/", match, ".o");
|
ar.Append(" $builddir/", match, ".o");
|
||||||
}
|
}
|
||||||
let abssrc = Path.GetAbsolutePath(src, Directory.GetCurrentDirectory(..scope .(128)), ..scope .(128));
|
let abssrc = Path.GetAbsolutePath(src, Directory.GetCurrentDirectory(..scope .(128)), ..scope .(128));
|
||||||
FileMatcher.HandleMatches(patterns, abssrc, scope => HandleMatch);
|
if (FileMatcher.HandleMatches(patterns, abssrc, scope => HandleMatch) case .Err(let err))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Syntax Error in Pattern: {err}");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
writer.WriteLine(ar);
|
writer.WriteLine(ar);
|
||||||
|
case .CMake:
|
||||||
|
#if !DEBUG
|
||||||
|
if (File.Exists(scope $"{builddir}/build.ninja"))
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
String cmd = scope .(512);
|
||||||
|
cmd.Append("cmake -S \"", src, "\" -B \"", builddir, "\" -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ");
|
||||||
|
cmd.Append("-DCMAKE_C_FLAGS=\"-target ", target, " ", cflags, "\" -DCMAKE_CXX_FLAGS=\"-target ", target, " ", cflags, "\" -DCMAKE_BUILD_TYPE=");
|
||||||
|
if (config == "Release") cmd.Append("Release");
|
||||||
|
else cmd.Append("RelWithDebInfo");
|
||||||
|
Assert!(system(cmd) == 0, "Build file generation failed");
|
||||||
|
case .Template: //TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = system(scope $"ninja -C {builddir}");
|
let ret = system(scope $"ninja -C {builddir}");
|
||||||
|
|||||||
Reference in New Issue
Block a user