next advance

This commit is contained in:
2026-08-08 07:38:03 -06:00
parent 657588cf58
commit baf19016ff
11 changed files with 520 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
/.vscode/
/bin/
/out/
makevars.mk
+15
View File
@@ -0,0 +1,15 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
// Friendly reminder to alter the includepath
// in YOUR OWN .vscode/settings.json
"C_Cpp.default.includePath": [
"./src"
],
"terminal.integrated.defaultProfile.windows": "MSYS2 UCRT",
}
}
+51
View File
@@ -0,0 +1,51 @@
name: ''
author: '' # author and authors are added together
authors: ['']
descr:
- ''
# Amount of text to output
verbosity: normal
build:
# Set build folders
src:
path: './src'
targets: ['c','cpp'] # Set targets for compilation
out:
path: './out'
target: 'exe'
bin:
path: './bin'
target: 'o'
deps:
path: './bin' # Reuse binaries folder (default)
target: 'd'
rev_target: 'rd' # Extension for reverse dependencies
style: gcc # Dependency style of generated output
# Set number of threads to use
# for compilation of multiple files
# 0 To turn off multithreading.
# Default: 0
# Recommended: 4
threads: 4
vars:
distros:
distro_name:
# Distro Vars (overrides global)
vars:
# Commands executed at the start
start:
- ''
# Commands to generate dependencies
deps:
- ''
# Commands to compile one file
# Files may be compiled on multiple threads
compile:
- ''
# Commands to link one file
link:
- ''
# Commands executed after linking program
end:
- ''
+78
View File
@@ -0,0 +1,78 @@
# Include variables from user defined
# makevars.mak for paths & other stuff.
include makevars.mk
#Compiler and Linker
CC := g++
#The Target Binary Program
TARGET := out.exe
#The Directories, Source, Includes, Objects, Binary and Resources
SRCDIR := src
BUILDDIR := bin
TARGETDIR := out
SRCEXT := cpp
DEPEXT := d
OBJEXT := o
#Flags, Libraries and Includes
ROOT := ./
CFLAGS := -std=c++20 -O2 \
-Wall -Werror -Wextra \
-Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align \
-Wunused -Woverloaded-virtual -Wconversion \
-Wsign-conversion -Wnull-dereference -Wdouble-promotion \
-Wformat=2 -Wimplicit-fallthrough -Wsuggest-override \
-Wextra-semi -Wduplicated-cond -Wduplicated-branches \
-Wlogical-op -Wuseless-cast -Wno-unused-parameter
LFLAGS := -std=c++20 -static-libstdc++ -static-libgcc \
-Wl,--fatal-warnings -Wl,--warn-common
LIBDIRS := $(EXT_LIBDIRS)
LIB := $(EXT_LIB)
INC := -I./src/ $(EXT_INC)
#---------------------------------------------------------------------------------
# DO NOT EDIT BELOW THIS LINE
#---------------------------------------------------------------------------------
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
#Defauilt Make
all: directories $(TARGET)
#Remake
remake: cleaner all
#Make the Directories
directories:
@mkdir -p $(TARGETDIR)
@mkdir -p $(BUILDDIR)
#Clean only Objecst
clean:
@$(RM) -rf $(BUILDDIR)
#Full Clean, Objects and Binaries
cleaner: clean
@$(RM) -rf $(TARGETDIR)
#Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
#Link
$(TARGET): $(OBJECTS)
$(CC) $(LFLAGS) -o $(TARGETDIR)/$(TARGET) $^ $(LIBDIRS) $(LIB)
#Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
@mkdir -p $(dir $@)
$(CC) $(CFLAGS) $(INC) -c -o $@ $<
@$(CC) $(CFLAGS) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
@cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
@sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
@sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
@rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
#Non-File Targets
.PHONY: all remake clean cleaner resources
+35
View File
@@ -0,0 +1,35 @@
#!/usr/bin/env bash
BOLD="\033[1m"
RESET="\033[0m"
SUCCESS="\033[38;2;80;220;100m"
FAIL="\033[38;2;255;90;90m"
INFO="\033[38;2;100;200;255m"
DIM="\033[2m"
LOG="./out/out.log"
# Start
printf "${DIM}────────────────────────────────────────${RESET}\n"
printf "${INFO}${BOLD}> Running...${RESET}\n"
printf "${DIM}────────────────────────────────────────${RESET}\n\n"
# Send both stdout and stderr to the console and the log file.
start=$(date +%s.%N)
./out/out "$@" 2>&1 | tee "$LOG"
status=${PIPESTATUS[0]}
end=$(date +%s.%N)
elapsed=$(awk "BEGIN { printf \"%.3f\", $end - $start }")
# Status!
printf "\n${DIM}────────────────────────────────────────${RESET}\n"
if (( status == 0 )); then
printf "${SUCCESS}${BOLD}✓ Success${RESET} (exit %d)\n" "$status"
else
printf "${FAIL}${BOLD}✗ Failed${RESET} (exit %d)\n" "$status"
fi
printf "${INFO}${BOLD}> Time${RESET} ${elapsed}s\n"
printf "${INFO}${BOLD}> Log${RESET} %s\n" "$LOG"
printf "${DIM}────────────────────────────────────────${RESET}"
exit "$status"
+8
View File
@@ -0,0 +1,8 @@
#include "kmake.hpp"
#include <iostream>
int main() {
std::cout << "hello" << std::endl;
return 0;
}
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <ckitty/memory/primitives.hpp>
#include <desktoplib/terminal/Terminal.hpp>
#include <desktoplib/terminal/ui/Box.hpp>
#include <desktoplib/terminal/ui/MenuMap.hpp>
#include <desktoplib/terminal/ui/Content.hpp>
#include <desktoplib/terminal/ui/InnerScroll.hpp>
namespace kmake {
using namespace ckitty;
}
+9
View File
@@ -0,0 +1,9 @@
#include "Distro.hpp"
namespace kmake {
Distro::Distro() {}
Distro::~Distro() {}
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include <kmake/kmake.hpp>
namespace kmake {
class Distro {
public:
map<string, string> vars;
vector<string> start;
vector<string> deps;
vector<string> compile;
vector<string> link;
vector<string> end;
public:
Distro();
~Distro();
public:
};
}
+232
View File
@@ -0,0 +1,232 @@
#include "Project.hpp"
#include <ckitty/strings/utils.hpp>
#include <kmake/project/Distro.hpp>
#include <c4/yml/tree.hpp>
#include <c4/yml/parse.hpp>
#include <c4/yml/std/std.hpp>
#include <c4/yml/std/string.hpp>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <map>
namespace ryml {
using namespace c4::yml;
using namespace c4;
}
namespace kmake {
using namespace ryml;
// Safely converts c4::csubstr view to string
static string to_string(csubstr s) {
if (s.str == nullptr || s.len == 0) return "";
return string(s.str, s.len);
}
// Extracts a string list and logs unexpected nodes/types
static void parse_string_list(ryml::ConstNodeRef node, vector<string>& dest, const string& path, vector<string>& log) {
if (!node.valid()) {
log.push_back("[WARN] Section missing at path: '" + path + "'");
return;
}
if (!node.is_seq()) {
log.push_back("[WARN] Expected a list/sequence at '" + path + "', but found a scalar or map.");
return;
}
size_t index = 0;
for (ryml::ConstNodeRef child : node.children()) {
string item_path = path + "[" + std::to_string(index++) + "]";
// Unexpected: List item is a map or nested list instead of a string value
if (!child.has_val()) {
log.push_back("[WARN] Expected scalar string at '" + item_path + "', but found a nested container.");
continue;
}
string val;
child >> val;
if (val.empty()) {
log.push_back("[WARN] Empty string element ignored at '" + item_path + "'");
} else {
dest.push_back(val);
}
}
}
// Extracts a key-value string map and logs unexpected entries/types
static void parse_string_map(ryml::ConstNodeRef node, map<string, string>& dest, const string& path, vector<string>& log) {
if (!node.valid()) {
log.push_back("[WARN] Section missing at path: '" + path + "'");
return;
}
if (!node.is_map()) {
log.push_back("[WARN] Expected key-value map at '" + path + "', but found a scalar or list.");
return;
}
for (ryml::ConstNodeRef child : node.children()) {
if (!child.has_key()) {
log.push_back("[WARN] Entry without a key found inside map at '" + path + "'");
continue;
}
string k = to_string(child.key());
string key_path = path + "." + k;
// Unexpected: Value is a sub-map or sub-list instead of a string scalar
if (!child.has_val()) {
log.push_back("[WARN] Expected string scalar for key '" + key_path + "', but found a nested object/list.");
continue;
}
string v;
child >> v;
if (v.empty()) {
log.push_back("[WARN] Value for key '" + key_path + "' is empty.");
}
dest[k] = v;
}
}
static Distro parse_distro(c4::yml::ConstNodeRef node, const std::string& path, std::vector<std::string>& log) {
Distro d;
if (node.has_child("vars")) parse_string_map(node["vars"], d.vars, path + ".vars", log);
if (node.has_child("start")) parse_string_list(node["start"], d.start, path + ".start", log);
if (node.has_child("deps")) parse_string_list(node["deps"], d.deps, path + ".deps", log);
if (node.has_child("compile")) parse_string_list(node["compile"], d.compile, path + ".compile", log);
if (node.has_child("link")) parse_string_list(node["link"], d.link, path + ".link", log);
if (node.has_child("end")) parse_string_list(node["end"], d.end, path + ".end", log);
return d;
}
Project::Project()
: verbosity(Verbosity::NORMAL) {
build.threads = 0;
}
Project::~Project() {}
bool Project::load(const string& filename) {
auto logs = vector<string>();
// 1. Read file into buffer
std::ifstream file(filename, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
logs.push_back("Failed to open file: " + filename);
return false;
}
std::streamsize size = file.tellg();
file.seekg(0, std::ios::beg);
vector<char> buffer(size);
if (!file.read(buffer.data(), size)) {
logs.push_back("Failed to read file content: " + filename);
return false;
}
// 2. Parse in-place
ryml::Tree tree = ryml::parse_in_place(ryml::to_substr(buffer));
ryml::ConstNodeRef root = tree.rootref();
if (!root.is_map()) {
logs.push_back("[ERROR] Root YAML document must be a map.");
return;
}
// Parse 'name'
if (root.has_child("name") && root["name"].has_val()) {
root["name"] >> name;
} else {
logs.push_back("[WARN] Key 'name' is missing or empty.");
}
// Parse combined 'author' and 'authors'
if (root.has_child("author") && root["author"].has_val()) {
string single_author;
root["author"] >> single_author;
if (!single_author.empty()) {
authors.push_back(single_author);
}
}
if (root.has_child("authors")) {
parse_string_list(root["authors"], authors, "authors", logs);
}
// Parse 'descr'
if (root.has_child("descr")) {
parse_string_list(root["descr"], descr, "descr", logs);
}
// Parse 'verbosity'
if (root.has_child("verbosity") && root["verbosity"].has_val()) {
string v_str;
root["verbosity"] >> v_str;
v_str = strings::to_lower(v_str);
if (v_str == "debug") {
verbosity = Verbosity::DEBUG;
} else if (v_str == "high") {
verbosity = Verbosity::HIGH;
} else if (v_str == "low") {
verbosity = Verbosity::LOW;
} else if (v_str == "normal") {
verbosity = Verbosity::NORMAL;
} else {
logs.push_back("[WARN] Unknown verbosity level '" + v_str + "'. Defaulting to 'normal'.");
verbosity = Verbosity::NORMAL;
}
}
// Parse 'build'
if (root.has_child("build")) {
ryml::ConstNodeRef b_node = root["build"];
if (b_node.has_child("src")) {
ryml::ConstNodeRef src_node = b_node["src"];
if (src_node.has_child("path") && src_node["path"].has_val()) {
src_node["path"] >> build.src.path;
}
if (src_node.has_child("targets")) {
parse_string_list(src_node["targets"], build.src.targets, "build.src.targets", logs);
}
}
if (b_node.has_child("threads") && b_node["threads"].has_val()) {
b_node["threads"] >> build.threads;
}
}
// Parse 'vars'
if (root.has_child("vars")) {
parse_string_map(root["vars"], vars, "vars", logs);
}
// Parse 'distros'
if (root.has_child("distros")) {
ryml::ConstNodeRef d_node = root["distros"];
if (d_node.is_map()) {
for (ryml::ConstNodeRef child : d_node.children()) {
if (child.has_key()) {
string distro_name = to_string(child.key());
distros[distro_name] = parse_distro(child, "distros." + distro_name, logs);
}
}
} else {
logs.push_back("[WARN] Key 'distros' must be a map of distro configs.");
}
}
}
}
+44
View File
@@ -0,0 +1,44 @@
#pragma once
#include <kmake/kmake.hpp>
namespace kmake {
class Distro;
enum class Verbosity : int {
DEBUG = 3, HIGH = 2, NORMAL = 1, LOW = 0
};
class Project {
public:
string name;
vector<string> authors;
vector<string> descr;
Verbosity verbosity;
struct {
struct {
string path;
vector<string> targets;
} src;
int threads;
} build;
map<string, string> vars;
map<string, Distro> distros;
public:
Project();
~Project();
public:
bool load(const string& filename);
};
}