march, flags, and git dependencies

This commit is contained in:
Jorijn van der Graaf 2025-02-03 22:06:54 +01:00
commit dc3865ba6d
8 changed files with 97 additions and 23 deletions

19
.github/workflows/release.yaml vendored Normal file
View file

@ -0,0 +1,19 @@
name: Main
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Prepare
run: sudo apt install clang lld
- name: Build
run: ./build.sh
- name: Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: build/crafter-build

View file

@ -24,7 +24,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::vector<Dependency> dependencies, std::vector<fs::path> additionalFiles): name(name), standard(standard), sourceFiles(sourceFiles), moduleFiles(moduleFiles), optimizationLevel(optimizationLevel), buildDir(buildDir), outputDir(outputDir), type(type), target(target), dependencies(dependencies), additionalFiles(additionalFiles) { 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): 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) {
} }
@ -38,6 +38,8 @@ Configuration::Configuration(const nlohmann::json& configs, const nlohmann::json
target = val.get<std::string>(); target = val.get<std::string>();
} else if(key == "type") { } else if(key == "type") {
type = val.get<std::string>(); type = val.get<std::string>();
} else if(key == "march") {
march = val.get<std::string>();
} else if(key == "source_files") { } else if(key == "source_files") {
const std::vector<std::string> tempSourceFiles = val.get<std::vector<std::string>>(); const std::vector<std::string> tempSourceFiles = val.get<std::vector<std::string>>();
sourceFiles = std::vector<fs::path>(tempSourceFiles.size()); sourceFiles = std::vector<fs::path>(tempSourceFiles.size());
@ -46,6 +48,8 @@ Configuration::Configuration(const nlohmann::json& configs, const nlohmann::json
const std::filesystem::path fullFilePath = workingDir / filePath; const std::filesystem::path fullFilePath = workingDir / filePath;
sourceFiles[i] = fullFilePath.generic_string(); sourceFiles[i] = fullFilePath.generic_string();
} }
} else if(key == "flags") {
flags = val.get<std::vector<std::string>>();
} else if(key == "module_files") { } else if(key == "module_files") {
const std::vector<std::string> tempModuleFiles = val.get<std::vector<std::string>>(); const std::vector<std::string> tempModuleFiles = val.get<std::vector<std::string>>();
moduleFiles = std::vector<fs::path>(tempModuleFiles.size()); moduleFiles = std::vector<fs::path>(tempModuleFiles.size());
@ -118,6 +122,12 @@ Configuration::Configuration(const nlohmann::json& configs, const nlohmann::json
if(!extendData.type.empty() && type.empty()) { if(!extendData.type.empty() && type.empty()) {
type = extendData.type; type = extendData.type;
} }
if(!extendData.march.empty() && march.empty()) {
march = extendData.march;
}
if(!extendData.flags.empty()){
flags.insert(flags.end(), extendData.flags.begin(), extendData.flags.end());
}
break; break;
} }
} }

View file

@ -41,9 +41,11 @@ export namespace Crafter::Build {
std::string outputDir; std::string outputDir;
std::string type; std::string type;
std::string target; std::string target;
std::string march;
std::vector<Dependency> dependencies; std::vector<Dependency> dependencies;
std::unordered_map<std::string, nlohmann::json> additionalProperties; std::unordered_map<std::string, nlohmann::json> additionalProperties;
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::vector<Dependency> dependencies, std::vector<fs::path> additionalFiles); std::vector<std::string> flags;
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);
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

