commit 6507b80f63c286ce53abd3ad28063b2d81501423 Author: Rune Date: Sun Jun 7 19:25:31 2026 +0200 add tool diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d0d82d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +recovery +build +BeefSpace_User.toml \ No newline at end of file diff --git a/BeefProj.toml b/BeefProj.toml new file mode 100644 index 0000000..571cdd7 --- /dev/null +++ b/BeefProj.toml @@ -0,0 +1,6 @@ +FileVersion = 1 + +[Project] +Name = "CxxBuildTool" +TargetType = "BeefLib" +StartupObject = "CxxBuildTool.Program" diff --git a/BeefSpace.toml b/BeefSpace.toml new file mode 100644 index 0000000..4a7099b --- /dev/null +++ b/BeefSpace.toml @@ -0,0 +1,7 @@ +FileVersion = 1 + +[Workspace] +StartupProject = "CxxBuildTool" + +[Projects] +CxxBuildTool = {Path = "."} diff --git a/README.md b/README.md new file mode 100644 index 0000000..bb06752 --- /dev/null +++ b/README.md @@ -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"); +} +``` diff --git a/src/BuildTool.bf b/src/BuildTool.bf new file mode 100644 index 0000000..ec7de28 --- /dev/null +++ b/src/BuildTool.bf @@ -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 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 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[.. 0) + str.Append(bufferView[..