This commit is contained in:
Jorijn van der Graaf 2025-05-15 15:25:06 +02:00
commit 5af6d0080a
8 changed files with 93 additions and 73 deletions

View file

@ -25,7 +25,7 @@ module Crafter.Build;
using namespace Crafter::Build; using namespace Crafter::Build;
namespace fs = std::filesystem; namespace fs = std::filesystem;
Configuration::Configuration(std::string name, std::string standard, std::vector<fs::path> sourceFiles, std::vector<fs::path> moduleFiles, std::string optimizationLevel, std::string buildDir, std::string outputDir, std::string type, std::string target, std::string march, std::vector<Dependency> dependencies, std::vector<fs::path> additionalFiles, std::vector<std::string> flags, bool debug, std::vector<std::string> libs, std::vector<std::string> lib_paths, std::vector<fs::path> c_files, std::vector<Shader> shaderFiles, std::vector<std::string> includeDirs, bool verbose): name(name), standard(standard), sourceFiles(sourceFiles), moduleFiles(moduleFiles), optimizationLevel(optimizationLevel), buildDir(buildDir), outputDir(outputDir), type(type), target(target), march(march), dependencies(dependencies), additionalFiles(additionalFiles), flags(flags), debug(debug), libs(libs), lib_paths(lib_paths), c_files(c_files), shaderFiles(shaderFiles), includeDirs(includeDirs), verbose(verbose) { Configuration::Configuration(std::string name, std::string standard, std::vector<fs::path> sourceFiles, std::vector<fs::path> moduleFiles, std::string optimizationLevel, std::string buildDir, std::string outputDir, std::string type, std::string target, std::string march, std::vector<Dependency> dependencies, std::vector<fs::path> additionalFiles, std::vector<std::string> flags, bool debug, std::vector<std::string> libs, std::vector<std::string> lib_paths, std::vector<fs::path> c_files, std::vector<Shader> shaderFiles, std::vector<std::string> includeDirs, bool verbose, std::vector<Define> defines): name(name), standard(standard), sourceFiles(sourceFiles), moduleFiles(moduleFiles), optimizationLevel(optimizationLevel), buildDir(buildDir), outputDir(outputDir), type(type), target(target), march(march), dependencies(dependencies), additionalFiles(additionalFiles), flags(flags), debug(debug), libs(libs), lib_paths(lib_paths), c_files(c_files), shaderFiles(shaderFiles), includeDirs(includeDirs), verbose(verbose), defines(defines) {
} }
@ -83,6 +83,12 @@ Configuration::Configuration(const nlohmann::json& configs, const nlohmann::json
const std::filesystem::path fullFilePath = workingDir / filePath; const std::filesystem::path fullFilePath = workingDir / filePath;
shaderFiles.emplace_back(fullFilePath, it["entrypoint"].get<std::string>(), static_cast<EShLanguage>(it["type"].get<std::uint32_t>())); shaderFiles.emplace_back(fullFilePath, it["entrypoint"].get<std::string>(), static_cast<EShLanguage>(it["type"].get<std::uint32_t>()));
} }
} else if(key == "defines") {
for (auto it : val) {
std::string name = it["name"].get<std::string>();
std::string value = it["value"].get<std::string>();
defines.emplace_back(name, value);
}
} else if(key == "additional_files") { } else if(key == "additional_files") {
const std::vector<std::string> tempAdditionalFiles = val.get<std::vector<std::string>>(); const std::vector<std::string> tempAdditionalFiles = val.get<std::vector<std::string>>();
additionalFiles = std::vector<fs::path>(tempAdditionalFiles.size()); additionalFiles = std::vector<fs::path>(tempAdditionalFiles.size());
@ -182,6 +188,9 @@ Configuration::Configuration(const nlohmann::json& configs, const nlohmann::json
if(!extendData.includeDirs.empty()){ if(!extendData.includeDirs.empty()){
includeDirs.insert(includeDirs.end(), extendData.includeDirs.begin(), extendData.includeDirs.end()); includeDirs.insert(includeDirs.end(), extendData.includeDirs.begin(), extendData.includeDirs.end());
} }
if(!extendData.defines.empty()){
defines.insert(defines.end(), extendData.defines.begin(), extendData.defines.end());
}
break; break;
} }
} }

View file

