commit 2fd5989756001aeb94f500f9cf56e0801b9153bf Author: Syed Daanish Date: Thu Oct 8 12:46:54 2026 +0100 Initial setup diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9eeef6a --- /dev/null +++ b/Makefile @@ -0,0 +1,89 @@ +SRC_DIR := src +BIN_DIR := bin +OBJ_DIR := build +INCLUDE_DIR := include + +CXX ?= g++ +CC ?= gcc + +TARGET_DEBUG := $(BIN_DIR)/blade-dbg +TARGET_RELEASE := $(BIN_DIR)/blade + +PCH_DIR_DEBUG := $(OBJ_DIR)/debug/pch +PCH_DIR_RELEASE := $(OBJ_DIR)/release/pch + +PCH_DEBUG := $(PCH_DIR_DEBUG)/pch.h.gch +PCH_RELEASE := $(PCH_DIR_RELEASE)/pch.h.gch + +MRUBY_CFLAGS ?= -I./libs/mruby/build/host/include +MRUBY_LIBS ?= -L./libs/mruby/build/host/lib -lmruby + +CFLAGS_DEBUG :=\ + -std=c++23 -Wall -Wextra -fno-rtti \ + -Og -fno-inline -gsplit-dwarf -DDEBUG \ + -g -fno-omit-frame-pointer -ffast-math \ + -I./include + +CFLAGS_RELEASE :=\ + -std=c++23 -O3 -mtune=generic -fno-rtti \ + -fvisibility=hidden -static -ffast-math \ + -fomit-frame-pointer -DNDEBUG -s \ + -I./include + +CFLAGS_DEBUG += $(MRUBY_CFLAGS) +CFLAGS_RELEASE += $(MRUBY_CFLAGS) + +LIBS := $(MRUBY_LIBS) + +SRC := $(shell find $(SRC_DIR) -type f -name '*.cc') +OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC)) +OBJ_RELEASE := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/release/%.o,$(SRC)) + +DEP_DEBUG := $(OBJ_DEBUG:.o=.d) +DEP_RELEASE := $(OBJ_RELEASE:.o=.d) + +.PHONY: all debug release clean + +all: release + +debug: $(TARGET_DEBUG) + +release: $(TARGET_RELEASE) + +$(PCH_DEBUG): $(INCLUDE_DIR)/pch.h + @mkdir -p $(PCH_DIR_DEBUG) + @$(CXX) $(CFLAGS_DEBUG) -x c++-header -o $@ $(INCLUDE_DIR)/pch.h + @echo "Debug Precompiled header generated at $@" + +$(PCH_RELEASE): $(INCLUDE_DIR)/pch.h + @mkdir -p $(PCH_DIR_RELEASE) + @$(CXX) $(CFLAGS_RELEASE) -x c++-header -o $@ $(INCLUDE_DIR)/pch.h + @echo "Release Precompiled header generated at $@" + +$(TARGET_DEBUG): $(PCH_DEBUG) $(OBJ_DEBUG) + @mkdir -p $(BIN_DIR) + @$(CXX) $(CFLAGS_DEBUG) -o $@ $(OBJ_DEBUG) $(LIBS) + @echo "Debug build complete: $@" + +$(TARGET_RELEASE): $(PCH_RELEASE) $(OBJ_RELEASE) + @mkdir -p $(BIN_DIR) + @$(CXX) $(CFLAGS_RELEASE) -o $@ $(OBJ_RELEASE)$(LIBS) + @strip $@ + @echo "Release build complete: $@" + +$(OBJ_DIR)/debug/%.o: $(SRC_DIR)/%.cc $(PCH_DEBUG) $(GENERATED_HEADER) + @mkdir -p $(dir $@) + @$(CXX) $(CFLAGS_DEBUG) -I$(PCH_DIR_DEBUG) -include pch.h -MMD -MP -c $< -o $@ + @echo "[CXX] Debug object file generated: $@ from $<" + +$(OBJ_DIR)/release/%.o: $(SRC_DIR)/%.cc $(PCH_RELEASE) $(GENERATED_HEADER) + @mkdir -p $(dir $@) + @$(CXX) $(CFLAGS_RELEASE) -I$(PCH_DIR_RELEASE) -include pch.h -MMD -MP -c $< -o $@ + @echo "[CXX] release object file generated: $@ from $<" + +-include $(DEP_DEBUG) +-include $(DEP_RELEASE) + +clean: + @rm -rf $(OBJ_DIR) $(BIN_DIR) + @echo "Cleaned build artifacts." diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..848dcfe --- /dev/null +++ b/flake.nix @@ -0,0 +1,111 @@ +{ + description = "Blade"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + self.submodules = true; + }; + + outputs = + { nixpkgs, ... }: + let + system = "x86_64-linux"; + pkgs = nixpkgs.legacyPackages.${system}.pkgsStatic; + hostPkgs = nixpkgs.legacyPackages.${system}; + + mruby = pkgs.stdenv.mkDerivation { + pname = "mruby"; + version = "0.0.1"; + + src = pkgs.lib.cleanSourceWith { + src = ./libs; + name = "mruby-src"; + }; + + patches = [ + ./libs/changes.patch + ]; + + nativeBuildInputs = with hostPkgs; [ + ruby + gnumake + ]; + + buildPhase = '' + cd mruby + rake + ''; + + installPhase = '' + mkdir -p $out + + cp -r build/host/lib $out/lib + cp -r build/host/include $out/include + + mkdir -p $out/bin + cp build/host/bin/mrbc $out/bin/mrbc + ''; + }; + + blade = pkgs.stdenv.mkDerivation { + pname = "blade"; + version = "0.1.0"; + + src = ./.; + + nativeBuildInputs = with hostPkgs; [ + bash + pkg-config + gnumake + findutils + binutils + ]; + + buildInputs = [ + mruby + ]; + + buildPhase = '' + make \ + MRUBY_CFLAGS="-I${mruby}/include" \ + MRUBY_LIBS="-L${mruby}/lib -lmruby" + ''; + + installPhase = '' + mkdir -p $out/bin + cp bin/blade $out/bin/blade + ''; + }; + in + { + packages.${system} = { + default = blade; + blade = blade; + mruby = mruby; + }; + + devShells.${system}.default = hostPkgs.mkShell { + inputsFrom = [ blade ]; + + packages = with hostPkgs; [ + clang-tools + pkg-config + ccache + gnumake + bear + ruby + gdb + binutils + findutils + ]; + + shellHook = '' + export CC="ccache $CC" + export CXX="ccache $CXX" + + export MRUBY_CFLAGS=-I${mruby}/include + export MRUBY_LIBS="-L${mruby}/lib -lmruby" + ''; + }; + }; +} diff --git a/include/pch.h b/include/pch.h new file mode 100644 index 0000000..e69de29 diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..cda7b08 --- /dev/null +++ b/plan.md @@ -0,0 +1,103 @@ +# Blade is a PID 1 + +## Core + +* [ ] Custom C++ userspace / init system +* [ ] Everything runs in one main PID 1 process +* [ ] Keep subsystems code-wise separate internally +* [ ] Single-user system +* [ ] Custom privilege escalation binary (`sudo`-like) + +## Init / Service Manager + +* [ ] PID 1 handles system initialization +* [ ] Start/stop/restart services +* [ ] Service dependencies +* [ ] Service ordering / stages +* [ ] Continuous service supervision +* [ ] Ruby-defined service configuration +* [ ] Ruby hooks for service events +* [ ] Runtime service control through Ruby socket + +## Package Manager + +* [ ] Built into the main userspace +* [ ] Packages defined as Ruby scripts +* [ ] Packages use Git sources +* [ ] Build using `make` commands +* [ ] Package dependencies +* [ ] Install/update packages +* [ ] Cleanup/remove unused packages +* [ ] Package hooks +* [ ] Hooks can add services/configuration/etc. +* [ ] Build required packages during startup + +## Ruby + +* [ ] Embedded static mruby +* [ ] Ruby is the main configuration language +* [ ] Same Ruby system defines packages + services + hooks +* [ ] Ruby commands available at runtime over a socket +* [ ] Runtime API for controlling the system +* [ ] Hooks / shortcuts can react to system events + +## Built-in Components + +* [ ] D-Bus broker +* [ ] Wayland compositor + - Notifications (also connects to dbus) + - Clipboard with history, and api to read/work with history. +* [ ] Terminal emulator +* [ ] Session manager +* [ ] Package manager +* [ ] Service manager +* [ ] System configuration/runtime API + +## Boot Sequence + +1. Start basic services + * Networking + * Audio + * Other essential infrastructure +2. Run package manager + * Build/update/install required packages + * Cleanup + * Run package hooks +3. Start TTY2 + * Launch shell +4. Start normal non-desktop services +5. Start Wayland on TTY1 +6. Wayland starts in `locker` state +7. Start services that depend on Wayland +8. Resolve service dependencies/order +9. Enter continuous runtime/event loop + +## Wayland / Desktop + +* [ ] Wayland compositor is built into PID 1 +* [ ] TTY1 is graphical +* [ ] TTY2 is shell/terminal +* [ ] Desktop states: + * `locker` + * `terminal` + * `application` +* [ ] `application` state gives each application its own workspace +* [ ] System owns/controls the login/unlock password +* [ ] No traditional display manager +* [ ] One built-in terminal emulator +* [ ] Consider multiplexing later if actually needed + +## Runtime + +* [ ] Everything remains active after boot +* [ ] Event-driven system +* [ ] Ruby command socket +* [ ] Runtime configuration changes +* [ ] Hooks can react to: + * service events + * package events + * Wayland events + * shortcuts + * system events +* [ ] Continuously monitor and manage services + diff --git a/src/init/init.cc b/src/init/init.cc new file mode 100644 index 0000000..5567143 --- /dev/null +++ b/src/init/init.cc @@ -0,0 +1,42 @@ +#include +#include +#include + +#include +#include + +int main() +{ + // PID 1 + + int console = open("/dev/console", O_RDWR); + + if (console < 0) + { + perror("open /dev/console"); + return 1; + } + + dup2(console, STDIN_FILENO); + dup2(console, STDOUT_FILENO); + dup2(console, STDERR_FILENO); + + close(console); + + while (true) + { + pid_t pid = fork(); + + if (pid == 0) + { + execl("/bin/sh", "sh", nullptr); + perror("exec"); + _exit(127); + } + + if (pid > 0) + { + waitpid(pid, nullptr, 0); + } + } +} diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..e69de29