0xKiire Systems Programming Blog

website·Indexed 32 days ago

https://0xkiire.com

A technical resource focused on low-level programming, systems design, and performance optimization. The site features comprehensive guides on graphics programming with SDL2 and Vulkan, Linux kernel interfaces like io_uring and futexes, memory management, build systems, and architectural deep dives into building web frameworks, text editors, and Git from scratch.

Tokens
290K
Snippets
950
Records
1.2K
Agent score
55%

What's inside 0xKiire

  1. Overview of the cg GUI library architecture

    The cg library is a production-quality, retained-mode GUI toolkit written in C with SDL2 as its sole dependency. Unlike immediate mode (IMGUI) where the UI is re-specified every frame, cg uses a retained-mode widget tree. This allows layout to be computed only when the tree changes, simplifies animations via property interpolation, and enables persistent widget state (e.g., focus, hover, scroll position).

    The architecture consists of four primary layers:

    1. Application Code: Manages widgets, callbacks, and properties.
    2. Core Library (cg): Handles the widget tree, box-model layout engine (inspired by CSS flexbox), event system (bubbling/capturing), theme system, and tweening animation engine.
    3. Rendering Abstraction (cg_draw.c): Provides primitives for rectangles, rounded rectangles, borders, text, images, and clipping.
    4. Backend: SDL2 and SDL_ttf for low-level rendering and font management.
  2. Overview of the GUI Event System

    The event system is responsible for routing SDL2 input events to the appropriate widgets. It is built on three core mechanisms:

    1. Hit testing: Determining which widget is currently under the user's cursor.
    2. Event bubbling: Propagating events from the leaf widget (the most specific target) up to the root widget.
    3. Capture: Allowing a specific widget to capture all mouse events, which is essential for implementing operations like drag-and-drop.
  3. Overview of Zig for WebAssembly development

    Zig is suitable for WebAssembly (WASM) because it has no garbage collector, no hidden allocator, and no required runtime. Using the wasm32-freestanding target in Zig 0.16.0 produces minimal modules containing only the code written by the developer. Unlike other languages, Zig does not provide automatic marshalling (like wasm-bindgen); developers must manually handle the movement of strings, arrays, and structs across the ABI boundary using linear memory.
  4. Overview of Zypher Web Framework

    Zypher is an open-source web framework written in the Zig programming language. It is designed for maximum performance and minimum overhead.
    # View Zypher on GitHub
    git clone https://github.com/zypher-org/zypher
  5. Introduction to Build Systems

    A build system automates the transformation of source code into executable programs. It is essential for managing projects that grow across multiple files, languages, platforms, and dependencies. Key benefits include incremental builds (rebuilding only changed files), dependency management, cross-platform support, reproducible builds, parallel compilation, and automated testing/packaging.
  6. Overview of zypher development approaches

    zypher provides two distinct ways to build web applications:

    1. The Package Approach (Manual Wiring): zypher is added as a Zig dependency in build.zig.zon. The developer manually configures build.zig and writes all source files. This offers maximum control over the project structure and dependencies.
    2. The CLI Approach: Uses a standalone zypher binary to scaffold projects (zypher new), manage migrations, create superusers, and run the development server. This approach automates repetitive setup tasks.

    Note on CLI Approach: Currently, zypher new generates a project that expects the zypher source tree to be located two directories above the project root (via a zypher-root build option), as it is not yet published to a package registry.

  7. List available zypher scaffold templates

    Use zypher templates to see available project structures. Embedded templates include single-file (prototypes), mvc (Model-View-Controller), mvp (Model-View-Presenter), and clean-arch (Clean Architecture), with corresponding -api versions for JSON-only REST APIs.
    # List embedded templates
    zypher templates
    
    # List templates in a custom directory
    zypher templates --template-dir ./my-templates
  8. Implement an npm postinstall script for Zig binaries

    Use a postinstall script (install.js) to detect the current platform and architecture, locate the corresponding platform-specific package, and copy the Zig binary into the root package's bin folder with executable permissions.
    const { execSync } = require("child_process");
    const path = require("path");
    const fs = require("fs");
    
    const PLATFORMS = {
      "linux-x64":    "my-tool-linux-x64",
      "linux-arm64":  "my-tool-linux-arm64",
      "darwin-x64":   "my-tool-darwin-x64",
      "darwin-arm64": "my-tool-darwin-arm64",
      "win32-x64":    "my-tool-win32-x64",
      "win32-arm64":  "my-tool-win32-arm64",
    };
    
    const key = `${process.platform}-${process.arch}`;
    const pkgName = PLATFORMS[key];
    
    if (!pkgName) {
      console.error(`my-tool: unsupported platform ${key}`);
      process.exit(1);
    }
    
    let pkgDir;
    try {
      pkgDir = path.dirname(require.resolve(`${pkgName}/package.json`));
    } catch {
      console.error(`my-tool: could not find platform package ${pkgName}.`);
      process.exit(1);
    }
    
    const ext = process.platform === "win32" ? ".exe" : "";
    const src = path.join(pkgDir, `my-tool${ext}`);
    const binDir = path.join(__dirname, "bin");
    const dest = path.join(binDir, `my-tool${ext}`);
    
    fs.mkdirSync(binDir, { recursive: true });
    fs.copyFileSync(src, dest);
    fs.chmodSync(dest, 0o755);
  9. Understand the CPU cache hierarchy and memory movement

    Modern CPUs use a multi-tiered cache hierarchy to bridge the speed gap between the processor and DRAM. A cache miss can cost tens to hundreds of cycles, making data layout critical for performance. Memory is moved in cache lines (typically 64 bytes); accessing a single byte triggers the CPU to fetch the entire line containing that byte.

    Hierarchy Levels:

    • L1: Smallest and fastest, dedicated per core.
    • L2: Larger and slightly slower, dedicated per core.
    • L3: Much larger, shared among all cores.
    • DRAM: Largest capacity but slowest access time.
  10. Understand frame buffers and double buffering

    A frame buffer is a region of memory containing pixel data for a single complete frame. To prevent screen flickering, double buffering is used: a 'Front buffer' is currently displayed to the user, while a 'Back buffer' is used for drawing the next frame. Once the frame is complete, the buffers are swapped.
  11. Inspect inode numbers and link counts in C

    Use lstat to retrieve metadata about a file or symlink. Using lstat instead of stat ensures you get information about the symlink itself rather than the target it points to. The struct stat contains st_ino (inode number), st_nlink (hard link count), and st_mode (file type).
    #include <errno.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    int main(int argc, char **argv) {
        if (argc != 2) {
            fprintf(stderr, "usage: %s <path>\n", argv[0]);
            return 2;
        }
    
        struct stat st;
        if (lstat(argv[1], &st) != 0) {
            fprintf(stderr, "lstat: %s\n", strerror(errno));
            return 1;
        }
    
        printf("inode: %lu\n", (unsigned long)st.st_ino);
        printf("links: %lu\n", (unsigned long)st.st_nlink);
        printf("size:  %lu\n", (unsigned long)st.st_size);
    
        if (S_ISLNK(st.st_mode)) {
            printf("type: symlink\n");
        } else if (S_ISDIR(st.st_mode)) {
            printf("type: directory\n");
        } else if (S_ISREG(st.st_mode)) {
            printf("type: regular\n");
        } else {
            printf("type: other\n");
        }
    
        return 0;
    }