From c2bb9023d4011d4523c844e680949fd0259fbef2 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Sat, 15 Nov 2025 19:20:33 +0100 Subject: [PATCH] threaded exception handling --- .forgejo/workflows/demo.yaml | 12 +-- build.sh | 4 +- implementations/Crafter.Build-Command.cpp | 62 ++++++------- .../Crafter.Build-Implementation.cpp | 14 ++- implementations/Crafter.Build-Module.cpp | 68 +++++++++----- implementations/Crafter.Build-Project.cpp | 88 +++++++++++++------ implementations/main.cpp | 29 ++++-- interfaces/Crafter.Build-Command.cppm | 28 +++--- interfaces/Crafter.Build-CompileStatus.cppm | 29 ++++++ interfaces/Crafter.Build-Implementation.cppm | 3 +- interfaces/Crafter.Build-Module.cppm | 9 +- interfaces/Crafter.Build-Project.cppm | 13 ++- interfaces/Crafter.Build.cppm | 3 +- project.json | 2 +- 14 files changed, 237 insertions(+), 127 deletions(-) create mode 100644 interfaces/Crafter.Build-CompileStatus.cppm diff --git a/.forgejo/workflows/demo.yaml b/.forgejo/workflows/demo.yaml index a74763e..e6408b8 100644 --- a/.forgejo/workflows/demo.yaml +++ b/.forgejo/workflows/demo.yaml @@ -1,7 +1,7 @@ -on: [push] -jobs: - test: - runs-on: arch - steps: - - run: curl google.com +# on: [push] +# jobs: +# test: +# runs-on: arch +# steps: +# - run: curl google.com diff --git a/build.sh b/build.sh index 00e5ebf..d52d8a0 100755 --- a/build.sh +++ b/build.sh @@ -11,6 +11,7 @@ if [ ! -f "$STD_HEADER" ]; then fi cp "$STD_HEADER" ./build/std.cppm clang++ -std=c++26 -Wno-reserved-identifier -Wno-reserved-module-identifier --precompile ./build/std.cppm -o ./build/std.pcm +clang++ -std=c++26 --precompile -fprebuilt-module-path=./build interfaces/Crafter.Build-CompileStatus.cppm -o ./build/Crafter.Build-CompileStatus.pcm clang++ -std=c++26 --precompile -fprebuilt-module-path=./build interfaces/Crafter.Build-Command.cppm -o ./build/Crafter.Build-Command.pcm clang++ -std=c++26 --precompile -fprebuilt-module-path=./build interfaces/Crafter.Build-Shader.cppm -o ./build/Crafter.Build-Shader.pcm clang++ -std=c++26 --precompile -fprebuilt-module-path=./build interfaces/Crafter.Build-Module.cppm -o ./build/Crafter.Build-Module.pcm @@ -27,6 +28,7 @@ clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./build/Crafter.Build-I clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./build/Crafter.Build-Configuration.pcm -o ./build/Crafter.Build-Configuration.o clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./build/Crafter.Build-Project.pcm -o ./build/Crafter.Build-Project.o clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./build/Crafter.Build-Test.pcm -o ./build/Crafter.Build-Test.o +clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./build/Crafter.Build-CompileStatus.pcm -o ./build/Crafter.Build-CompileStatus.o clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./build/Crafter.Build.pcm -o ./build/Crafter.Build.o clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./implementations/Crafter.Build-Command.cpp -o ./build/Crafter.Build-Command_impl.o @@ -38,7 +40,7 @@ clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./implementations/Craft clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./implementations/Crafter.Build-Project.cpp -o ./build/Crafter.Build-Project_impl.o clang++ -std=c++26 -O3 -fprebuilt-module-path=./build -c ./implementations/main.cpp -o ./build/main.o -clang++ -std=c++26 -O3 -L/usr/local/lib -L/usr/lib/ -lvulkan -lMachineIndependent -lOSDependent -lGenericCodeGen -lglslang -lglslang-default-resource-limits -lSPIRV -ltbb -fuse-ld=lld ./build/Crafter.Build-Command.o ./build/Crafter.Build-Shader.o ./build/Crafter.Build-Module.o ./build/Crafter.Build-Configuration.o ./build/Crafter.Build-Project.o ./build/Crafter.Build.o ./build/Crafter.Build-Command_impl.o ./build/Crafter.Build-Shader_impl.o ./build/Crafter.Build-Module_impl.o ./build/Crafter.Build-Configuration_impl.o ./build/Crafter.Build-Project_impl.o ./build/Crafter.Build-Implementation.o ./build/Crafter.Build-Implementation_impl.o ./build/Crafter.Build-Test_impl.o ./build/Crafter.Build-Test.o ./build/main.o -o ./bin/executable/crafter-build +clang++ -std=c++26 -O3 -L/usr/local/lib -L/usr/lib/ -lvulkan -lMachineIndependent -lOSDependent -lGenericCodeGen -lglslang -lglslang-default-resource-limits -lSPIRV -ltbb -fuse-ld=lld ./build/Crafter.Build-Command.o ./build/Crafter.Build-CompileStatus.o ./build/Crafter.Build-Shader.o ./build/Crafter.Build-Module.o ./build/Crafter.Build-Configuration.o ./build/Crafter.Build-Project.o ./build/Crafter.Build.o ./build/Crafter.Build-Command_impl.o ./build/Crafter.Build-Shader_impl.o ./build/Crafter.Build-Module_impl.o ./build/Crafter.Build-Configuration_impl.o ./build/Crafter.Build-Project_impl.o ./build/Crafter.Build-Implementation.o ./build/Crafter.Build-Implementation_impl.o ./build/Crafter.Build-Test_impl.o ./build/Crafter.Build-Test.o ./build/main.o -o ./bin/executable/crafter-build cp -r binlib/* bin/ diff --git a/implementations/Crafter.Build-Command.cpp b/implementations/Crafter.Build-Command.cpp index 41f5e77..18744ae 100644 --- a/implementations/Crafter.Build-Command.cpp +++ b/implementations/Crafter.Build-Command.cpp @@ -51,40 +51,40 @@ namespace Crafter { pclose(pipe); } - CompileException::CompileException(std::vector&& errors) : errors(std::move(errors)) { - for(CompileError error : errors) { - message += std::format("File: {}:{}\nMessage: {}\nCode: {}", error.filename, error.line, error.message, error.code); - } - }; - const char* CompileException::what() const noexcept { - return message.c_str(); - } + // CompileException::CompileException(std::vector&& errors) : errors(std::move(errors)) { + // for(CompileError error : errors) { + // message += std::format("File: {}:{}\nMessage: {}\nCode: {}", error.filename, error.line, error.message, error.code); + // } + // }; + // const char* CompileException::what() const noexcept { + // return message.c_str(); + // } - void RunClang(const std::string_view cmd) { - std::cout << cmd << std::endl; - std::string result = RunCommand(cmd); - std::cout << result << std::endl; - // std::vector errors; + std::string RunClang(const std::string_view cmd) { + // std::string result = RunCommand(cmd); + // // std::vector errors; - // std::regex error_regex(R"((/[^:]+\.cpp):(\d+):\d+: error: (.*)\n\s*[0-9| ]*\s*(.*))"); - // std::smatch match; + // // std::regex error_regex(R"((/[^:]+\.cpp):(\d+):\d+: error: (.*)\n\s*[0-9| ]*\s*(.*))"); + // // std::smatch match; - // while (std::regex_search(result, match, error_regex)) { - // CompileError error; - // error.filename = match[1].str(); - // error.line = std::stoi(match[2].str()); - // error.message = match[3].str(); - // error.code = match[4].str(); - // errors.push_back(error); - // result = match.suffix().str(); + // // while (std::regex_search(result, match, error_regex)) { + // // CompileError error; + // // error.filename = match[1].str(); + // // error.line = std::stoi(match[2].str()); + // // error.message = match[3].str(); + // // error.code = match[4].str(); + // // errors.push_back(error); + // // result = match.suffix().str(); + // // } + + // if(result != "") { + // // if(errors.size() != 0) { + // // throw CompileException(std::move(errors)); + // // } else { + // throw std::runtime_error(result); + // //} // } - - if(result != "") { - // if(errors.size() != 0) { - // throw CompileException(std::move(errors)); - // } else { - throw std::runtime_error(result); - //} - } + std::cout << cmd << std::endl; + return RunCommand(cmd); } } \ No newline at end of file diff --git a/implementations/Crafter.Build-Implementation.cpp b/implementations/Crafter.Build-Implementation.cpp index 5688b9a..0db5cda 100644 --- a/implementations/Crafter.Build-Implementation.cpp +++ b/implementations/Crafter.Build-Implementation.cpp @@ -45,17 +45,23 @@ namespace Crafter { return true; } } - void Implementation::Compile(const std::string_view clang, const fs::path& buildDir) const { + void Implementation::Compile(const std::string_view clang, const fs::path& buildDir, std::string& result) const { for(ModulePartition* dependency : partitionDependencies) { if(!dependency->compiled.load()) { - dependency->compiled.wait(false); + dependency->compiled.wait(CRAFTER_COMPILE_STATUS_WAITING); + if(dependency->compiled.load() == CRAFTER_COMPILE_STATUS_ERROR) { + return; + } } } for(Module* dependency : moduleDependencies) { if(!dependency->compiled.load()) { - dependency->compiled.wait(false); + dependency->compiled.wait(CRAFTER_COMPILE_STATUS_WAITING); + if(dependency->compiled.load() == CRAFTER_COMPILE_STATUS_ERROR) { + return; + } } } - RunClang(std::format("{} {}.cpp -c -o {}_impl.o", clang, path.string(), (buildDir/path.filename()).string())); + return RunClang(std::format("{} {}.cpp -c -o {}_impl.o", clang, path.string(), (buildDir/path.filename()).string())); } } diff --git a/implementations/Crafter.Build-Module.cpp b/implementations/Crafter.Build-Module.cpp index ba6e0e5..7e36a6b 100644 --- a/implementations/Crafter.Build-Module.cpp +++ b/implementations/Crafter.Build-Module.cpp @@ -24,7 +24,7 @@ import :Command; namespace fs = std::filesystem; namespace Crafter { - ModulePartition::ModulePartition(std::string&& name, fs::path&& path) : name(std::move(name)), path(std::move(path)), compiled(false), checked(false) {} + ModulePartition::ModulePartition(std::string&& name, fs::path&& path) : name(std::move(name)), path(std::move(path)), compiled(CRAFTER_COMPILE_STATUS_WAITING), checked(false) {} bool ModulePartition::Check(const fs::path& pcmDir) { if(!checked) { @@ -43,7 +43,7 @@ namespace Crafter { } } needsRecompiling = false; - compiled.store(true); + compiled.store(CRAFTER_COMPILE_STATUS_COMPLETED); return false; } else { needsRecompiling = true; @@ -54,24 +54,34 @@ namespace Crafter { } } - void ModulePartition::Compile(const std::string_view clang, const fs::path& pcmDir, const fs::path& buildDir) { + void ModulePartition::Compile(const std::string_view clang, const fs::path& pcmDir, const fs::path& buildDir, std::string& result) { for(ModulePartition* dependency : partitionDependencies) { if(!dependency->compiled.load()) { //std::cout << std::format("{} is waiting on {} {}", name, dependency->name, dependency->needsRecompiling) << std::endl; - dependency->compiled.wait(false); + dependency->compiled.wait(CRAFTER_COMPILE_STATUS_WAITING); + if(dependency->compiled.load() == CRAFTER_COMPILE_STATUS_ERROR) { + compiled.store(CRAFTER_COMPILE_STATUS_ERROR); + compiled.notify_all(); + return; + } } } - RunClang(std::format("{} {}.cppm --precompile -o {}.pcm", clang, path.string(), (pcmDir/path.filename()).string())); - RunClang(std::format("{} {}.pcm -c -o {}.o", clang, (pcmDir/path.filename()).string(), (buildDir/path.filename()).string())); - compiled.store(true); - compiled.notify_all(); + result += RunClang(std::format("{} {}.cppm --precompile -o {}.pcm", clang, path.string(), (pcmDir/path.filename()).string())); + result += RunClang(std::format("{} {}.pcm -c -o {}.o", clang, (pcmDir/path.filename()).string(), (buildDir/path.filename()).string())); + if(result.empty()) { + compiled.store(CRAFTER_COMPILE_STATUS_COMPLETED); + compiled.notify_all(); + } else { + compiled.store(CRAFTER_COMPILE_STATUS_ERROR); + compiled.notify_all(); + } } - Module::Module(std::string&& name, fs::path&& path, std::vector>&& partitions) : name(std::move(name)), path(std::move(path)), partitions(std::move(partitions)), compiled(false), checked(false) {} + Module::Module(std::string&& name, fs::path&& path, std::vector>&& partitions) : name(std::move(name)), path(std::move(path)), partitions(std::move(partitions)), compiled(CRAFTER_COMPILE_STATUS_WAITING), checked(false) {} - Module::Module(std::string&& name, fs::path&& path) : name(std::move(name)), path(std::move(path)), compiled(false), checked(false) {} + Module::Module(std::string&& name, fs::path&& path) : name(std::move(name)), path(std::move(path)), compiled(CRAFTER_COMPILE_STATUS_WAITING), checked(false) {} - Module::Module(fs::path&& path) : path(std::move(path)), compiled(false), checked(false) { + Module::Module(fs::path&& path) : path(std::move(path)), compiled(CRAFTER_COMPILE_STATUS_WAITING), checked(false) { std::ifstream t(this->path); std::stringstream buffer; buffer << t.rdbuf(); @@ -101,7 +111,7 @@ namespace Crafter { return true; } else { needsRecompiling = false; - compiled.store(true); + compiled.store(CRAFTER_COMPILE_STATUS_COMPLETED); return false; } } else { @@ -115,14 +125,13 @@ namespace Crafter { return needsRecompiling; } } - - void Module::Compile(const std::string_view clang, const fs::path& pcmDir, const fs::path& buildDir) { + + void Module::Compile(const std::string_view clang, const fs::path& pcmDir, const fs::path& buildDir, std::string& result) { std::vector threads; - for(std::unique_ptr& partition : partitions) { - if(partition->needsRecompiling) { - threads.emplace_back([&partition, clang, &pcmDir, &buildDir](){ - partition->Compile(clang, pcmDir, buildDir); - }); + std::vector results(partitions.size()); + for(std::uint_fast32_t i = 0; i < partitions.size(); i++) { + if( partitions[i]->needsRecompiling) { + threads.emplace_back(&ModulePartition::Compile, partitions[i].get(), clang, pcmDir, buildDir, std::ref(results[i])); } } @@ -130,10 +139,23 @@ namespace Crafter { thread.join(); } - RunClang(std::format("{} {}.cppm --precompile -o {}.pcm", clang, path.string(), (pcmDir/path.filename()).string())); - RunClang(std::format("{} {}.pcm -c -o {}.o", clang, (pcmDir/path.filename()).string(), (buildDir/path.filename()).string())); + for(const std::string& result2 : results) { + result += result2; + } - compiled.store(true); - compiled.notify_all(); + if(result.empty()) { + result += RunClang(std::format("{} {}.cppm --precompile -o {}.pcm", clang, path.string(), (pcmDir/path.filename()).string())); + result += RunClang(std::format("{} {}.pcm -c -o {}.o", clang, (pcmDir/path.filename()).string(), (buildDir/path.filename()).string())); + if(result.empty()) { + compiled.store(CRAFTER_COMPILE_STATUS_COMPLETED); + compiled.notify_all(); + } else { + compiled.store(CRAFTER_COMPILE_STATUS_ERROR); + compiled.notify_all(); + } + } else { + compiled.store(CRAFTER_COMPILE_STATUS_ERROR); + compiled.notify_all(); + } } } diff --git a/implementations/Crafter.Build-Project.cpp b/implementations/Crafter.Build-Project.cpp index 218ef22..4845242 100644 --- a/implementations/Crafter.Build-Project.cpp +++ b/implementations/Crafter.Build-Project.cpp @@ -31,28 +31,28 @@ namespace Crafter { Project::Project(std::string&& name, fs::path&& path, std::vector&& configurations) : name(std::move(name)), path(std::move(path)), configurations(std::move(configurations)) {} Project::Project(std::string&& name, fs::path&& path, std::vector&& configurations, fs::path&& binDir, fs::path&& buildDir) : name(std::move(name)), path(std::move(path)), configurations(std::move(configurations)), binDir(std::move(binDir)), buildDir(std::move(buildDir)) {} - Configuration& Project::Build(std::string_view configuration) { + + std::tuple Project::Build(std::string_view configuration) { for(Configuration& config : configurations) { if(config.name == configuration){ - Build(config); - return config; + return {config, Build(config)}; } } throw std::runtime_error(std::format("Configuration: {} not found.", configuration)); } - Configuration& Project::Build(std::string_view configuration, const fs::path& binDir, const fs::path& outputDir, const fs::path& buildDir, std::string outputName) { + std::tuple Project::Build(std::string_view configuration, const fs::path& binDir, const fs::path& outputDir, const fs::path& buildDir, std::string outputName) { for(Configuration& config : configurations) { if(config.name == configuration){ - Build(config, binDir, binDir, outputDir, outputName); - return config; + return {config, Build(config)}; } } throw std::runtime_error(std::format("Configuration: {} not found.", configuration)); } - void Project::Build(Configuration& config) const { - Build(config, binDir/config.name, binDir/config.name, buildDir/config.name, name); + BuildResult Project::Build(Configuration& config) const { + return Build(config, binDir/config.name, binDir/config.name, buildDir/config.name, name); } - void Project::Build(Configuration& config, const fs::path& binDir, const fs::path& outputDir, const fs::path& buildDir, std::string outputName) const { + BuildResult Project::Build(Configuration& config, const fs::path& binDir, const fs::path& outputDir, const fs::path& buildDir, std::string outputName) const { + BuildResult buildResult; if (!fs::exists(binDir)) { fs::create_directories(binDir); } @@ -75,7 +75,6 @@ namespace Crafter { std::thread fileThread([&config, &outputDir](){ for (const fs::path& additionalFile : config.additionalFiles) { fs::path destination = outputDir / additionalFile.filename(); - std::cout << destination << std::endl; if (fs::is_directory(additionalFile)) { if (!fs::exists(destination)) { @@ -190,9 +189,10 @@ namespace Crafter { std::vector depThreads = std::vector(config.dependencies.size()); std::mutex libMutex; std::string libsString; + std::vector resultsDep(config.dependencies.size()); for(std::uint_fast32_t i = 0; i < depThreads.size(); i++) { - depThreads[i] = std::thread([i, &config, &libMutex, &depLibSet, &buildDir, &pcmDir, &libsString, &binDir, this](){ + depThreads[i] = std::thread([i, &config, &libMutex, &depLibSet, &buildDir, &pcmDir, &libsString, &binDir, this, &buildResult, &resultsDep](){ if(config.dependencies[i].path.ends_with(".git")) { fs::path name = fs::path(config.dependencies[i].path).filename(); name.replace_extension(); @@ -216,8 +216,13 @@ namespace Crafter { for(Configuration& depConfig : project.configurations) { if(depConfig.name == config.dependencies[i].configuration){ fs::path depBuildDir = fs::path(config.dependencies[i].path).parent_path()/project.buildDir/depConfig.name; - project.Build(depConfig, pcmDir, binDir, depBuildDir, project.name); + BuildResult depResult = project.Build(depConfig, pcmDir, binDir, depBuildDir, project.name); libMutex.lock(); + if(depResult.repack) { + buildResult.repack = true; + } + resultsDep[i] = depResult.errors; + if (depLibSet.insert(project.name).second) { libsString+=std::format(" -l{}", project.name); } @@ -231,6 +236,7 @@ namespace Crafter { libsString+=std::format(" -l{}", project.name); } } + libMutex.unlock(); return; } @@ -243,31 +249,55 @@ namespace Crafter { thread.join(); } + for(const std::string& result2 : resultsDep) { + buildResult.errors += result2; + } + + if(!buildResult.errors.empty()) { + fileThread.join(); + return buildResult; + } + std::string files; - bool repack = false; - for(std::unique_ptr& modulee : config.interfaces) { - if(modulee->Check(pcmDir)) { - threads.emplace_back(&Module::Compile, modulee.get(), command, pcmDir, buildDir); - repack = true; + std::vector resultInterfaces(config.interfaces.size()); + + for(uint_fast32_t i = 0; i < config.interfaces.size(); i++) { + if(config.interfaces[i]->Check(pcmDir)) { + threads.emplace_back(&Module::Compile, config.interfaces[i].get(), command, pcmDir, buildDir, std::ref(resultInterfaces[i])); + buildResult.repack = true; } - files += std::format(" {}/{}.o", buildDir.string(), modulee->path.filename().string()); - for(std::unique_ptr& part : modulee->partitions) { + files += std::format(" {}/{}.o", buildDir.string(), config.interfaces[i]->path.filename().string()); + for(std::unique_ptr& part : config.interfaces[i]->partitions) { files += std::format(" {}/{}.o", buildDir.string(), part->path.filename().string()); } } + std::vector resultImplementations(config.implementations.size()); - for(const Implementation& implementation : config.implementations) { - if(implementation.Check(buildDir, pcmDir)) { - repack = true; - threads.emplace_back(&Implementation::Compile, &implementation, command, buildDir); + for(uint_fast32_t i = 0; i < config.implementations.size(); i++) { + if(config.implementations[i].Check(buildDir, pcmDir)) { + buildResult.repack = true; + threads.emplace_back(&Implementation::Compile, &config.implementations[i], command, buildDir, std::ref(resultImplementations[i])); } - files += std::format(" {}/{}_impl.o", buildDir.string(), implementation.path.filename().string()); + files += std::format(" {}/{}_impl.o", buildDir.string(), config.implementations[i].path.filename().string()); } for(std::thread& thread : threads) { thread.join(); } + for(const std::string& result2 : resultInterfaces) { + buildResult.errors += result2; + } + for(const std::string& result2 : resultImplementations) { + buildResult.errors += result2; + } + + + if(!buildResult.errors.empty()) { + fileThread.join(); + return buildResult; + } + if(config.target != "wasm32-wasi") { command += " -L/usr/local/lib"; } @@ -285,19 +315,21 @@ namespace Crafter { command += std::format(" -L{}", pcmDir.string()); } - if(repack) { + if(buildResult.repack) { if(config.type == CRAFTER_CONFIGURATION_TYPE_EXECUTABLE){ if(config.target == "wasm32-wasi") { outputName += ".wasm"; } - RunClang(std::format("{}{} -o {} -fuse-ld=lld", command, files, (binDir/outputName).string())); + buildResult.errors = RunClang(std::format("{}{} -o {} -fuse-ld=lld", command, files, (binDir/outputName).string())); } else if(config.type == CRAFTER_CONFIGURATION_TYPE_LIBRARY){ - std::cout << std::format("ar r {}.a {}", (binDir/fs::path(std::string("lib")+outputName)).string(), files) << std::endl; RunCommandIgnore(std::format("ar r {}.a {}", (binDir/fs::path(std::string("lib")+outputName)).string(), files)); } else { - RunClang(std::format("{}{} -shared -o {}.so -Wl,-rpath,'$ORIGIN' -fuse-ld=lld", command, files, (binDir/(std::string("lib")+outputName)).string())); + buildResult.errors = RunClang(std::format("{}{} -shared -o {}.so -Wl,-rpath,'$ORIGIN' -fuse-ld=lld", command, files, (binDir/(std::string("lib")+outputName)).string())); } } + + + return buildResult; } Project Project::LoadFromJSON(const fs::path& path) { diff --git a/implementations/main.cpp b/implementations/main.cpp index 66e63cf..1c2bfc3 100644 --- a/implementations/main.cpp +++ b/implementations/main.cpp @@ -69,18 +69,25 @@ int main(int argc, char* argv[]) { Project project = Project::LoadFromJSON(projectPath); if(command == "build") { - Configuration& config = project.Build(argument); - if(run){ - std::string binDir = std::format("{}/{}", project.binDir.string(), config.name); - if(config.debug) { - system(std::format("cd {} && ./{}", (fs::path(projectPath).parent_path()/binDir).string(), project.name).c_str()); - //system(std::format("cd {} && lldb -o run {}", (fs::path(projectPath).parent_path()/binDir).string(), project.name).c_str()); - } else { - system(std::format("cd {} && ./{}", (fs::path(projectPath).parent_path()/binDir).string(), project.name).c_str()); + std::tuple config = project.Build(argument); + std::cout << "amogus" << std::endl; + if(std::get<1>(config).errors.empty()) { + if(run){ + std::string binDir = std::format("{}/{}", project.binDir.string(), std::get<0>(config).name); + if(std::get<0>(config).debug) { + system(std::format("cd {} && ./{}", (fs::path(projectPath).parent_path()/binDir).string(), project.name).c_str()); + //system(std::format("cd {} && lldb -o run {}", (fs::path(projectPath).parent_path()/binDir).string(), project.name).c_str()); + } else { + system(std::format("cd {} && ./{}", (fs::path(projectPath).parent_path()/binDir).string(), project.name).c_str()); + } } - return 0; + } else { + std::cout << std::get<1>(config).errors << std::endl; + return 1; } } else if(command == "test") { + bool anyFailed = false; + if(argument.empty()) { std::vector results = project.RunTests(); for(const TestResult& result : results) { @@ -88,6 +95,7 @@ int main(int argc, char* argv[]) { std::cout << std::format("✅ {}", result.name) << std::endl; } else { std::cout << std::format("❌ {}\t{}", result.name, result.message) << std::endl; + anyFailed = true; } } } else { @@ -96,8 +104,11 @@ int main(int argc, char* argv[]) { std::cout << std::format("✅ {}", result.name) << std::endl; } else { std::cout << std::format("❌ {}\t{}", result.name, result.message) << std::endl; + anyFailed = true; } } + + return anyFailed ? 1 : 0; } else { std::println("Unkown command: {}", command); } diff --git a/interfaces/Crafter.Build-Command.cppm b/interfaces/Crafter.Build-Command.cppm index c024170..2422748 100644 --- a/interfaces/Crafter.Build-Command.cppm +++ b/interfaces/Crafter.Build-Command.cppm @@ -21,22 +21,22 @@ export module Crafter.Build:Command; import std; namespace Crafter { - export struct CompileError { - std::string filename; - std::uint_fast32_t line; - std::string message; - std::string code; - }; + // export struct CompileError { + // std::string filename; + // std::uint_fast32_t line; + // std::string message; + // std::string code; + // }; - export class CompileException : public std::exception { - public: - std::string message; - std::vector errors; - CompileException(std::vector&& errors); - const char* what() const noexcept override; - }; + // export class CompileException : public std::exception { + // public: + // std::string message; + // std::vector errors; + // CompileException(std::vector&& errors); + // const char* what() const noexcept override; + // }; export std::string RunCommand(const std::string_view cmd); export void RunCommandIgnore(const std::string_view cmd); - export void RunClang(const std::string_view cmd); + export std::string RunClang(const std::string_view cmd); } \ No newline at end of file diff --git a/interfaces/Crafter.Build-CompileStatus.cppm b/interfaces/Crafter.Build-CompileStatus.cppm new file mode 100644 index 0000000..b2d694a --- /dev/null +++ b/interfaces/Crafter.Build-CompileStatus.cppm @@ -0,0 +1,29 @@ +/* +Crafter® Build +Copyright (C) 2025 Catcrafts® +Catcrafts.net + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License version 3.0 as published by the Free Software Foundation; + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +export module Crafter.Build:CompileStatus; +import std; + +namespace Crafter { + export enum CompileStatus { + CRAFTER_COMPILE_STATUS_WAITING, + CRAFTER_COMPILE_STATUS_COMPLETED, + CRAFTER_COMPILE_STATUS_ERROR + }; +} \ No newline at end of file diff --git a/interfaces/Crafter.Build-Implementation.cppm b/interfaces/Crafter.Build-Implementation.cppm index c94c5f5..a6eb448 100644 --- a/interfaces/Crafter.Build-Implementation.cppm +++ b/interfaces/Crafter.Build-Implementation.cppm @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ export module Crafter.Build:Implementation; +import :CompileStatus; import std; namespace fs = std::filesystem; @@ -31,6 +32,6 @@ namespace Crafter { fs::path path; Implementation(fs::path&& path); bool Check(const fs::path& buildDir, const fs::path& pcmDir) const; - void Compile(const std::string_view clang, const fs::path& buildDir) const; + void Compile(const std::string_view clang, const fs::path& buildDir, std::string& result) const; }; } diff --git a/interfaces/Crafter.Build-Module.cppm b/interfaces/Crafter.Build-Module.cppm index c62459f..a6648f9 100644 --- a/interfaces/Crafter.Build-Module.cppm +++ b/interfaces/Crafter.Build-Module.cppm @@ -18,6 +18,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ export module Crafter.Build:Module; +import :CompileStatus; import std; namespace fs = std::filesystem; @@ -27,19 +28,19 @@ namespace Crafter { public: std::vector moduleDependencies; std::vector partitionDependencies; - std::atomic compiled; + std::atomic compiled; bool needsRecompiling; bool checked = false; std::string name; fs::path path; ModulePartition(std::string&& name, fs::path&& path); bool Check(const fs::path& pcmDir); - void Compile(const std::string_view clang, const fs::path& pcmDir, const fs::path& buildDir); + void Compile(const std::string_view clang, const fs::path& pcmDir, const fs::path& buildDir, std::string& result); }; export class Module { public: - std::atomic compiled; + std::atomic compiled; bool needsRecompiling; bool checked = false; std::vector> partitions; @@ -49,6 +50,6 @@ namespace Crafter { Module(std::string&& name, fs::path&& path); Module(std::string&& name, fs::path&& path, std::vector>&& partitions); bool Check(const fs::path& pcmDir); - void Compile(const std::string_view clang, const fs::path& pcmDir, const fs::path& buildDir); + void Compile(const std::string_view clang, const fs::path& pcmDir, const fs::path& buildDir, std::string& result); }; } diff --git a/interfaces/Crafter.Build-Project.cppm b/interfaces/Crafter.Build-Project.cppm index 1d2184a..06b3209 100644 --- a/interfaces/Crafter.Build-Project.cppm +++ b/interfaces/Crafter.Build-Project.cppm @@ -24,6 +24,11 @@ import :Test; namespace fs = std::filesystem; namespace Crafter { + export struct BuildResult { + std::string errors; + bool repack; + }; + export class Project { public: std::string name; @@ -35,10 +40,10 @@ namespace Crafter { Project(std::string&& name, fs::path&& path, std::vector&& configurations); Project(std::string&& name, fs::path&& path, std::vector&& configurations, fs::path&& buildDir, fs::path&& binDir); static Project LoadFromJSON(const fs::path& path); - Configuration& Build(std::string_view configuration); - Configuration& Build(std::string_view configuration, const fs::path& binDir, const fs::path& outputDir, const fs::path& buildDir, std::string outputName); - void Build(Configuration& configuration) const; - void Build(Configuration& configuration, const fs::path& binDir, const fs::path& outputDir, const fs::path& buildDir, std::string outputName) const; + std::tuple Build(std::string_view configuration); + std::tuple Build(std::string_view configuration, const fs::path& binDir, const fs::path& outputDir, const fs::path& buildDir, std::string outputName); + BuildResult Build(Configuration& configuration) const; + BuildResult Build(Configuration& configuration, const fs::path& binDir, const fs::path& outputDir, const fs::path& buildDir, std::string outputName) const; TestResult RunTest(const std::string_view test); TestResult RunTest(Test& test) const; std::vector RunTests(); diff --git a/interfaces/Crafter.Build.cppm b/interfaces/Crafter.Build.cppm index c8f0235..01df9da 100644 --- a/interfaces/Crafter.Build.cppm +++ b/interfaces/Crafter.Build.cppm @@ -24,4 +24,5 @@ export import :Module; export import :Configuration; export import :Shader; export import :Implementation; -export import :Test; \ No newline at end of file +export import :Test; +export import :CompileStatus; \ No newline at end of file diff --git a/project.json b/project.json index f5ffa7c..52827c2 100644 --- a/project.json +++ b/project.json @@ -3,7 +3,7 @@ "configurations": [ { "name": "base", - "interfaces": ["interfaces/Crafter.Build-Command", "interfaces/Crafter.Build-Configuration", "interfaces/Crafter.Build-Module", "interfaces/Crafter.Build-Project", "interfaces/Crafter.Build-Shader", "interfaces/Crafter.Build", "interfaces/Crafter.Build-Implementation", "interfaces/Crafter.Build-Test"], + "interfaces": ["interfaces/Crafter.Build-Command", "interfaces/Crafter.Build-Configuration", "interfaces/Crafter.Build-Module", "interfaces/Crafter.Build-Project", "interfaces/Crafter.Build-Shader", "interfaces/Crafter.Build", "interfaces/Crafter.Build-Implementation", "interfaces/Crafter.Build-Test", "interfaces/Crafter.Build-CompileStatus"], "implementations": ["implementations/Crafter.Build-Command", "implementations/Crafter.Build-Configuration", "implementations/Crafter.Build-Module", "implementations/Crafter.Build-Project", "implementations/Crafter.Build-Shader", "implementations/Crafter.Build-Implementation", "implementations/Crafter.Build-Test"], "libs": ["vulkan", "MachineIndependent", "OSDependent", "GenericCodeGen", "glslang", "glslang-default-resource-limits", "SPIRV", "tbb"] },