This commit is contained in:
2026-06-07 19:25:31 +02:00
commit 6507b80f63
5 changed files with 149 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
recovery
build
BeefSpace_User.toml

6
BeefProj.toml Normal file
View File

@@ -0,0 +1,6 @@
FileVersion = 1
[Project]
Name = "CxxBuildTool"
TargetType = "BeefLib"
StartupObject = "CxxBuildTool.Program"

7
BeefSpace.toml Normal file
View File

@@ -0,0 +1,7 @@
FileVersion = 1
[Workspace]
StartupProject = "CxxBuildTool"
[Projects]
CxxBuildTool = {Path = "."}

9
README.md Normal file
View File

@@ -0,0 +1,9 @@
# CxxBuildTool
```
[OnCompile(.TypeDone)]
private static void Build()
{
CxxBuildTool.CMake(Compiler.ProjectDir + "/SDL", Compiler.BuildDir + "/" + Compiler.ProjectName + "/SDL", "-DSDL_STATIC=ON -DSDL_SHARED=OFF -DSDL_TESTS=OFF");
CxxBuildTool.Ninja(Compiler.ProjectDir, Compiler.BuildDir + "/" + Compiler.ProjectName + "/vk_mem_alloc", "vk_mem_alloc", "-Ipath/to/vulkan/include", "vk_mem_alloc.cpp");
}
```

124
src/BuildTool.bf Normal file
View File

@@ -0,0 +1,124 @@
using System;
using System.IO;
using System.Threading;
using System.Collections;
using System.Diagnostics;
namespace CxxBuildTool;
static class CxxBuildTool
{
public static void CMake(StringView sourceDir, StringView buildDir, StringView cmakeFlags = "", StringView clangFlags = "")
{
if (!File.Exists(scope $"{buildDir}/CMakeCache.txt"))
{
StringView buildType;
String flags = scope .(64);
switch ((Compiler.Options.OptLevel)Compiler.Options.OptimizationLevel)
{
case .Og, .OgPlus:
buildType = "RelWithDebInfo";
flags.Append("-O2");
default:
buildType = "Release";
flags.Append('-');
_.ToString(flags);
}
flags.Append(" --target=", Compiler.Options.TargetTriple);
RunCommand("cmake", scope $"-S {sourceDir} -B {buildDir} {cmakeFlags} -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_BUILD_TYPE={buildType
} -DCMAKE_C_FLAGS=\"{clangFlags} {flags}\" -DCMAKE_CXX_FLAGS=\"{clangFlags} {flags}\"");
}
RunCommand("cmake", scope $"--build {buildDir}");
}
public static void Ninja(StringView sourceDir, StringView buildDir, StringView projectName, StringView clangFlags, params Span<StringView> sourceFiles)
{
String ninja = scope .(1024);
ninja.AppendF($"""
src = {sourceDir}
builddir = {buildDir}
cflags = {clangFlags} --target={Compiler.Options.TargetTriple}
""");
switch ((Compiler.Options.OptLevel)Compiler.Options.OptimizationLevel)
{
case .Og, .OgPlus:
ninja.Append(" -O2 -g");
default:
ninja.Append(" -");
_.ToString(ninja);
}
ninja.Append("""
cc = clang
ar = llvm-ar
rule cc
command = $cc $cflags -MD -MF $out.d -c $in -o $out
depfile = $out.d
deps = gcc
description = Building $in
rule ar
command = $ar crs $out $in
description = Linking $out
""");
for (let src in sourceFiles)
ninja.Append("build $builddir/", src, ".o: cc $src/", src, "\n");
ninja.Append("\nbuild $builddir/", projectName,
((Compiler.Options.PlatformType)Compiler.Options.Platform == .Windows) ? ".lib" : ".a",
": ar");
for (let src in sourceFiles)
ninja.Append(" $builddir/", src, ".o");
ninja.Append('\n');
Directory.CreateDirectory(buildDir);
File.WriteAllText(scope $"{buildDir}/build.ninja", ninja);
RunCommand("ninja", scope $"-C {buildDir}");
}
static void RunCommand(StringView cmd, StringView args)
{
let startInfo = scope ProcessStartInfo();
startInfo.SetFileName(cmd);
startInfo.SetArguments(args);
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.CreateNoWindow = true;
let proc = scope SpawnedProcess();
Runtime.Assert(proc.Start(startInfo) case .Ok, "starting command failed");
FileStream output = scope .();
FileStream error = scope .();
proc.AttachStandardOutput(output);
proc.AttachStandardError(error);
String str = scope .();
Span<uint8> buffer = uint8[1024]();
StringView bufferView = *(.)&buffer;
while (!proc.HasExited || !output.IsEmpty || !error.IsEmpty)
{
while (output.TryRead(buffer) case .Ok(let val) && val > 0)
str.Append(bufferView[..<val]);
if (!str.IsEmpty)
{
Console.Write(str);
str.Clear();
}
while (error.TryRead(buffer) case .Ok(let val) && val > 0)
str.Append(bufferView[..<val]);
if (!str.IsEmpty)
{
Console.Write(str);
str.Clear();
}
}
Runtime.Assert(proc.ExitCode == 0, "command failed");
}
}