@ -94,11 +94,17 @@ void ModuleFile::Compile(std::string clangDir, const Configuration& config, fs::
for(ModuleFile* dep : dependencies){ for(ModuleFile* dep : dependencies){
dep->Compile(clangDir, config, pcmDir, target); dep->Compile(clangDir, config, pcmDir, target);
} }
system(std::format("{} -std={} {}.cppm --precompile -fprebuilt-module-path={} -o {}.pcm {}", clangDir, config.standard, path.generic_string(), pcmDir.generic_string(), (pcmDir/path.filename()).generic_string(), target).c_str());
std::string flags;
for(const std::string& flag : config.flags) {
flags+=flag;
}
system(std::format("{} -std={} {}.cppm --precompile -march={} {} -fprebuilt-module-path={} -o {}.pcm {}", clangDir, config.standard, path.generic_string(), config.march, flags, pcmDir.generic_string(), (pcmDir/path.filename()).generic_string(), target).c_str());
recompiled = true; recompiled = true;
fileMutex.unlock(); fileMutex.unlock();
system(std::format("{} -std={} {}.pcm -fprebuilt-module-path={} -c -O{} -o {}.o {}", clangDir, config.standard, (pcmDir/path.filename()).generic_string(), pcmDir.generic_string(), config.optimizationLevel, (config.buildDir/path.filename()).generic_string(), target).c_str()); system(std::format("{} -std={} {}.pcm -fprebuilt-module-path={} -c -O{} -march={} {} -o {}.o {}", clangDir, config.standard, (pcmDir/path.filename()).generic_string(), pcmDir.generic_string(), config.optimizationLevel, config.march, flags, (config.buildDir/path.filename()).generic_string(), target).c_str());
} else { } else {
fileMutex.unlock(); fileMutex.unlock();
} }

View file