@ -23,6 +23,7 @@ module;
#include <vector> #include <vector>
#include "json.hpp" #include "json.hpp"
#include <unordered_map> #include <unordered_map>
#include <format>
export module Crafter.Build:Configuration; export module Crafter.Build:Configuration;
import :Dependency; import :Dependency;
import :Shader; import :Shader;
@ -30,6 +31,14 @@ import :Shader;
namespace fs = std::filesystem; namespace fs = std::filesystem;
export namespace Crafter::Build { export namespace Crafter::Build {
struct Define {
std::string name;
std::string value;
std::string ToString() const {
return std::format(" -D {}={}", name, value);
}
};
class Configuration { class Configuration {
public: public:
std::string name; std::string name;
@ -40,6 +49,7 @@ export namespace Crafter::Build {
std::vector<Shader> shaderFiles; std::vector<Shader> shaderFiles;
std::vector<fs::path> additionalFiles; std::vector<fs::path> additionalFiles;
std::vector<std::string> includeDirs; std::vector<std::string> includeDirs;
std::vector<Define> defines;
std::string optimizationLevel; std::string optimizationLevel;
std::string buildDir; std::string buildDir;
std::string outputDir; std::string outputDir;
@ -53,7 +63,7 @@ export namespace Crafter::Build {
std::unordered_map<std::string, nlohmann::json> additionalProperties; std::unordered_map<std::string, nlohmann::json> additionalProperties;
std::vector<std::string> flags; std::vector<std::string> flags;
bool verbose = false; bool verbose = false;
Configuration(std::string name, std::string standard, std::vector<fs::path> sourceFiles, std::vector<fs::path> moduleFiles, std::string optimizationLevel, std::string buildDir, std::string outputDir, std::string type, std::string target, std::string march, std::vector<Dependency> dependencies, std::vector<fs::path> additionalFiles, std::vector<std::string> flags, bool debug, std::vector<std::string> libs, std::vector<std::string> lib_paths, std::vector<fs::path> c_files, std::vector<Shader> shaderFiles, std::vector<std::string> includeDirs, bool verbose); Configuration(std::string name, std::string standard, std::vector<fs::path> sourceFiles, std::vector<fs::path> moduleFiles, std::string optimizationLevel, std::string buildDir, std::string outputDir, std::string type, std::string target, std::string march, std::vector<Dependency> dependencies, std::vector<fs::path> additionalFiles, std::vector<std::string> flags, bool debug, std::vector<std::string> libs, std::vector<std::string> lib_paths, std::vector<fs::path> c_files, std::vector<Shader> shaderFiles, std::vector<std::string> includeDirs, bool verbose, std::vector<Define> defines);
Configuration(const nlohmann::json& configs, const nlohmann::json& config, fs::path workingDir); Configuration(const nlohmann::json& configs, const nlohmann::json& config, fs::path workingDir);
}; };
} }

View file

@ -29,6 +29,7 @@ export namespace Crafter::Build {
std::string configuration; std::string configuration;
std::string commit; std::string commit;
std::string branch; std::string branch;
std::string name;
Dependency(std::string path, std::string configuration, std::string commit, std::string branch); Dependency(std::string path, std::string configuration, std::string commit, std::string branch);
}; };
} }

View file

@ -55,10 +55,8 @@ ModulePartition::ModulePartition(const std::string& name, const fs::path& path,
} }
if(!fs::exists((pcmDir/path.filename()).generic_string()+".pcm")) { if(!fs::exists((pcmDir/path.filename()).generic_string()+".pcm")) {
needsRecompiling = true; needsRecompiling = true;
needsRecompilingDependency = true;
} else if(fs::last_write_time(path.generic_string()+".cppm") > fs::last_write_time((pcmDir/path.filename()).generic_string()+".pcm")) { } else if(fs::last_write_time(path.generic_string()+".cppm") > fs::last_write_time((pcmDir/path.filename()).generic_string()+".pcm")) {
needsRecompiling = true; needsRecompiling = true;
needsRecompilingDependency = true;
} }
} }
@ -77,7 +75,7 @@ void ModulePartition::AddDependants() {
void ModulePartition::Check() { void ModulePartition::Check() {
if(!needsRecompiling) { if(!needsRecompiling) {
for(ModulePartition* dependency : partitionDependenciesP) { for(ModulePartition* dependency : partitionDependenciesP) {
if(dependency->needsRecompilingDependency) { if(dependency->needsRecompiling) {
needsRecompiling = true; needsRecompiling = true;
break; break;
} }
@ -87,12 +85,16 @@ void ModulePartition::Check() {
void ModulePartition::Compile(std::string clangDir, const Configuration& config, fs::path pcmDir, std::string target, const std::string& march, const std::string& flags) { void ModulePartition::Compile(std::string clangDir, const Configuration& config, fs::path pcmDir, std::string target, const std::string& march, const std::string& flags) {
if(needsRecompiling) { if(needsRecompiling) {
std::string defines;
for(const Define& define : config.defines) {
defines+=define.ToString();
}
for(ModulePartition* dependency : partitionDependenciesP) { for(ModulePartition* dependency : partitionDependenciesP) {
if(dependency->needsRecompiling) { if(dependency->needsRecompiling) {
dependency->compiled->wait(false); dependency->compiled->wait(false);
} }
} }
std::string command = std::format("{} {} -std={} {}.cppm --precompile {} -fprebuilt-module-path={} -o {}.pcm {}", clangDir, flags, config.standard, path.generic_string(), march, pcmDir.generic_string(), (pcmDir/path.filename()).generic_string(), target); std::string command = std::format("{} {} {} -std={} {}.cppm --precompile {} -fprebuilt-module-path={} -o {}.pcm {}", clangDir, defines, flags, config.standard, path.generic_string(), march, pcmDir.generic_string(), (pcmDir/path.filename()).generic_string(), target);
if(config.verbose) { if(config.verbose) {
std::cout << command << std::endl; std::cout << command << std::endl;
} }
@ -102,7 +104,11 @@ void ModulePartition::Compile(std::string clangDir, const Configuration& config,
compiled->notify_all(); compiled->notify_all();
} }
void ModulePartition::CompileSource(std::string clangDir, const Configuration& config, fs::path pcmDir, std::string target, const std::string& march, const std::string& flags, const fs::path& buildDir) { void ModulePartition::CompileSource(std::string clangDir, const Configuration& config, fs::path pcmDir, std::string target, const std::string& march, const std::string& flags, const fs::path& buildDir) {
std::string command = std::format("{} -std={} {}.pcm -fprebuilt-module-path={} -c -O{} {} {} -o {}.o {}", clangDir, config.standard, (pcmDir/path.filename()).generic_string(), pcmDir.generic_string(), config.optimizationLevel, march, flags, (buildDir/path.filename()).generic_string(), target); std::string defines;
for(const Define& define : config.defines) {
defines+=define.ToString();
}
std::string command = std::format("{} {} -std={} {}.pcm -fprebuilt-module-path={} -c -O{} {} {} -o {}.o {}", clangDir, defines, config.standard, (pcmDir/path.filename()).generic_string(), pcmDir.generic_string(), config.optimizationLevel, march, flags, (buildDir/path.filename()).generic_string(), target);
if(config.verbose) { if(config.verbose) {
std::cout << command << std::endl; std::cout << command << std::endl;
} }
@ -145,9 +151,12 @@ void Module::Check() {
val.Check(); val.Check();
} }
for(auto& [key, val] : partitions) {; for(auto& [key, val] : partitions) {
if(val.needsRecompilingDependency) { if(val.needsRecompiling) {
needsRecompiling = true; needsRecompiling = true;
for(auto& [key, val] : partitions) {
val.needsRecompiling = true;
}
break; break;
} }
} }

View file

@ -36,7 +36,6 @@ export namespace Crafter::Build {
class ModulePartition { class ModulePartition {
public: public:
bool needsRecompilingDependency = false;
bool needsRecompiling = false; bool needsRecompiling = false;
fs::path path; fs::path path;
Module* parent; Module* parent;

View file

@ -30,73 +30,54 @@ module;
#include <thread> #include <thread>
#include <glslang/SPIRV/GlslangToSpv.h> #include <glslang/SPIRV/GlslangToSpv.h>
#include <regex> #include <regex>
#include <mutex>
module Crafter.Build; module Crafter.Build;
using namespace Crafter::Build; using namespace Crafter::Build;
namespace fs = std::filesystem; namespace fs = std::filesystem;
std::vector<std::string> mergeUnique(const std::vector<std::string>& vec1, const std::vector<std::string>& vec2) {
std::unordered_set<std::string> uniqueElements;
std::vector<std::string> result;
for (const auto& str : vec1) {
if (uniqueElements.insert(str).second) {
result.push_back(str);
}
}
for (const auto& str : vec2) {
if (uniqueElements.insert(str).second) {
result.push_back(str);
}
}
return result;
}
Project::Project(std::string name, fs::path path, std::vector<Configuration> configurations) : name(name), path(path), configurations(configurations) { Project::Project(std::string name, fs::path path, std::vector<Configuration> configurations) : name(name), path(path), configurations(configurations) {
} }
void Project::Build(std::string configuration) const { const Configuration& Project::Build(std::string configuration) {
for(const Configuration& config : configurations) { for(Configuration& config : configurations) {
if(config.name == configuration){ if(config.name == configuration){
Build(config); Build(config);
return; return config;
} }
} }
throw std::runtime_error("Configuration: " + configuration + " not found."); throw std::runtime_error("Configuration: " + configuration + " not found.");
} }
void Project::Build(std::string configuration, fs::path outputDir) const { const Configuration& Project::Build(std::string configuration, fs::path outputDir) {
for(const Configuration& config : configurations) { for(Configuration& config : configurations) {
if(config.name == configuration){ if(config.name == configuration){
Build(config, outputDir); Build(config, outputDir);
return; return config;
} }
} }
throw std::runtime_error("Configuration: " + configuration + " not found."); throw std::runtime_error("Configuration: " + configuration + " not found.");
} }
void Project::Build(std::string configuration, fs::path outputDir, fs::path binDir) const { const Configuration& Project::Build(std::string configuration, fs::path outputDir, fs::path binDir) {
for(const Configuration& config : configurations) { for(Configuration& config : configurations) {
if(config.name == configuration){ if(config.name == configuration){
Build(config, outputDir, binDir); Build(config, outputDir, binDir);
return; return config;
} }
} }
throw std::runtime_error("Configuration: " + configuration + " not found."); throw std::runtime_error("Configuration: " + configuration + " not found.");
} }
void Project::Build(Configuration configuration) const { void Project::Build(Configuration& configuration) {
Build(configuration, configuration.outputDir); Build(configuration, configuration.outputDir);
} }
void Project::Build(Configuration config, fs::path outputDir) const { void Project::Build(Configuration& config, fs::path outputDir) {
Build(config, outputDir, outputDir); Build(config, outputDir, outputDir);
} }
void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) const { void Project::Build(Configuration& config, fs::path outputDir, fs::path binDir) {
if(config.standard.empty()) { if(config.standard.empty()) {
config.standard = "c++26"; config.standard = "c++26";
} }
@ -149,7 +130,7 @@ void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) c
} }
for(Shader& shader : config.shaderFiles) { for(Shader& shader : config.shaderFiles) {
shader.Compile(outputDir); shader.Compile(binDir);
} }
std::vector<std::thread> depThreads = std::vector<std::thread>(config.dependencies.size()); std::vector<std::thread> depThreads = std::vector<std::thread>(config.dependencies.size());
@ -157,7 +138,7 @@ void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) c
if(config.dependencies.size() > 0){ if(config.dependencies.size() > 0){
libs += std::format(" -L{}", pcmDir.generic_string()); libs += std::format(" -L{}", pcmDir.generic_string());
} }
std::unordered_set<std::string> depLibSet;
for(std::int_fast32_t i = 0; i < depThreads.size(); i++) { for(std::int_fast32_t i = 0; i < depThreads.size(); i++) {
if(config.dependencies[i].path.ends_with(".git")) { if(config.dependencies[i].path.ends_with(".git")) {
fs::path name = fs::path(config.dependencies[i].path).filename(); fs::path name = fs::path(config.dependencies[i].path).filename();
@ -176,26 +157,37 @@ void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) c
} }
config.dependencies[i].path = fs::path(config.dependencies[i].path).filename().replace_extension(); config.dependencies[i].path = fs::path(config.dependencies[i].path).filename().replace_extension();
Project project = Project::LoadFromJSON(fs::path(buildDir)/config.dependencies[i].path/"project.json"); Project project = Project::LoadFromJSON(fs::path(buildDir)/config.dependencies[i].path/"project.json");
config.dependencies[i].name = project.name;
if (depLibSet.insert(project.name).second) {
libs+=std::format(" -l{}", project.name); libs+=std::format(" -l{}", project.name);
depThreads[i] = std::thread([i, pcmDir, config, project, binDir]() { }
project.Build(config.dependencies[i].configuration, pcmDir, binDir); const Configuration& depConfig = project.Build(config.dependencies[i].configuration, pcmDir, binDir);
}); for(const std::string& lib2 : depConfig.libs) {
for(const Configuration& config2 : project.configurations) { if (depLibSet.insert(lib2).second) {
if(config2.name == config.dependencies[i].configuration){ libs+=std::format(" -l{}", lib2);
config.libs = mergeUnique(config.libs, config2.libs); }
break; }
for(const Dependency& dep2 : depConfig.dependencies) {
if (depLibSet.insert(dep2.name).second) {
libs+=std::format(" -l{}", dep2.name);
} }
} }
} else{ } else{
Project project = Project::LoadFromJSON(config.dependencies[i].path); Project project = Project::LoadFromJSON(config.dependencies[i].path);
config.dependencies[i].name = project.name;
if (depLibSet.insert(project.name).second) {
libs+=std::format(" -l{}", project.name); libs+=std::format(" -l{}", project.name);
depThreads[i] = std::thread([i, pcmDir, config, project, binDir]() { }
project.Build(config.dependencies[i].configuration, pcmDir, binDir); const Configuration& depConfig = project.Build(config.dependencies[i].configuration, pcmDir, binDir);
}); for(const std::string& lib2 : depConfig.libs) {
for(const Configuration& config2 : project.configurations) { if (depLibSet.insert(lib2).second) {
if(config2.name == config.dependencies[i].configuration){ libs+=std::format(" -l{}", lib2);
config.libs = mergeUnique(config.libs, config2.libs); }
break; }
for(const Dependency& dep2 : depConfig.dependencies) {
if (depLibSet.insert(dep2.name).second) {
libs+=std::format(" -l{}", dep2.name);
} }
} }
} }
@ -231,10 +223,6 @@ void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) c
libs+= std::format(" -l{}",lib); libs+= std::format(" -l{}",lib);
} }
for(std::thread& thread : depThreads){
thread.join();
}
std::string march; std::string march;
if(config.target != "wasm32-unknown-wasi"){ if(config.target != "wasm32-unknown-wasi"){
march = std::format("-march={}", config.march); march = std::format("-march={}", config.march);

View file

@ -33,13 +33,13 @@ export namespace Crafter::Build {
fs::path path; fs::path path;
std::vector<Configuration> configurations; std::vector<Configuration> configurations;
Project(std::string name, fs::path path, std::vector<Configuration> configurations); Project(std::string name, fs::path path, std::vector<Configuration> configurations);
void Build(std::string configuration) const; const Configuration& Build(std::string configuration);
void Build(std::string configuration, fs::path outputDir) const; const Configuration& Build(std::string configuration, fs::path outputDir);
void Build(std::string configuration, fs::path outputDir, fs::path binDir) const; const Configuration& Build(std::string configuration, fs::path outputDir, fs::path binDir);
void Build(Configuration configuration) const; void Build(Configuration& configuration);
void Build(Configuration configuration, fs::path outputDir) const; void Build(Configuration& configuration, fs::path outputDir);
void Build(Configuration configuration, fs::path outputDir, fs::path binDir) const; void Build(Configuration& configuration, fs::path outputDir, fs::path binDir);
void SaveToJSON(fs::path path) const; void SaveToJSON(fs::path path);
static Project LoadFromJSON(fs::path path); static Project LoadFromJSON(fs::path path);
}; };
} }

View file

@ -31,11 +31,15 @@ using namespace Crafter::Build;
namespace fs = std::filesystem; namespace fs = std::filesystem;
void Source::GetSourceFiles(std::string clangDir, const Configuration& config, fs::path pcmDir, std::string target, const std::string& march, const std::string& flags, std::vector<std::thread>& threads, const std::vector<Module>& modules, std::string& files, const fs::path& buildDir) { void Source::GetSourceFiles(std::string clangDir, const Configuration& config, fs::path pcmDir, std::string target, const std::string& march, const std::string& flags, std::vector<std::thread>& threads, const std::vector<Module>& modules, std::string& files, const fs::path& buildDir) {
std::string defines;
for(const Define& define : config.defines) {
defines+=define.ToString();
}
for(const fs::path& sourceFile : config.sourceFiles) { for(const fs::path& sourceFile : config.sourceFiles) {
files+=std::format("{}_source.o ",(buildDir/sourceFile.filename()).generic_string()); files+=std::format("{}_source.o ",(buildDir/sourceFile.filename()).generic_string());
if(Source::Check(sourceFile, modules, config, buildDir)) { if(Source::Check(sourceFile, modules, config, buildDir)) {
threads.emplace_back([&config, sourceFile, pcmDir, target, clangDir, flags, march, buildDir](){ threads.emplace_back([&config, sourceFile, pcmDir, target, clangDir, flags, march, buildDir, defines](){
std::string command = std::format("{} -std={} {}.cpp -fprebuilt-module-path={} -c -O{} {} {} -o {}_source.o {}", clangDir, config.standard, sourceFile.generic_string(), pcmDir.generic_string(), config.optimizationLevel, march, flags, (buildDir/sourceFile.filename()).generic_string(), target); std::string command = std::format("{} {} -std={} {}.cpp -fprebuilt-module-path={} -c -O{} {} {} -o {}_source.o {}", clangDir, defines, config.standard, sourceFile.generic_string(), pcmDir.generic_string(), config.optimizationLevel, march, flags, (buildDir/sourceFile.filename()).generic_string(), target);
if(config.verbose) { if(config.verbose) {
std::cout << command << std::endl; std::cout << command << std::endl;
} }