@ -74,6 +74,16 @@ void Project::Build(Configuration config, fs::path outputDir) const {
} }
void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) const { void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) const {
if(config.standard.empty()) {
config.standard = "c++26";
}
if(config.march.empty()) {
config.march = "native";
}
if(config.type.empty()) {
config.type = "executable";
}
if (!fs::exists(config.buildDir)) { if (!fs::exists(config.buildDir)) {
fs::create_directory(config.buildDir); fs::create_directory(config.buildDir);
} }
@ -101,7 +111,11 @@ void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) c
} }
for(std::int_fast32_t i = 0; i < depThreads.size(); i++) { for(std::int_fast32_t i = 0; i < depThreads.size(); i++) {
Project project = Project::LoadFromJSON(config.dependencies[i].path); if(config.dependencies[i].path.ends_with(".git")) {
system(std::format("cd {} && git clone {}", config.buildDir, config.dependencies[i].path).c_str());
}
config.dependencies[i].path = fs::path(config.dependencies[i].path).filename().replace_extension();
Project project = Project::LoadFromJSON(fs::path(config.buildDir)/config.dependencies[i].path/"project.json");
libs+=std::format(" -l{}", project.name); libs+=std::format(" -l{}", project.name);
depThreads[i] = std::thread([i, pcmDir, config, project, binDir]() { depThreads[i] = std::thread([i, pcmDir, config, project, binDir]() {
project.Build(config.dependencies[i].configuration, pcmDir, binDir); project.Build(config.dependencies[i].configuration, pcmDir, binDir);
@ -125,30 +139,35 @@ void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) c
clangDir = "clang++ -Wno-unused-command-line-argument"; clangDir = "clang++ -Wno-unused-command-line-argument";
} }
std::string flags;
for(const std::string& flag : config.flags) {
flags+=flag;
}
for(std::thread& thread : depThreads){ for(std::thread& thread : depThreads){
thread.join(); thread.join();
} }
std::string files; std::string files;
std::vector<std::thread> moduleThreads(config.moduleFiles.size()); //std::vector<std::thread> moduleThreads(config.moduleFiles.size());
for(std::uint_fast32_t i = 0; i < config.moduleFiles.size(); i++) { for(std::uint_fast32_t i = 0; i < config.moduleFiles.size(); i++) {
moduleThreads[i] = std::thread([i, &config, pcmDir, target, clangDir](){ //moduleThreads[i] = std::thread([i, &config, pcmDir, target, clangDir](){
ModuleFile::CompileModuleFile(config.moduleFiles[i], clangDir, config, pcmDir, target); ModuleFile::CompileModuleFile(config.moduleFiles[i], clangDir, config, pcmDir, target);
}); //});
files+=std::format("{}.o ",(config.buildDir/config.moduleFiles[i].filename()).generic_string()); files+=std::format("{}.o ",(config.buildDir/config.moduleFiles[i].filename()).generic_string());
} }
for(std::thread& thread : moduleThreads){ // for(std::thread& thread : moduleThreads){
thread.join(); // thread.join();
} // }
std::vector<std::thread> threads; std::vector<std::thread> threads;
for(std::uint_fast32_t i = 0; i < config.sourceFiles.size(); i++) { for(std::uint_fast32_t i = 0; i < config.sourceFiles.size(); i++) {
files+=std::format("{}_source.o ",(config.buildDir/config.sourceFiles[i].filename()).generic_string()); files+=std::format("{}_source.o ",(config.buildDir/config.sourceFiles[i].filename()).generic_string());
if(!fs::exists((config.buildDir/config.sourceFiles[i].filename()).generic_string()+"_source.o") || fs::last_write_time(config.sourceFiles[i].generic_string()+".cpp") > fs::last_write_time((config.buildDir/config.sourceFiles[i].filename()).generic_string()+"_source.o")) { //if(!fs::exists((config.buildDir/config.sourceFiles[i].filename()).generic_string()+"_source.o") || fs::last_write_time(config.sourceFiles[i].generic_string()+".cpp") > fs::last_write_time((config.buildDir/config.sourceFiles[i].filename()).generic_string()+"_source.o")) {
threads.emplace_back([i, &config, pcmDir, target, clangDir](){ threads.emplace_back([i, &config, pcmDir, target, clangDir, flags](){
system(std::format("{} -std={} {}.cpp -fprebuilt-module-path={} -c -O{} -o {}_source.o {}", clangDir, config.standard, config.sourceFiles[i].generic_string(), pcmDir.generic_string(), config.optimizationLevel, (config.buildDir/config.sourceFiles[i].filename()).generic_string(), target).c_str()); system(std::format("{} -std={} {}.cpp -fprebuilt-module-path={} -c -O{} -march={} {} -o {}_source.o {}", clangDir, config.standard, config.sourceFiles[i].generic_string(), pcmDir.generic_string(), config.optimizationLevel, config.march, flags, (config.buildDir/config.sourceFiles[i].filename()).generic_string(), target).c_str());
}); });
} //}
} }
for(std::thread& thread : threads){ for(std::thread& thread : threads){
@ -156,11 +175,11 @@ void Project::Build(Configuration config, fs::path outputDir, fs::path binDir) c
} }
if(config.type == "executable"){ if(config.type == "executable"){
system(std::format("{} {}-O{} -o {} {} {}", clangDir, files, config.optimizationLevel, (outputDir/name).generic_string(), target, libs).c_str()); system(std::format("{} {}-O{} -o {} {} {} -fuse-ld=lld", clangDir, files, config.optimizationLevel, (outputDir/name).generic_string(), target, libs).c_str());
} else if(config.type == "library"){ } else if(config.type == "library"){
system(std::format("ar r {}.a {}", (outputDir/fs::path("lib"+name)).generic_string(), files).c_str()); system(std::format("ar r {}.a {}", (outputDir/fs::path("lib"+name)).generic_string(), files).c_str());
} else if(config.type == "shared-library"){ } else if(config.type == "shared-library"){
system(std::format("ar r {}.so {} -shared", (outputDir/fs::path("lib"+name)).generic_string(), files).c_str()); system(std::format("ar r {}.so {}", (outputDir/fs::path("lib"+name)).generic_string(), files).c_str());
} }
for(const fs::path& additionalFile : config.additionalFiles){ for(const fs::path& additionalFile : config.additionalFiles){

View file

@ -67,10 +67,12 @@ Save and close, then run ``crafter-build -c debug``. Now you can run the ``hello
``-o`` Overrides the output folder. ``-o`` Overrides the output folder.
``-r`` Runs the executable after building.
## configuration properties ## configuration properties
``name`` Name of the configuration. ``name`` Name of the configuration.
``standard`` C++ standard that this configuration uses, please refer to the [relevant clang documentation](https://clang.llvm.org/cxx_status.html) ``standard`` C++ standard that this configuration uses, please refer to the [relevant clang documentation](https://clang.llvm.org/cxx_status.html), defaults to ``c++26``.
``source_files`` All source files of the project ``.cpp`` extension is assumed. ``source_files`` All source files of the project ``.cpp`` extension is assumed.
@ -82,9 +84,11 @@ Save and close, then run ``crafter-build -c debug``. Now you can run the ``hello
``output_dir`` The directory where the output files will be placed. ``output_dir`` The directory where the output files will be placed.
``type`` The type of the project: ``executable``, ``library``, ``shared-library``.
``extends`` An array of configuration names that this configuration extends, later elements in the array take priority over previous ones. ``extends`` An array of configuration names that this configuration extends, later elements in the array take priority over previous ones.
``optimization_level`` Please refer to the [relevant clang documentation](https://clang.llvm.org/docs/CommandGuide/clang.html#code-generation-options). ``optimization_level`` Please refer to the [relevant clang documentation](https://clang.llvm.org/docs/CommandGuide/clang.html#code-generation-options), defaults to ``0``.
``dependencies`` An object array of the dependencies of this project, example: ``dependencies`` An object array of the dependencies of this project, example:
```json ```json
@ -93,6 +97,10 @@ Save and close, then run ``crafter-build -c debug``. Now you can run the ``hello
"path":"/home/Crafter.Build/project.json", "path":"/home/Crafter.Build/project.json",
"configuration":"debug-lib" "configuration":"debug-lib"
} }
{
"path":"https://github.com/Catcrafts/Crafter.Build.git",
"configuration":"debug-lib"
}
] ]
``` ```
This will now link the library of Crafter.Build in the configuration you use this in. This will now link the library of Crafter.Build in the configuration you use this in.

View file

@ -1,4 +1,3 @@
clear
mkdir build mkdir build
mkdir bin mkdir bin
@ -21,5 +20,4 @@ clang++ -std=c++26 ./build/Crafter.Build-Dependency.pcm -fprebuilt-module-path=.
clang++ -std=c++26 ./build/Crafter.Build.pcm -fprebuilt-module-path=./build -c -O3 -o ./build/Crafter.Build.o clang++ -std=c++26 ./build/Crafter.Build.pcm -fprebuilt-module-path=./build -c -O3 -o ./build/Crafter.Build.o
clang++ ./build/main.o ./build/Crafter.Build-ModuleFile_source.o ./build/Crafter.Build-ModuleFile.o ./build/Crafter.Build.o ./build/Crafter.Build-Configuration.o ./build/Crafter.Build-Configuration_source.o ./build/Crafter.Build-Project.o ./build/Crafter.Build-Project_source.o ./build/Crafter.Build-Dependency.o ./build/Crafter.Build-Dependency_source.o -O3 -o ./bin/crafter-build clang++ ./build/main.o ./build/Crafter.Build-ModuleFile_source.o ./build/Crafter.Build-ModuleFile.o ./build/Crafter.Build.o ./build/Crafter.Build-Configuration.o ./build/Crafter.Build-Configuration_source.o ./build/Crafter.Build-Project.o ./build/Crafter.Build-Project_source.o ./build/Crafter.Build-Dependency.o ./build/Crafter.Build-Dependency_source.o -O3 -o ./bin/crafter-build
rm -rf build; rm -rf build
# crafter-build -c debug

View file

@ -31,13 +31,16 @@ int main(int argc, char* argv[]) {
fs::path filepath = "project.json"; fs::path filepath = "project.json";
std::string configuration; std::string configuration;
std::string outputDir; std::string outputDir;
bool run = false;
for (std::uint_fast32_t i = 1; i < argc; i++) { for (std::uint_fast32_t i = 1; i < argc; i++) {
std::string arg = std::string(argv[i]); std::string arg = std::string(argv[i]);
if(arg == "--help"){ if(arg == "--help"){
std::println("--help\tDisplays this help message.\n-c The name of the configuration to build.\n-p The path to the project file. defualts to project.json\n-o Overrides the output folder.\n"); std::println("--help\tDisplays this help message.\n-c The name of the configuration to build.\n-p The path to the project file. defualts to project.json\n-o Overrides the output folder.\n-r Runs the executable after building.");
return 0; return 0;
} else if(arg == "-c"){ } else if(arg == "-c"){
configuration = argv[++i]; configuration = argv[++i];
} else if(arg == "-r"){
run = true;
} else if(arg == "-o"){ } else if(arg == "-o"){
outputDir = argv[++i]; outputDir = argv[++i];
} else if(arg == "-p"){ } else if(arg == "-p"){
@ -61,4 +64,13 @@ int main(int argc, char* argv[]) {
} else{ } else{
project.Build(configuration, fs::path(outputDir)); project.Build(configuration, fs::path(outputDir));
} }
if(run){
for(const Configuration& config : project.configurations) {
if(config.name == configuration){
system(std::format("{}", (projectPath/fs::path(config.outputDir)/project.name).generic_string()).c_str());
return 0;
}
}
}
} }